Git Product home page Git Product logo

sam0x17 / mongo_orm Goto Github PK

View Code? Open in Web Editor NEW
32.0 6.0 6.0 206 KB

Mongo ORM: A simple ORM for using MongoDB with the crystal programming language, designed for use with Amber. Based loosely on Granite ORM. Supports Rails-esque models, associations and embedded documents.

License: MIT License

Crystal 99.11% Shell 0.89%
crystal-language orm mongo database-access amber-framework crystal-shard mongodb shards

mongo_orm's Introduction

Mongo ORM

This shard provides a basic ORM for using MongoDB wth the Crystal programming language. Mongo ORM is based on Granite ORM, and provides basic querying, associations, and model lifecycle capabilities. Mongo ORM is intended to be used with the Amber Framework, but can be used with vanilla crystal or any web framework.

Suggestions, feature requests, bug fixes, and pull requests are always welcome.

Installation

First you will need to install MongoDB (unless you are running a remote server), as well as the dependencies for Mongo.cr. On Arch Linux and Ubuntu, this can be done using your package manager as shown below. For other linux distrubutions, you may be able to use the script shown below.

Arch Linux:

Simply run:

$ sudo pacman -Syu libbson mongodb
$ sudo systemctl start mongodb

Ubuntu

Simply run:

sudo apt update
sudo apt install libmongoc-dev libmongoc-1.0-0 libmongoclient-dev

Other Linux:

Simply run ./install_linux_deps, the contents of which are shown below:

# install_linux_deps.sh
#!/bin/bash
mkdir -p lib || exit 1
cd lib || exit 1
wget https://github.com/mongodb/mongo-c-driver/releases/download/1.1.0/mongo-c-driver-1.1.0.tar.gz || exit 1
tar -zxvf mongo-c-driver-1.1.0.tar.gz && cd mongo-c-driver-1.1.0/ || exit 1
./configure --prefix=/usr --libdir=/usr/lib || exit 1
make -j4 || exit 1
sudo make install -j4 || exit 1

MacOS:

You can just run ./install_macos_deps, the contents of which are shown below:

#!/bin/bash
curl -LO https://github.com/mongodb/mongo-c-driver/releases/download/1.9.4/mongo-c-driver-1.9.4.tar.gz || exit 1
tar xzf mongo-c-driver-1.9.4.tar.gz || exit 1
cd mongo-c-driver-1.9.4 || exit 1
./configure || exit 1
make || exit 1
sudo make install || exit 1

Next, add the following to the shard.yml file in your project and run shards install:

# shard.yml
dependencies:
  mongo_orm:
    github: sam0x17/mongo_orm

Establishing MongoDB Connection

By default (with zero configuration), Mongo ORM will attempt to connect to a database running at localhost:27017 which is the default MongoDB port, with the database name monogo_orm_db.

Using Environment Variables

If the environment variable DATABASE_URL is present, Mongo ORM will connect using this variable instead. You can also specify the database name using the DATABASE_NAME environment variable. For example:

$ DATABASE_URL=mongodb://localhost:11771;DATABASE_NAME=my_db crystal app.cr

Using a YAML Configuration File

If the DATABASE_URL environment variable is not present, Mongo ORM will look for the file config/database.yml within your project directory. If the file exists, Mongo ORM will expect the following format (specify the keys database_url and database_name):

# config/database.yml
database_url: mongodb://localhost:11771
database_name: my_db

Mongo ORM Reference

Static Fields

MongoDB is different from conventional relational database systems mainly because there is no set-in-stone schema, but instead a wilderness of BSON-based "documents" that may or may not roughly follow the same schema. Declaring static fields works much the same as it does in Granite ORM:

require "mongo_orm"

class User < Mongo::ORM::Document
  field name : String
  field age : Int32
  field deleted_at : Time
  field turned_on : Bool
  timestamps
end

This will declare a model called User with a string field called name, a 32-bit integer field called age, a Time field called deleted_at, a boolean field called turned_on, and the standard created_at and updated_at fields you will recognize from Rails that are created because we specified timestamps.

Note: all Time fields are presently locked into UTC because of some conversion bugs that arise when changing time zones and converting between BSON and crystal models.

To instantiate a User and save it to the database, you can do:

user = User.new
user.name = "Sam"
user.age = 248
user.turned_on = true
user.save!
puts user.inspect # print the created user
puts "id: #{user._id}" # print the ID of the created user

Note that the ID field is named _id, as in standard MongoDB.

You can also use the more compact create notation:

user = User.create name: "Sam", age: 248, turned_on: true

Model Associations

Currently, you can define has_many associations directly on a model, and they will behave roughly the same way they would in standard Rails. For example:

class Group < Mongo::ORM::Document
  field name : String
  has_many :users
end

This defines another model called Group. A group has a String field name, and has an ID-based collection of User documents called users which can be accessed via group.users where group is an instance of Group. To make a User a member of a Group, user.group_id can be set to the document ID of an already-created Group. Note that when you specify that model A has_many model B, the b.a_id field is also automatically created.

