diff --git a/lib/poutine/collection.coffee b/lib/poutine/collection.coffee index 3a8b181..bcfc4f0 100644 --- a/lib/poutine/collection.coffee +++ b/lib/poutine/collection.coffee @@ -203,19 +203,22 @@ class Collection # posts = connect().find("posts") # posts.insert title: "New and exciting", (error, post)-> # console.log "Inserted #{post._id}" - insert: (document, options, callback)-> + insert: (objects, options, callback)-> if !callback && typeof options == "function" [options, callback] = [null, options] + multi = Array.isArray(objects) + objects = [objects] unless multi + documents = ((if Model.isModel(object) then object._ else object) for object in objects) @_connect (error, collection, database)=> return callback error if error if callback - collection.insert document, options, (error, results)-> - if Array.isArray(document) - callback error, results + collection.insert documents, options, (error, results)-> + if multi + callback error, objects else - callback error, results[0] + callback error, objects[0] else - collection.insert document, options + collection.insert documents, options # -- Implementation details -- diff --git a/lib/poutine/model.coffee b/lib/poutine/model.coffee index 85dd0b4..a995066 100644 --- a/lib/poutine/model.coffee +++ b/lib/poutine/model.coffee @@ -21,6 +21,12 @@ connect = require("./connect").connect # User.where(name: "Assaf").one (error, user)-> # console.log "Loaded #{user.name}" class Model + # Default constructor assigns defined fields from any object you pass, e.g. + # new User(name: "Assaf") + constructor: (document)-> + if document + for name of @constructor.fields + @[name] = document[name] # -- Schema -- @@ -96,6 +102,11 @@ class Model assert setter, "Missing setter function" @prototype.__defineSetter__ name, setter + # Returns true if we think the object is an instance of a model + @isModel: (instance)-> + model = instance.constructor + return model.collection_name && model.fields + # -- Finders -- @@ -148,6 +159,12 @@ class Model @lifecycle.addHook this, "afterLoad", hook + # -- Insert/update/remove -- + + @insert: (document, callback)-> + connect().collection(this).insert document, callback + + # Poutine uses these lifecycle methods to perform operations on models, but keeps them separate so we don't pollute the # Model prototype with methods that are never used directly by actual model classes. Inheriting from a class that has # hundreds of implementation methods is an anti-pattern we dislike. diff --git a/spec/model/insert_spec.coffee b/spec/model/insert_spec.coffee new file mode 100644 index 0000000..c3b1900 --- /dev/null +++ b/spec/model/insert_spec.coffee @@ -0,0 +1,156 @@ +{ assert, vows, connect, setup, Model } = require("../helpers") + + +class Post extends Model + @collection "posts" + + @field "title", String + @field "author_id" + @field "category", String + @field "created_at", Date + + +vows.describe("Model insert").addBatch + + # -- Model.insert -- + + "Model.insert": + topic: -> + setup @callback + + "POJO": + "single": + "no callback": + topic: -> + result = Post.insert(title: "Insert 3.1") + return result || "nothing" + "should return nothing": (result)-> + assert.equal result, "nothing" + "new document": + topic: -> + Post.find title: "Insert 3.1", @callback + "should exist in database": (posts)-> + assert.equal posts[0].title, "Insert 3.1" + + "with callback": + topic: -> + Post.insert title: "Insert 3.2", @callback + "should pass document to callback": (post)-> + assert.equal post.title, "Insert 3.2" + "should pass a POJO to callback": (post)-> + assert !(post instanceof Post) + "should set document ID": (post)-> + assert post._id + "new document": + topic: (post)-> + Post.find post._id, @callback + "should exist in database": (post)-> + assert.equal post.title, "Insert 3.2" + + "multiple": + "no callback": + topic: -> + result = Post.insert([{ title: "Insert 3.3", category: "foo" }, { title: "Insert 3.3", category: "bar" }]) + return result || "nothing" + "should return nothing": (result)-> + assert.equal result, "nothing" + "new documents": + topic: -> + Post.find title: "Insert 3.3", @callback + "should exist in database": (posts)-> + assert.lengthOf posts, 2 + categories = (post.category for post in posts).join(" ") + assert.equal categories, "foo bar" + + "with callback": + topic: -> + Post.insert [{ title: "Insert 3.4", category: "foo" }, { title: "Insert 3.4", category: "bar" }], @callback + "should pass documents to callback": (posts)-> + for post in posts + assert.equal post.title, "Insert 3.4" + "should pass POJOs to callback": (posts)-> + for post in posts + assert !(post instanceof Post) + "should set document ID": (posts)-> + for post in posts + assert post._id + "new documents": + topic: (posts)-> + ids = (post._id for post in posts) + Post.find ids, @callback + "should exist in database": (posts)-> + assert.lengthOf posts, 2 + categories = (post.category for post in posts).join(" ") + assert.equal categories, "foo bar" + + + "Model": + "no callback": + topic: -> + post = new Post(title: "Insert 3.5") + result = Post.insert(post) + return result || "nothing" + "should return nothing": (result)-> + assert.equal result, "nothing" + "new document": + topic: -> + Post.find title: "Insert 3.5", @callback + "should exist in database": (posts)-> + assert.equal posts[0].title, "Insert 3.5" + + "with callback": + topic: (post)-> + post = new Post(title: "Insert 3.6") + Post.insert post, @callback + "should pass document to callback": (post)-> + assert.equal post.title, "Insert 3.6" + "should pass a model to callback": (post)-> + assert.instanceOf post, Post + "should set document ID": (post)-> + assert post._id + "new document": + topic: (post)-> + Post.find post._id, @callback + "should exist in database": (post)-> + assert.equal post.title, "Insert 3.6" + + "multiple": + "no callback": + topic: -> + posts = [new Post( title: "Insert 3.7", category: "foo" ), new Post( title: "Insert 3.7", category: "bar" )] + result = Post.insert(posts) + return result || "nothing" + "should return nothing": (result)-> + assert.equal result, "nothing" + "new documents": + topic: -> + Post.find title: "Insert 3.7", @callback + "should exist in database": (posts)-> + assert.lengthOf posts, 2 + categories = (post.category for post in posts).join(" ") + assert.equal categories, "foo bar" + + "with callback": + topic: -> + posts = [new Post( title: "Insert 3.8", category: "foo" ), new Post( title: "Insert 3.8", category: "bar" )] + Post.insert posts, @callback + "should pass documents to callback": (posts)-> + for post in posts + assert.equal post.title, "Insert 3.8" + "should pass models to callback": (posts)-> + for post in posts + assert.instanceOf post, Post + "should set document ID": (posts)-> + for post in posts + assert post._id + "new documents": + topic: (posts)-> + ids = (post._id for post in posts) + Post.find ids, @callback + "should exist in database": (posts)-> + assert.lengthOf posts, 2 + categories = (post.category for post in posts).join(" ") + assert.equal categories, "foo bar" + + +.export(module)