Another ORM for Node, supporting sqlite and postgres
The API design is largely borrowed from Django's ORM; while not 100% similar the general theme should be familiar to anyone who has worked with Django before.
The three major types of objects are
namespaces (otherwise known as
Namespaces may contain one or more model definitions; these model definitions may refer to models from other namespaces.
Namespaces are (currently) responsible for creation of database tables for their constituent models. The schema and metadata
of a model may only be set within a namespace.
Let's take a look at what the average
models.js file might look like:
var models = require'sqliteorm'models;exportsns =modelsnamespace'blog'var Post = nscreate'Post';Postschema// field definitions need not be explictly called,// uncalled fields will be instantiated with the default options.'title':modelsCharField'slug':modelsCharFieldregex:/^[\w\d\-_]*$/g unique:true'pub_date':modelsDateField return ;'description':modelsTextField;Postmeta'order_by':'-pub_date';// models returned by `ns.create` are class constructor functions, just like in vanilla JS.// all instances of that model will have anything you throw onto their `prototype` available to them.return '<Post: '+thistitle+'>';;var Section = nscreate'Section';Sectionschema'post':modelsForeignKeyPost'header':modelsCharFieldnullable:true default:null'subhead':modelsCharFieldnullable:true default:null'content':modelsTextField'ordering':modelsPositiveIntegerField;Sectionmeta'order_by':'ordering''unique_together':'ordering' 'post';var Tag = nscreate'Tag';Tagschema'name':modelsCharFieldmax_length:100'posts':modelsManyToManyPost related_name:'tags';exportsPost = Post;exportsSection = Section;exportsTag = Tag;;
In this schema, a
Post has many
Tags may be associated with many
Posts. Note that models are just plain-old function constructors,
namespace callback is executed immediately --
exporting models from within the namespace is encouraged.
Outside of the namespace closure, the
meta methods will be unavailable and your models will be ready to use.
Building on the previous example, let's look at how we might query the above objects.
var models = require'./models'Post = modelsPostSection = modelsSectionTag = modelsTag;// Model classes are automatically assigned a `Manager` (available under 'Model._default_manager' as well as 'Model.objects') which is responsible for starting queries, like so:_// query all of the posts.var posts = Postobjectsall// queries emit either 'data' or 'error', and nothing else.// when 'data' is emitted, the query has completed.postson'data'postsforEachconsole.log'Got '+post;;;postson'error'// handle your error, sir.;// you may also call posts as if it was a function taking a callback:// no casting necessary.posts// do something with posts.;// you may filter on the fields available to 'post'.// multiple arguments in one filter call will be 'AND'd together.var other_posts = Postobjectsfiltertitle__contains:'something' slug:'something-else';// filters may be chained, and excluded.// chained filters will be 'AND'd together as well.// exclude will produce NOT(arg AND arg AND arg)other_postsfilterpub_date__lte:excludeslug__startswith:'butts';// you may use a filter to delete objects as well:other_postsdeleteother_posts// if there's no 'err', your filter has run successfully;// if you only need one specific row, use 'get':Postobjectsgettitle:'something'// if more than one 'Post' was returned, err will be an instance of Post.MultipleObjectsReturned.// if no 'Post's were returned, err will be an instance of Post.DoesNotExist,// otherwise post will be a single Post object.;// creation is pretty easy as well:var my_post = Postobjectscreate'title':'Introducing SQLiteORM''slug':'introducing-sqliteorm''pub_date':'description':'SQLiteORM';my_poston'data'// our post object exists!;// you may also use this format:var post ='title':'Introducing SQLiteORM''slug':'introducing-sqliteorm''pub_date':'description':'SQLiteORM';postsaveon'data'// my post!;// you may pass querysets to other querysets as arguments without waiting for them to return, as well:section = Sectionobjectscreate'content':'whoa''ordering':0'post':Postobjectscreate'title':'Introducing SQLiteORM''slug':'introducing-sqliteorm''pub_date':'description':'SQLiteORM';// errors from inner queries such as the above will be bubbled up through the 'section' queryset.// you may query across related tables, as well:sectionobjectsfilterpost__title__contains:'hats';// or in reverse (the default reverse relation name is the name of the model with the foreign key, lowercased, plus '_set'):Postobjectsfiltersection_set__content:'whoa';// the above statement about being able to pass querysets applies to filtering, as wellSectionobjectsfilterpost:Postobjectsgetpk:3Sectionobjectsfilterpost__in:Postobjectsfiltertitle__contains:'something'// related filtered works with M2M relations:Tagobjectsfilterpost__title:'Yeah!'// note that we configured the related name for Tags in the models above.Postobjectsfiltertags__name__contains:'bowser'// filters may be limited and ordered:// "give me three posts, ordered by title ASC, id DESC"Postobjectsfilterpk:3order_by'title' '-id'limit3// "give me 20 posts starting at 10."Postobjectsfilterpk:3limit10 20;
Filters execute as soon as the current stack is exhausted.