Embedded Documents

In addition to conventional table-style models/documents, Mongo ORM supports the ability to embed documents or collections of documents within documents, as per the BSON standard. This is sometimes a more convenient or more efficient alternative to spreading data out across multiple document collections (tables) and fully leverages the document-based nature of MongoDB. Note that you can also nest embedded documents. See the example below:

class Topic < Mongo::ORM::Document
  embeds top_comment : Comment # e.g. topic.top_comment.body
end

class Tag < Mongo::ORM::EmbeddedDocument
  field topic : String
end

class Comment < Mongo::ORM::EmbeddedDocument
  field body : String
  embeds_many :tags # e.g. comment.tags[0]
end

Extended Fields

Mongo ORM also allows you to make use of document fields that are not specified explicitly in the model schema. In fact, it is possible to use Mongo ORM without specifying any model schema at all, however we have provided both options, as schemas provide sane defaults, type checking, and consistency, whereas extended fields (our name for fields not specified in a model schema) make it easy to do dynamic things that would be difficult or impossible in traditional relational databases, and require zero configuration.

For example, suppose you have an Admin collection in your database, and that some (but not all) Admin documents have a field called alias:

admin = Admin.find(4)
puts admin.alias

If the document does indeed have a field named alias, then this will print its value. If such a field is not defined, then nil (nothing) will be printed. This will also work on nested documents, for example blog.header.tag where blog is a Blog document and header is a Header embedded document.

If you know for a fact that alias should be defined on this particular document, you can use the following syntax to be more explicit:

admin = Admin.find(4)
puts admin.alias!

The ! syntax will cause an error to be thrown (undefined method) in the event that the alias field is not defined.

mongo_orm's People

Contributors

alaaattya avatar mniak avatar sam0x17 avatar steffanperry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

mongo_orm's Issues

Not working with crystal 0.26.1 - JSON::Type

Error target TesteCrystal failed to compile:
Error in src/TesteCrystal.cr:1: while requiring "mongo_orm"

require "mongo_orm"
^

in lib/mongo_orm/src/mongo_orm.cr:2: while requiring "./mongo_orm/*"

require "./mongo_orm/*"
^

in lib/mongo_orm/src/mongo_orm/document.cr:2: while requiring "./fields"

require "./fields"
^

in lib/mongo_orm/src/mongo_orm/fields.cr:4: undefined constant JSON::Type

  alias Type = JSON::Type | DB::Any
               ^~~~~~~~~~

Can't import the library

while requiring "mongo-orm": can't find file'mongo-orm' is thrown.
Also tried importing just the "mongo" library, then: undefined constant Mongo::ORM::Document

How do you import this?

install_linux_deps issue on antergos/arch linux

...
src/mongoc/mongoc-rand.c: In function ‘_mongoc_pseudo_rand_bytes’:
src/mongoc/mongoc-rand.c:33:5: warning: ‘RAND_pseudo_bytes’ is deprecated [-Wdeprecated-declarations]
     return RAND_pseudo_bytes(buf, num);
     ^~~~~~
In file included from /usr/include/openssl/e_os2.h:13,
                 from /usr/include/openssl/ossl_typ.h:19,
                 from /usr/include/openssl/rand.h:14,
                 from src/mongoc/mongoc-rand.c:26:
/usr/include/openssl/rand.h:47:1: note: declared here
 DEPRECATEDIN_1_1_0(int RAND_pseudo_bytes(unsigned char *buf, int num))
 ^~~~~~~~~~~~~~~~~~
  CC       src/mongoc/libmongoc_priv_la-mongoc-sasl.lo
  CC       src/mongoc/libmongoc_1_0_la-mongoc-array.lo
