mongoose-fill
Version:
Mongoose.js add-on that adds virtual (temporary) async fileds API
277 lines (238 loc) • 7.43 kB
JavaScript
import test from 'tape';
import mongoose from './index';
mongoose.connect('mongodb://localhost/mongoose_fill_test');
const userSchema = new mongoose.Schema({
_id: 'number',
name: 'string',
age: 'number',
dude: { type: 'number', ref: 'User' }
})
const accountSchema = new mongoose.Schema({
_id: 'number',
name: 'string'
})
const petSchema = new mongoose.Schema({
_id: 'number',
name: 'string',
master: { type: 'number', ref: 'User' }
})
accountSchema.fill('upper', function (add, callback) {
this.db.model('User')
callback(null, this.name.toUpperCase() + add)
}).options('_Y')
const surnames = ['Galt', 'Dow']
const Account = mongoose.model('Account', accountSchema)
const makeAccounts = (names) => {
return names.map(name => new Account({ name: name }))
}
userSchema.fill('surname', function (callback) {
this.db.model('User')
const val = surnames[this._id - 1]
callback(null, val)
}).multi(function (users, ids, callback) {
const result = ids.map(function (id) {
return { _id: id, surname: surnames[id - 1] }
})
callback(null, result)
})
userSchema.fill('accounts').value(function (callback) {
const val = [
makeAccounts(['fb', 'twitter']),
makeAccounts(['google'])
][this._id - 1]
callback(null, val)
}).default([])
userSchema.fill('actions mood', function (upperCase, prefix, callback) {
const mood = prefix + 'good'
callback(null, {
actions: ['eat', 'pray', 'kill'],
mood: (upperCase ? mood.toUpperCase() : mood)
})
}).options(false, 'super')
userSchema.fill('purchases', function (callback) {
callback(null, [{ amount: 5 }, { amount: 10 }])
})
userSchema.fill('friend', function (callback) {
const val = [
new User({ _id: 2 }),
new User({ _id: 1 })
][this._id - 1]
callback(null, val)
})
userSchema.fill('nested.dude', function (callback) {
this.db.model('User')
.findOne({_id: this.dude})
.exec(callback)
})
const User = mongoose.model('User', userSchema)
const Pet = mongoose.model('Pet', petSchema)
test('setup', async t => {
const usersData = [
{ _id: 1, name: 'Alex', age: 10 },
{ _id: 2, name: 'Jane', age: 12, dude: 1 }
];
try {
await User.remove({});
await User.create(usersData);
t.end();
} catch (err) {
t.error(err);
}
})
test('fill one property: purchases', async t => {
try {
const user = await User.findById(1).fill('purchases');
t.ok(user.name == 'Alex', 'user name is ok');
t.ok(!!user.purchases, 'user purchases present');
t.ok(user.purchases[0].amount == 5, 'first purchase amount is ok');
t.end();
} catch (err) {
t.error(err);
}
})
test('fill one property: purchases (exec callback)', async t => {
User.findById(1).fill('purchases').exec((err, user) => {
t.ok(user.name == 'Alex', 'user name is ok');
t.ok(!!user.purchases, 'user purchases present');
t.ok(user.purchases[0].amount == 5, 'first purchase amount is ok');
t.end();
});
});
test('fill multiple properties with select: purchases, actions', async t => {
try {
const user = await User.findById(1).select('name purchases actions')
t.ok(user.name == 'Alex', 'user name is ok')
//t.ok(user.accounts && user.accounts.length == 0, 'user accounts filled with default value')
t.ok(!user.age, 'user age not selected')
t.ok(user.purchases && user.purchases.length > 0, 'purchases here')
t.ok(user.actions && user.actions.length > 0, 'actions here')
t.ok(!user.mood, 'mood is not here')
t.end();
} catch (err) {
t.error(err);
}
})
test('fill on instance only one (exclusive) "mood" prop with lacking options', async t => {
t.plan(2);
try {
let user = await User.findById(1)
user = await user.fill('mood', true);
t.is(user.mood, 'SUPERGOOD', 'user mood here')
t.ok(!user.actions, 'user actions not here')
//t.ok(user.actions && user.actions.length > 0, 'user actions here')
} catch (err) {
t.error(err);
};
})
test('fill on instance: mood, actions, surname', async t => {
try {
let user = await User.findById(1);
user = await user.fill('mood actions surname');
t.is(user.mood, 'supergood', 'user mood here')
t.ok(user.actions && user.actions.length > 0, 'user actions here')
t.ok(user.surname == 'Galt', 'surname is here')
t.end()
} catch (err) {
t.error(err);
}
});
test('fill property using multi: surnames', async t => {
try {
const users = await User
.find({ name: { $exists: true } })
//.sort('accounts')
.limit(5)
.fill('accounts surname')
.fill('accounts.upper')
t.ok(users.length == 2, 'user count ok')
t.is(users[0].surname, surnames[users[0].id - 1], 'user1 surname ok ok')
t.ok(users[0].accounts, 'user1 accounts filled')
t.is(users[0].accounts.length, 2, 'user1 accounts count ok')
t.is(users[0].accounts[0].upper, 'FB_Y', 'user1 accounts count ok')
t.is(users[1].surname, surnames[users[1].id - 1], 'user2 surname ok ok')
t.end();
} catch (err) {
t.error(err);
}
});
test('fill friend nested', async t => {
try {
const users = await User
.find({ name: { $exists: true } })
.fill('friend.accounts.upper', '_X');
t.ok(users[0].friend, 'user1 friend filled')
t.ok(users[0].friend.accounts, 'user1 friend.accounts filled')
t.is(users[0].friend.accounts[0].upper, 'GOOGLE_X', 'user1 friend filled')
t.ok(users[1].friend, 'user2 friend filled')
t.end()
} catch (err) {
t.error(err);
}
})
test('fill nested dude', async t => {
try {
const users = await User
.find({ name: 'Jane' })
.fill('nested.dude');
t.ok(users[0].nested.dude, 'user2 nested dude filled')
t.is(users[0].nested.dude.name, 'Alex', 'user2 nested dude filled')
t.end()
} catch (err) {
t.error(err);
}
})
test('should not fill absent property', async t => {
try {
const users = await User
.find({ name: { $exists: true } })
.fill('absent.accounts.upper', '_X')
t.ok(!users[0].enemy, 'user1 enemy is empty')
t.end()
} catch (err) {
t.error(err);
}
})
test('should not fill absent property', async t => {
try {
const users = await User
.find({ name: { $exists: true } })
.fill('enemy.accounts.upper', '_X')
t.ok(!users[0].enemy, 'user1 enemy is empty')
t.end()
} catch (err) {
t.error(err);
}
})
test('should fill nested not filled property', async t => {
try {
const user = await User
.findOne({ name: 'Jane' })
.populate('dude')
.fill('dude.accounts.upper', '_X')
t.is(user.dude.name, 'Alex', 'user.dude name is correct')
t.is(user.dude.accounts.length, 2, 'user.dude accounts filled')
t.end()
} catch (err) {
t.error(err);
}
})
test('should fill nested on model that has no fill property', async t => {
try {
const pet = new Pet({ master: new User({ name: 'Alex', _id: 1 }) })
await pet.fill('master.accounts')
t.is(pet.master.accounts.length, 2, 'pet.master.accounts filled')
t.end()
} catch (err) {
t.error(err);
}
})
test('should fill nested on model that has no fill property (promise)', t => {
const pet = new Pet({ master: new User({ name: 'Alex', _id: 1 }) })
pet.fill('master.accounts').then((pet) => {
t.is(pet.master.accounts.length, 2, 'pet.master.accounts filled')
t.end()
}, t.error)
})
test.onFinish(() => {
process.exit()
})