Skip to content
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# IntelliJ project files
.idea
34 changes: 34 additions & 0 deletions BaseSchemaRules.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
log = new ObjectLogger("practical.BaseSchema", "debug")


@practical.BaseSchemaRules = ->
return {
# https://github.com/aldeed/meteor-collection2#autovalue
# Force value to be current date (on server) upon insert
# and prevent updates thereafter.
createdAt:
type: Date
index: 1
autoValue: ->
if @isInsert
return lv.util.getCurrentDate()
else if @isUpsert
return {$setOnInsert: lv.util.getCurrentDate()}
else
this.unset()
denyUpdate: true

# https://github.com/aldeed/smeteor-collection2#autovalue
# Force value to be current date (on server) upon update.
# On insert, it will always be set to the insert date.
modifiedAt:
type: Date
index: 1
autoValue: ->
if @isUpdate
return lv.util.getCurrentDate()
else if @isUpsert
return {$set: lv.util.getCurrentDate()}
denyInsert: true
optional: true
}
106 changes: 106 additions & 0 deletions CollectionInit.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
log = new ObjectLogger("practical.CollectionInit", "debug")
practical = @practical

class @CollectionInit


@init: (collection, opts = {})=>
try
log.enter("init", opts)
expect(collection, "collection is not a Mongo Collection").to.be.instanceOf(Mongo.Collection)
expect(opts, "opts").to.be.an("object")

collection.practical = {}

@_createSchema(collection, opts)

if opts.autopublish
@_autoPublishCollection(collection)

# Custom publish and subscription handlers
if opts.sub and opts.pub and not opts.autopublish
@_customSubAndPub(collection, opts)

if opts.populate? and Meteor.isServer
expect(opts.populate, "populate").to.be.a("function")
opts.populate()

if opts.indexes? and Meteor.isServer
@_ensureIndexes(collection, opts)



finally
log.return()


@_createSchema: (collection, opts)=>
try
log.enter("_createSchema", opts)
expect(collection).to.be.instanceOf(Mongo.Collection)
expect(collection.practical).to.be.an("object")

schemaRules = practical.BaseSchemaRules()

if opts.schemaRules?
expect(opts.schemaRules).to.be.an("object")
schemaRules = _.extend(schemaRules, opts.schemaRules)

collection.practical.schemaRules = schemaRules
collection.practical.schema = new SimpleSchema(schemaRules)
collection.attachSchema(collection.practical.schema)


finally
log.return()


@_autoPublishCollection: (collection)->
try
log.enter("_autoPublishCollection")
expect(collection).to.be.instanceOf(Mongo.Collection)
expect(collection.practical).to.be.an("object")

if Meteor.isServer
Meteor.publish collection._name, ->
return collection.find({})

if Meteor.isClient
collection.practical.subHandle = Meteor.subscribe collection._name,{
onReady: ->
onError: (error)->
log.error("Error with subscription [#{collection._name}]", error) if error
}

finally
log.return()


@_customSubAndPub: (collection, opts)=>
try
log.enter("_customSubAndPub", opts)

if Meteor.isServer
expect(opts.pub, "custom publication").to.be.a("function")
opts.pub()

if Meteor.isClient
expect(opts.sub, "custom subscription").to.be.a("function")
opts.sub()

finally
log.return()


@_ensureIndexes: (collection, opts)=>
try
log.enter("_ensureIndexes", opts)
expect(Meteor.isServer).to.be.true
expect(opts.indexes).to.be.an("array")

for index in opts.indexes
expect(index.keys).to.be.an("object")
expect(index.options).to.be.an("object")
collection._ensureIndex(index.keys, index.options)
finally
log.return()
2 changes: 2 additions & 0 deletions bin/ci-test
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
spacejam test-packages --driver-package practicalmeteor:mocha-console-runner ./
3 changes: 3 additions & 0 deletions bin/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash
unset MONGO_URL
meteor test-packages --driver-package practicalmeteor:mocha ./ --port 3100
12 changes: 12 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
machine:
node:
version: 0.10.40

dependencies:
pre:
- curl https://install.meteor.com/ | sh
- npm install -g spacejam

test:
override:
- ./bin/ci-test
43 changes: 43 additions & 0 deletions package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
Package.describe({
name: "practicalmeteor:collection-init",
summary: "write package tests with mocha and run them in the browser or from the command line with spacejam.",
git: "https://github.com/practicalmeteor/meteor-mocha.git",
version: '0.1.0'
});