src/mongoc/mongoc-stream-tls.c:100:1: error: variable ‘gMongocStreamTlsRawMethods’ has initializer but incomplete type
 static BIO_METHOD gMongocStreamTlsRawMethods = {
 ^~~~~~
src/mongoc/mongoc-stream-tls.c:101:4: warning: excess elements in struct initializer
    BIO_TYPE_FILTER,
    ^~~~~~~~~~~~~~~
src/mongoc/mongoc-stream-tls.c:101:4: note: (near initialization for ‘gMongocStreamTlsRawMethods’)
src/mongoc/mongoc-stream-tls.c:102:4: warning: excess elements in struct initializer
    "mongoc-stream-tls-glue",
    ^~~~~~~~~~~~~~~~~~~~~~~~
src/mongoc/mongoc-stream-tls.c:102:4: note: (near initialization for ‘gMongocStreamTlsRawMethods’)
src/mongoc/mongoc-stream-tls.c:103:4: warning: excess elements in struct initializer
    _mongoc_stream_tls_bio_write,
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/mongoc/mongoc-stream-tls.c:103:4: note: (near initialization for ‘gMongocStreamTlsRawMethods’)
src/mongoc/mongoc-stream-tls.c:104:4: warning: excess elements in struct initializer
    _mongoc_stream_tls_bio_read,
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/mongoc/mongoc-stream-tls.c:104:4: note: (near initialization for ‘gMongocStreamTlsRawMethods’)
src/mongoc/mongoc-stream-tls.c:105:4: warning: excess elements in struct initializer
    _mongoc_stream_tls_bio_puts,
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/mongoc/mongoc-stream-tls.c:105:4: note: (near initialization for ‘gMongocStreamTlsRawMethods’)
src/mongoc/mongoc-stream-tls.c:106:4: warning: excess elements in struct initializer
    _mongoc_stream_tls_bio_gets,
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/mongoc/mongoc-stream-tls.c:106:4: note: (near initialization for ‘gMongocStreamTlsRawMethods’)
src/mongoc/mongoc-stream-tls.c:107:4: warning: excess elements in struct initializer
    _mongoc_stream_tls_bio_ctrl,
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/mongoc/mongoc-stream-tls.c:107:4: note: (near initialization for ‘gMongocStreamTlsRawMethods’)
src/mongoc/mongoc-stream-tls.c:108:4: warning: excess elements in struct initializer
    _mongoc_stream_tls_bio_create,
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/mongoc/mongoc-stream-tls.c:108:4: note: (near initialization for ‘gMongocStreamTlsRawMethods’)
src/mongoc/mongoc-stream-tls.c:109:4: warning: excess elements in struct initializer
    _mongoc_stream_tls_bio_destroy
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/mongoc/mongoc-stream-tls.c:109:4: note: (near initialization for ‘gMongocStreamTlsRawMethods’)
src/mongoc/mongoc-stream-tls.c: In function ‘_mongoc_stream_tls_bio_create’:
src/mongoc/mongoc-stream-tls.c:134:5: error: dereferencing pointer to incomplete type ‘BIO’ {aka ‘struct bio_st’}
    b->init = 1;
     ^~
src/mongoc/mongoc-stream-tls.c: At top level:
src/mongoc/mongoc-stream-tls.c:100:19: error: storage size of ‘gMongocStreamTlsRawMethods’ isn’t known
 static BIO_METHOD gMongocStreamTlsRawMethods = {
                   ^~~~~~~~~~~~~~~~~~~~~~~~~~
make[1]: *** [Makefile:2828: src/mongoc/libmongoc_priv_la-mongoc-stream-tls.lo] Error 1
make[1]: *** Waiting for unfinished jobs....
src/mongoc/mongoc-ssl.c: In function ‘_mongoc_ssl_check_cert’:
src/mongoc/mongoc-ssl.c:253:16: warning: ‘ASN1_STRING_data’ is deprecated [-Wdeprecated-declarations]
                check = (char *)ASN1_STRING_data (name->d.ia5);
                ^~~~~
In file included from /usr/include/openssl/bn.h:31,
                 from /usr/include/openssl/asn1.h:24,
                 from /usr/include/openssl/objects.h:916,
                 from /usr/include/openssl/evp.h:27,
                 from /usr/include/openssl/x509.h:23,
                 from /usr/include/openssl/ssl.h:50,
                 from src/mongoc/mongoc-ssl.c:24:
/usr/include/openssl/asn1.h:553:1: note: declared here
 DEPRECATEDIN_1_1_0(unsigned char *ASN1_STRING_data(ASN1_STRING *x))
 ^~~~~~~~~~~~~~~~~~
At top level:
src/mongoc/mongoc-ssl.c:515:1: warning: ‘_mongoc_ssl_thread_locking_callback’ defined but not used [-Wunused-function]
 _mongoc_ssl_thread_locking_callback (int         mode,
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/mongoc/mongoc-ssl.c:504:1: warning: ‘_mongoc_ssl_thread_id_callback’ defined but not used [-Wunused-function]
 _mongoc_ssl_thread_id_callback (void)
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make[1]: Leaving directory '/home/sam/Desktop/workspace/crystal-mongo-orm/lib/mongo-c-driver-1.1.0'
make: *** [Makefile:3727: all-recursive] Error 1

Not able to install mongo_orm

Failed git branch --list --column=never --contains 86c9e530c0ac980ed7b15e653746bc5b6f2527fc (no such commit 86c9e530c0ac980ed7b15e653746bc5b6f2527fc). Maybe a commit, branch or file doesn't exist?

Time.now undefined method

Hello

I found a bug when to create document, it seem problem on timestamp that use function Time.now which deprecated in crystal 0.33.

https://crystal-lang.org/api/0.33.0/Time.html

the message

Which expanded to:

 > 10 | if _id
 > 11 |   __run_before_update
 > 12 |   @updated_at = Time.now.to_utc
                             ^--
Error: undefined method 'now' for Time.class

Did you mean 'new'?

Can't convert to JSON

After calling #to_json on a query result, i get an error:

no overload matches 'BSON::ObjectId#to_json' with type JSON::Builder

Am I doing something wrong or is this functionality not supported?

Disclaimer: I'm new to Crystal and Amber.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.