Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Glob pattern to load fixtures and save fallback #11

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
language: node_js
services: mongodb
node_js:
- 0.8
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mongoose-fixtures
mongoose-fixtures [![Build Status](https://travis-ci.org/joaoneto/mongoose-fixtures.png?branch=master)](https://travis-ci.org/joaoneto/mongoose-fixtures)
=================

Simple fixture loader for Mongoose on NodeJS.
Expand Down Expand Up @@ -63,6 +63,22 @@ Usage

//Directories (loads all files in the directory)
fixtures.load(__dirname + '/fixtures');

//You can use patterns to match files
//this match all, excluding all index.*
fixturesLoader.load('./fixtures/!(index.*)(.*)');

//This match /fixture/user/* and /fixture/user/*
fixture.load('./fixtures/{user,blog}/*.js');

See:

* `man sh`
* `man bash`
* `man 3 fnmatch`
* `man 5 gitignore`
* [node-glob](https://github.com/isaacs/node-glob)
* [minimatch documentation](https://github.com/isaacs/minimatch)

Installation
------------
Expand Down
132 changes: 49 additions & 83 deletions mongoose_fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
var fs = require('fs');
var mongoose = require('mongoose');
var async = require('async');

var path = require('path');
var glob = require('glob');


/**
* Clears a collection and inserts the given data as new documents
Expand All @@ -18,6 +20,8 @@ var load = exports.load = function(data, db, callback) {
if (typeof db === 'function') {
callback = db;
db = mongoose.connection;
} else {
db = db || mongoose.connection;
}

if (typeof data == 'object') {
Expand All @@ -26,23 +30,7 @@ var load = exports.load = function(data, db, callback) {

} else if (typeof data == 'string') {

//Get the absolute dir path if a relative path was given
if (data.substr(0, 1) !== '/') {
var parentPath = module.parent.filename.split('/');
parentPath.pop();
data = parentPath.join('/') + '/' + data;
}

//Determine if data is pointing to a file or directory
fs.stat(data, function(err, stats) {
if (err) throw err;

if (stats.isDirectory()) {
loadDir(data, db, callback);
} else { //File
loadFile(data, db, callback);
}
});
loadFiles(data, db, callback);

} else { //Unsupported type

Expand All @@ -51,7 +39,7 @@ var load = exports.load = function(data, db, callback) {
}
}


/**
* Clears a collection and inserts the given data as new documents
*
Expand All @@ -65,17 +53,14 @@ var load = exports.load = function(data, db, callback) {
*/
function insertCollection(modelName, data, db, callback) {
callback = callback || {};

//Counters for managing callbacks
var tasks = { total: 0, done: 0 };


//Load model
var Model = db.model(modelName);

//Clear existing collection
Model.collection.remove(function(err) {
if (err) return callback(err);

//Convert object to array
var items = [];
if (Array.isArray(data)) {
Expand All @@ -85,32 +70,37 @@ function insertCollection(modelName, data, db, callback) {
items.push(data[i]);
}
}

//Check number of tasks to run
if (items.length == 0) {
return callback();
} else {
tasks.total = items.length;
}

//Insert each item individually so we get Mongoose validation etc.
items.forEach(function(item) {

var iterator = function(item, next) {
var doc = new Model(item);
doc.save(function(err) {
if (err) return callback(err);

//Check if task queue is complete
tasks.done++;
if (tasks.done == tasks.total) callback();
});
//Insert each item individually so we get Mongoose validation etc.
doc.save(function (err) {
if (err) {
//Or Fallback Deep insert
Model.collection.insert(doc.toObject(), function (err, res) {
if (err) return next(err);
next();
});
}
else
next();
})
};
async.forEach(items, iterator, function (){
callback();
});
});
}


/**
* Loads fixtures from object data
*
*
* @param {Object} The data to load, keyed by the Mongoose model name e.g.:
* { User: [{name: 'Alex'}, {name: 'Bob'}] }
* @param {Connection} The mongoose connection to use
Expand All @@ -124,55 +114,31 @@ function loadObject(data, db, callback) {
async.forEach(Object.keys(data), iterator, callback);
}


/**
* Loads fixtures from one file
*
* Loads fixtures from matches of glob search filesystem pattern
*
* TODO: Add callback option
*
* @param {String} The full path to the file to load
*
* @param {String} The directory path to load e.g. 'data/fixtures' or '../data'
* @param {Connection} The mongoose connection to use
* @param {Function} Callback
*/
function loadFile(file, db, callback) {
callback = callback || function() {};

if (file.substr(0, 1) !== '/') {
var parentPath = module.parent.filename.split('/');
parentPath.pop();
file = parentPath.join('/') + '/' + file;
}

load(require(file), db, callback);
}
function loadFiles(data, db, callback) {
callback = callback || function() {};
var __cwd = module.parent.filename.split('/');
__cwd.pop();
__cwd = __cwd.join('/');

data = path.join(__cwd, data);
if (!/(\..*|\/\.\*|\.js*)$|[\(\)\!]/.test(data))
data = data + '/*.*';

/**
* Loads fixtures from all files in a directory
*
* TODO: Add callback option
*
* @param {String} The directory path to load e.g. 'data/fixtures' or '../data'
* @param {Connection} The mongoose connection to use
* @param {Function} Callback
*/
function loadDir(dir, db, callback) {
callback = callback || function() {};

//Get the absolute dir path if a relative path was given
if (dir.substr(0, 1) !== '/') {
var parentPath = module.parent.filename.split('/');
parentPath.pop();
dir = parentPath.join('/') + '/' + dir;
}

//Load each file in directory
fs.readdir(dir, function(err, files){
if (err) return callback(err);

var iterator = function(file, next){
loadFile(dir + '/' + file, db, next);
};
async.forEach(files, iterator, callback);
});
glob(data, { cwd: __cwd }, function(err, files) {
if (err) return callback(err);

var iterator = function(file, next) {
load(require(file), db, next);
};
async.forEach(files, iterator, callback);
});
};
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"url": "https://github.com/jackdbernier"
}
],
"version": "0.1.0",
"version": "0.1.1",
"repository": {
"type": "git",
"url": "http://github.com/powmedia/mongoose-fixtures.git"
Expand All @@ -34,7 +34,8 @@
],
"dependencies": {
"mongoose": "3.2.x",
"async": "0.1.x"
"async": "0.1.x",
"glob": "3.1.x"
},
"devDependencies": {
"mocha": "1.6.x",
Expand Down
7 changes: 7 additions & 0 deletions tests/fixtures/globfolder/clients.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
exports.Client = {
client1: {
_id: "516b515f4448521a66d1e551",
user_id: "5113ddd5f9bd2f0c06000003",
secret: "secret"
}
}
Empty file.
1 change: 1 addition & 0 deletions tests/fixtures/globfolder/index.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is not a fixture!
6 changes: 6 additions & 0 deletions tests/fixtures/paranoidhooks/paranoids.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
exports.Paranoid = {
paranoid1: {
_id: "516b515f4448521a66d1e551",
name: "Foo bar"
}
}
15 changes: 15 additions & 0 deletions tests/models/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
var mongoose = require('mongoose');

var ClientSchema = new mongoose.Schema({
user_id: { type: mongoose.Schema.ObjectId, ref: 'User', index: { unique: true }, required: true },
secret: { type: String, required: true },
redirect_uri: { type: String }
});

// Methods
ClientSchema.methods.getClientByUserId = function (user_id, next) {
this.findOne({ user_id: user_id }, next);
};

mongoose.model('Client', ClientSchema);

11 changes: 11 additions & 0 deletions tests/models/paranoid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
var mongoose = require('mongoose');

var ParanoidSchema = new mongoose.Schema({
name: { type: String, required: true },
});

ParanoidSchema.pre('save', function (next) {
return next(new Error('You can\'t do this!'));
});

mongoose.model('Paranoid', ParanoidSchema);
49 changes: 43 additions & 6 deletions tests/mongoose_fixtures.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@ var MongooseInitializer = require('openifyit-commons').MongooseInitializer;

describe('mongoose-fixtures test', function(){
before(function(done){
this.mongooseInitializer = new MongooseInitializer(process.env.MONGODB_URL, path.join(__dirname, './models'));
// @todo Fix connection and model loader
mongoose.connect(process.env.MONGODB_URL);
require('./models/client');
require('./models/paranoid');
require('./models/country.coffee');
done();

// this.mongooseInitializer = new MongooseInitializer(process.env.MONGODB_URL, path.join(__dirname, './models'));

var functions = [
this.mongooseInitializer.openConnection,
this.mongooseInitializer.loadModels
];
async.series(functions, done);
// var functions = [
// this.mongooseInitializer.openConnection,
// this.mongooseInitializer.loadModels
// ];
// async.series(functions, done);
});

after(function(done){
Expand Down Expand Up @@ -65,4 +72,34 @@ describe('mongoose-fixtures test', function(){
});
});
});

it('should load fixtures from glob pattern', function(done){
var pattern = './fixtures/globfolder/!(index.*)(*.*)';
fixturesLoader.load(pattern, function(err){
expect(err).not.to.be.ok();
var ClientSchema = mongoose.connection.model('Client');
ClientSchema.find({}, function(err, clients){
expect(err).not.to.be.ok();
expect(clients).to.be.ok();
expect(clients).to.be.an(Array);
expect(clients.length).to.be.eql(1);
done();
});
});
});

it('should load fixtures from a paranid model', function(done){
var pattern = './fixtures/paranoidhooks/paranoids.js';
fixturesLoader.load(pattern, function(err){
expect(err).not.to.be.ok();
var ParanoidSchema = mongoose.connection.model('Paranoid');
ParanoidSchema.find({}, function(err, paranoids){
expect(err).not.to.be.ok();
expect(paranoids).to.be.ok();
expect(paranoids).to.be.an(Array);
expect(paranoids.length).to.be.eql(1);
done();
});
});
});
});