Package.onUse(function(api){

// TODO add specific packages versions
// Meteor packages
api.use("coffeescript");
api.use("mongo");
api.use("underscore");

// Practical Meteor packages
api.use("practicalmeteor:core");

// Vendor packages
api.use("aldeed:simple-schema");
api.use("aldeed:collection2@2.5.0");

api.imply("aldeed:simple-schema@1.3.3");
api.imply("aldeed:collection2@2.5.0");

// Files
api.addFiles("CollectionInit.coffee")
api.addFiles("BaseSchemaRules.coffee")

});

Package.onTest(function (api) {

api.use("coffeescript");
api.use("mongo");
api.use("underscore");

api.use("practicalmeteor:collection-init");
api.use("practicalmeteor:loglevel");

api.addFiles("tests/CollectionInitTests.coffee");
});
148 changes: 148 additions & 0 deletions tests/CollectionInitTests.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
log = new ObjectLogger("practical.CollectionInitTests")

describe "CollectionInit", ->

collectionName = "collection"
collection = new Mongo.Collection(collectionName)

beforeEach ->

delete collection.practical

spies.create("Meteor.subscribe", Meteor, "subscribe") if Meteor.isClient

if Meteor.isServer
spies.create("Meteor.publish", Meteor, "publish")

stubs.create("collection.ensureIndex", collection, "_ensureIndex")


it "Add 'practical' property to the collection", ->

CollectionInit.init(collection)
expect(collection.practical).to.be.an("object")


it "Create publication and subscription for collection is autopublish is true ", ->

opts = {
autopublish: true
}

CollectionInit.init(collection, opts)

if Meteor.isClient
# Save subscription handle into practical
expect(collection.practical.subHandle).to.be.an("object")
expect(spies["Meteor.subscribe"]).to.have.been.called
expect(spies["Meteor.subscribe"].args[0][0]).to.equals(collectionName)

if Meteor.isServer
expect(spies["Meteor.publish"]).to.have.been.called
expect(spies["Meteor.publish"].args[0][0]).to.equals(collectionName)


it "Calls custom sub and pub if not autopublish", ->

opts = {
sub: stubs.create("sub")
pub: stubs.create("pub")
}

CollectionInit.init(collection, opts)
if Meteor.isClient
expect(stubs.sub).to.have.been.called

if Meteor.isServer
expect(stubs.pub).to.have.been.called

it "Don't calls custom sub and pub if not autopublish", ->

opts = {
autopublish: true
sub: stubs.create("sub")
pub: stubs.create("pub")
}

CollectionInit.init(collection, opts)

if Meteor.isClient
expect(stubs.sub).not.to.have.been.called

if Meteor.isServer
expect(stubs.pub).not.to.have.been.called

it "Calls populate function", ->

opts = {
populate: stubs.create("populate")
}
CollectionInit.init(collection, opts)

if Meteor.isServer
expect(stubs.populate).to.have.been.called
if Meteor.isClient
expect(stubs.populate).not.to.have.been.called

it "create indexes for the collection", ->

opts = {
indexes:[
{
keys: {name: 1}
options: {unique: true}
},
{
keys: {title: 1}
options: {}
}
]
}

CollectionInit.init(collection, opts)

if Meteor.isServer
expect(stubs["collection.ensureIndex"]).to.have.been.callCount(opts.indexes.length)
for index in opts.indexes
expect(stubs["collection.ensureIndex"]).to.have.been.calledWith(index.keys, index.options)

if Meteor.isClient
expect(stubs["collection.ensureIndex"]).not.to.have.been.called


it "Attach base schema to collection", ->

opts = {
}

CollectionInit.init(collection, opts)

expect(collection.practical.schema).to.be.instanceOf(SimpleSchema)
expect(_.keys(collection.practical.schemaRules)).to.eql(_.keys(practical.BaseSchemaRules()))

# I'm using a private property to determinate the keys of the schema of the collection,
# this can change and made the tests to fail in next releases of the package
expect(_.keys(collection.practical.schemaRules)).to.eql(collection.practical.schema._schemaKeys)


it "Attach base schema and other schema to the collection", ->

opts = {
schemaRules: {
name:
type: String
}
}
expectKeys = _.keys(practical.BaseSchemaRules()).concat(_.keys(opts.schemaRules))


CollectionInit.init(collection, opts)


expect(collection.practical.schema).to.be.instanceOf(SimpleSchema)
expect(_.keys(collection.practical.schemaRules)).to.eql(expectKeys)

# I'm using a private property to determinate the keys of the schema of the collection,
# this can change and made the tests to fail in next releases of the package
expect(_.keys(collection.practical.schemaRules)).to.eql(collection.practical.schema._schemaKeys)