Meteor Publication Factory
Create validated Meteor publications. Lightweight. Simple.
With this package you can define factory functions to create a variety of Meteor publications. Decouples definition from instantiation (also for the schema) and allows different configurations for different types of publications.
Minified size < 2KB!
Why do I want this?
- Decouple definition from instantiation
- Validate publication arguments as with
mdg:validated-method
- Just pass in the schema as plain object, instead of manually instantiating
SimpleSchema
- Create mixins (similar to
mdg:validated-method
) on the abstract factory level, on the factory level, or both (see mixins section) - Fail silently in case of errors (uses the publication's
error
andready
), undefined cursors or unexpected returntypes
Installation
Simply add this package to your meteor packages
$ meteor add leaonline:publication-factory
Usage
Import the createPublicationFactory
publication and create the factory function from it:
1import { createPublicationFactory } from 'meteor/leaonline:publication-factory' 2import { MyCollection } from '/path/to/MyCollection' 3 4const createPublication = createPublicationFactory() // no params = use defaults 5const fancyPublication = createPublication({ name: 'fancy', validate: () => {}, run: () => MyCollection.find() }) // minimal required
Under the hood it all runs like a
With schema
We support various ways to validate an input schema. To decouple schema definition from instantiation, we introduced a shemaFactory
, which
is basically a function that creates your schema for this collection. This also ensures, that
publications don't share the same schema instances.
Using SimpleSchema
1import { createPublicationFactory } from 'meteor/leaonline:publication-factory' 2import { MyCollection } from '/path/to/MyCollection' 3import SimpleSchema from 'simpl-schema' 4 5const schemaFactory = definitions => new SimpleSchema(definitions) 6 7const createPublication = createPublicationFactory({ schemaFactory }) 8createPublication({ 9 name: 'fancy', 10 schema: { author: String }, 11 run: function({ author }) { 12 return MyCollection.find({ author }) 13 } 14})
and subcribe via
1Meteor.subscribe('fancy', { author: 'Mr.x' }) // leaving author will raise an error
As you can see, there is no need to pass a validate
function as it is internally built using the schemaFactory
and the given schema
.
Overriding validate
when using schema
You can also override the internal validate
when using schema
by passing a validate
function.
This, however, disables the schema validation and is then your responsibility:
1import { createPublicationFactory } from 'meteor/leaonline:publication-factory' 2import { MyCollection } from '/path/to/MyCollection' 3import SimpleSchema from 'simpl-schema' 4 5const schemaFactory = definitions => new SimpleSchema(definitions) 6 7const createPublication = createPublicationFactory({ schemaFactory }) 8createPublication({ 9 name: 'fancy', 10 schema: { author: String }, 11 validate: () => {}, 12 run: function({ author }) { 13 return MyCollection.find({ author }) 14 } 15})
and subcribe via
1Meteor.subscribe('fancy', {}) // leaving author will NOT raise an error
If none of these cover your use case, you can still use mixins.
Using check
You can also use Meteor's builtin check
and Match
for schema validation:
1import { check } from 'meteor/check' 2import { MyCollection } from '/path/to/MyCollection' 3import { createPublicationFactory } from 'meteor/leaonline:publication-factory' 4 5const schemaFactory = schema => ({ 6 validate (args) { 7 check(args, schema) 8 } 9}) 10 11const createPublication = createPublicationFactory({ schemaFactory }) 12createPublication({ 13 name: 'fancy', 14 schema: { author: String }, 15 run: function({ author }) { 16 return MyCollection.find({ author }) 17 } 18})
Note, that some definitions for SimpleSchema
and check
/Match
may differ.
With mixins
There are three ways to define mixins:
- on the abstract factory function level, all publications created by the factory will contain these mixins
- on the factory level, you basically pass mixins the a single publication
- on both levels, where mixins from the abstract factory function are executed first; no overrides
Abstract factory level mixins
If you want a certain mixin to be included for all publications created by the factory just pass them to the
createPublicationFactory
function:
1import { createPublicationFactory } from 'meteor/leaonline:publication-factory' 2import { ValidatedPublication } from 'meteor/mdg:validated-publication' 3import { myDefaultMixin } from '/path/to/myDefaultMixin' 4import { MyCollection } from '/path/to/MyCollection' 5 6const createPublication = createPublicationFactory({ mixins: [myDefaultMixin] }) 7createPublication({ 8 name: 'publicationWithMixin', 9 validate: () => {}, 10 run: () => MyCollection.find(), 11 foo: 'bar' // assuming your mixin requires foo 12})
Factory level mixins
You can also define mixins for each publication. This is the same as passing mixins to the ValidatedPublication
:
1import { createPublicationFactory } from 'meteor/leaonline:publication-factory' 2import { ValidatedPublication } from 'meteor/mdg:validated-publication' 3import { myDefaultMixin } from '/path/to/myDefaultMixin' 4import { MyCollection } from '/path/to/MyCollection' 5 6const createPublication = createPublicationFactory() // use defaults 7 8createPublication({ 9 name: 'publicationWithMixin', 10 mixins: [myDefaultMixin], 11 validate: () => {}, 12 run: () => MyCollection.find(), 13 foo: 'bar' // assuming your mixin requires foo 14}) 15 16const publicationWithoutMixin = createPublication({ 17 name: 'publicationWithoutMixin', 18 validate: () => {}, 19 run: () => MyCollection.find(), 20})
Use mixins on both levels
Of course you can define mixins on both levels, so that you have a certain set of default mixins and publication-specific mixins:
1import { createPublicationFactory } from 'meteor/leaonline:publication-factory' 2import { ValidatedPublication } from 'meteor/mdg:validated-publication' 3import { myDefaultMixin } from '/path/to/myDefaultMixin' 4import { someOtherMixin } from '/path/to/someOtherMixin' 5import { MyCollection } from '/path/to/MyCollection' 6 7const createPublication = createPublicationFactory({ mixins: [myDefaultMixin] }) 8 9const publicationWithMixin = createPublication({ 10 name: 'publicationWithMixin', 11 validate: () => {}, 12 run: () => MyCollection.find(), 13 foo: 'bar' // assuming your mixin requires foo 14}) 15 16const publicationWithMixins = createPublication({ 17 name: 'publicationWithMixin', 18 mixins: [someOtherMixin], 19 validate: () => {}, 20 run: () => MyCollection.find(), 21 foo: 'bar', // assuming your mixin requires foo 22 bar: 'baz', // assuming the other mixin requires bar 23})
Codestyle
We use standard
as code style and for linting.
via npm
$ npm install --global standard snazzy $ standard | snazzy
via Meteor npm
$ meteor npm install --global standard snazzy $ standard | snazzy
Test
We use meteortesting:mocha
to run our tests on the package.
Watch mode
$ TEST_WATCH=1 TEST_CLIENT=0 meteor test-packages ./ --driver-package meteortesting:mocha
Cli mode
License
MIT, see LICENSE