From a18ecadb6487392bcb3e64adff4f649d6374fceb Mon Sep 17 00:00:00 2001 From: Izel Nakri Date: Sat, 28 Oct 2017 13:51:06 +0200 Subject: [PATCH] relationships feature is complete with tests, small adjustments to error messages and randomly failing tests --- lib/mem-server.js | 4 +- lib/mem-server/model.js | 51 ++++- lib/mem-server/utils.js | 6 +- package.json | 2 - test/mem-server.fixtures.js | 10 +- test/mem-server.model.delete.js | 2 +- test/mem-server.model.insert.js | 4 +- test/mem-server.model.js | 33 +++ test/mem-server.model.query.js | 6 +- test/mem-server.model.relationships.js | 275 +++++++++++++++++++------ test/mem-server.utils.js | 4 +- 11 files changed, 304 insertions(+), 93 deletions(-) diff --git a/lib/mem-server.js b/lib/mem-server.js index b52871f..df5588e 100644 --- a/lib/mem-server.js +++ b/lib/mem-server.js @@ -105,9 +105,9 @@ function resetDatabase(models) { const primaryKey = getModelPrimaryKey(model, existingPrimaryKey, modelName); if (!primaryKey) { - throw new Error(chalk.red(`MemServer DATABASE ERROR: At least one of your ${modelName} fixtures missing a primary key. Please make sure all your ${modelName} fixtures have either id or uuid primaryKey`)); + throw new Error(chalk.red(`[MemServer] DATABASE ERROR: At least one of your ${modelName} fixtures missing a primary key. Please make sure all your ${modelName} fixtures have either id or uuid primaryKey`)); } else if (primaryKeys.includes(model[primaryKey])) { - throw new Error(chalk.red(`MemServer DATABASE ERROR: Duplication in ${modelName} fixtures with ${primaryKey}: ${model[primaryKey]}`)); + throw new Error(chalk.red(`[MemServer] DATABASE ERROR: Duplication in ${modelName} fixtures with ${primaryKey}: ${model[primaryKey]}`)); } const existingAttributes = targetNamespace.MemServer.Models[modelName].attributes; diff --git a/lib/mem-server/model.js b/lib/mem-server/model.js index 3f07944..3813e1a 100644 --- a/lib/mem-server/model.js +++ b/lib/mem-server/model.js @@ -1,7 +1,9 @@ import util from 'util'; import chalk from 'chalk'; import { primaryKeyTypeSafetyCheck, generateUUID } from './utils'; +import { classify, underscore } from 'ember-cli-string-utils'; +const { pluralize, singularize } = require('i')(); // NOTE: move to ES6 imports const targetNamespace = typeof global === 'object' ? global : window; export default function(options) { @@ -17,7 +19,7 @@ export default function(options) { }, find(param) { if (!param) { - throw new Error(chalk.red(`MemServer ${this.modelName}.find(id) cannot be called without a valid id`)); + throw new Error(chalk.red(`[MemServer] ${this.modelName}.find(id) cannot be called without a valid id`)); } else if (Array.isArray(param)) { const models = targetNamespace.MemServer.DB[this.modelName] || []; @@ -27,7 +29,7 @@ export default function(options) { return foundModel ? result.concat([foundModel]) : result; }, []); } else if (typeof param !== 'number') { - throw new Error(chalk.red(`MemServer ${this.modelName}.find(id) cannot be called without a valid id`)); + throw new Error(chalk.red(`[MemServer] ${this.modelName}.find(id) cannot be called without a valid id`)); } const models = targetNamespace.MemServer.DB[this.modelName] || []; @@ -36,7 +38,7 @@ export default function(options) { }, findBy(options) { if (!options) { - throw new Error(chalk.red(`MemServer ${this.modelName}.findBy(id) cannot be called without a parameter`)); + throw new Error(chalk.red(`[MemServer] ${this.modelName}.findBy(id) cannot be called without a parameter`)); } const keys = Object.keys(options); @@ -128,8 +130,16 @@ export default function(options) { return targetRecord; }, - embed(relationship) { // { comments: Comment } - // NOTE: console.error(`${relationshipName} couldnt found for ${model}, put an another model lookup as 4th argument to embed() perhaps?`); + embed(relationship) { // EXAMPLE: { comments: Comment } + if (typeof relationship !== 'object' || relationship.modelName) { + throw new Error(chalk.red(`[MemServer] ${this.modelName}.embed(relationshipObject) requires an object as a parameter: { relationshipKey: $RelationshipModel }`)); + } + + const key = Object.keys(relationship)[0]; + + if (!relationship[key]) { + throw new Error(chalk.red(`[MemServer] ${this.modelName}.embed() fails: ${key} Model reference is not a valid. Please put a valid $ModelName to ${this.modelName}.embed()`)); + } return Object.assign(this.embedReferences, relationship); }, @@ -143,7 +153,7 @@ export default function(options) { }, serialize(object) { // NOTE: add links object ? return Object.keys(this.embedReferences).reduce((result, embedObject) => { - const embedKey = Object.keys(embedObject)[0]; + const embedKey = Object.keys(embedObject)[0]; // NOTE: console.error(`${relationshipName} couldnt found for ${model}, put an another model lookup as 4th argument to embed() perhaps?`); const embedModel = embedObject[embedKey]; const embeddedRecords = this.getRelationship(object, embedKey, embedModel); @@ -151,10 +161,33 @@ export default function(options) { }, object); }, getRelationship(parentObject, relationshipName, relationshipModel) { - // NOTE: checking from the relationship name if its plural - // NOTE: could be on both sides this or relationshipModel.modelName + if (Array.isArray(parentObject)) { + throw new Error(chalk.red(`[MemServer] ${this.modelName}.getRelationship expects model input to be an object not an array`)); + } + + const targetRelationshipModel = relationshipModel || + targetNamespace.MemServer.Models[classify(singularize(relationshipName))]; + const hasManyRelationship = pluralize(relationshipName) === relationshipName; + + if (!targetRelationshipModel) { // NOTE: test this + throw new Error(chalk.red(`[MemServer] ${relationshipName} relationship could not be found on ${this.modelName} model. Please put the ${relationshipName} Model object as the third parameter to ${this.modelName}.getRelationship function`)); + } else if (hasManyRelationship) { + const hasManyRecords = targetRelationshipModel.findAll({ + [`${underscore(this.modelName)}_id`]: parentObject.id + }); + + return hasManyRecords.length > 0 ? hasManyRecords : []; + } + + const objectsReference = parentObject[`${underscore(targetRelationshipModel.modelName)}_id`]; + + if (objectsReference) { + return targetRelationshipModel.find(objectsReference); + } - // NOTE: console.error(`${relationshipName} couldnt found for ${model}, put an another model lookup as 4th argument to embed() perhaps?`); + return targetRelationshipModel.findBy({ // NOTE: id or uuid lookup? + [`${underscore(this.modelName)}_id`]: parentObject.id + }); } }, options); } diff --git a/lib/mem-server/utils.js b/lib/mem-server/utils.js index 204f7df..3486749 100644 --- a/lib/mem-server/utils.js +++ b/lib/mem-server/utils.js @@ -3,7 +3,7 @@ import chalk from 'chalk'; export function generateUUID() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8); - + return v.toString(16); }); } @@ -12,9 +12,9 @@ export function primaryKeyTypeSafetyCheck(targetPrimaryKeyType, primaryKey, mode const primaryKeyType = typeof primaryKey; if (targetPrimaryKeyType === 'id' && (primaryKeyType !== 'number')) { - throw new Error(chalk.red(`MemServer ${modelName} model primaryKey type is 'id'. Instead you've tried to enter id: ${primaryKey} with ${primaryKeyType} type`)); + throw new Error(chalk.red(`[MemServer] ${modelName} model primaryKey type is 'id'. Instead you've tried to enter id: ${primaryKey} with ${primaryKeyType} type`)); } else if (targetPrimaryKeyType === 'uuid' && (primaryKeyType !== 'string')) { - throw new Error(chalk.red(`MemServer ${modelName} model primaryKey type is 'uuid'. Instead you've tried to enter uuid: ${primaryKey} with ${primaryKeyType} type`)); + throw new Error(chalk.red(`[MemServer] ${modelName} model primaryKey type is 'uuid'. Instead you've tried to enter uuid: ${primaryKey} with ${primaryKeyType} type`)); } return targetPrimaryKeyType; diff --git a/package.json b/package.json index ecbe3aa..a2cd677 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,7 @@ "babel-preset-env": "^1.6.1", "babel-register": "^6.26.0", "chalk": "^2.2.0", - "core-object": "^3.1.5", "ember-cli-string-utils": "^1.1.0", - "ember-inflector": "^2.0.1", "fake-xml-http-request": "^1.6.0", "i": "^0.3.6", "jsdom": "^11.3.0", diff --git a/test/mem-server.fixtures.js b/test/mem-server.fixtures.js index 9487a4f..c2168ad 100644 --- a/test/mem-server.fixtures.js +++ b/test/mem-server.fixtures.js @@ -89,7 +89,7 @@ describe('MemServer fixture constraint feature', function() { assert.throws(() => MemServer.start(), (err) => { return (err instanceof Error) && - /MemServer DATABASE ERROR\: At least one of your PhotoComment fixtures missing a primary key\. Please make sure all your PhotoComment fixtures have either id or uuid primaryKey/.test(err); + /\[MemServer\] DATABASE ERROR\: At least one of your PhotoComment fixtures missing a primary key\. Please make sure all your PhotoComment fixtures have either id or uuid primaryKey/.test(err); }); assert.deepEqual(MemServer.Pretender, {}); @@ -158,7 +158,7 @@ describe('MemServer fixture constraint feature', function() { assert.throws(() => MemServer.start(), (err) => { return (err instanceof Error) && - /MemServer Photo model primaryKey type is 'id'. Instead you've tried to enter id: 2 with string type/.test(err); + /\[MemServer\] Photo model primaryKey type is 'id'. Instead you've tried to enter id: 2 with string type/.test(err); }); assert.deepEqual(MemServer.Pretender, {}); @@ -229,7 +229,7 @@ describe('MemServer fixture constraint feature', function() { assert.throws(() => MemServer.start(), (err) => { return (err instanceof Error) && - /MemServer PhotoComment model primaryKey type is 'uuid'. Instead you've tried to enter uuid: 12 with number type/.test(err); + /\[MemServer\] PhotoComment model primaryKey type is 'uuid'. Instead you've tried to enter uuid: 12 with number type/.test(err); }); assert.deepEqual(MemServer.Pretender, {}); @@ -265,7 +265,7 @@ describe('MemServer fixture constraint feature', function() { assert.throws(() => MemServer.start(), (err) => { return (err instanceof Error) && - /MemServer DATABASE ERROR: Duplication in Photo fixtures with id: 2/.test(err); + /\[MemServer\] DATABASE ERROR: Duplication in Photo fixtures with id: 2/.test(err); }); }); @@ -302,7 +302,7 @@ describe('MemServer fixture constraint feature', function() { assert.throws(() => MemServer.start(), (err) => { return (err instanceof Error) && - /MemServer DATABASE ERROR: Duplication in PhotoComment fixtures with uuid: 499ec646-493f-4eea-b92e-e383d94182f4/.test(err); + /\[MemServer\] DATABASE ERROR: Duplication in PhotoComment fixtures with uuid: 499ec646-493f-4eea-b92e-e383d94182f4/.test(err); }); }); }); diff --git a/test/mem-server.model.delete.js b/test/mem-server.model.delete.js index 0e05783..2544efc 100644 --- a/test/mem-server.model.delete.js +++ b/test/mem-server.model.delete.js @@ -135,7 +135,7 @@ describe('MemServer.Model Delete Interface', function() { assert.throws(() => Photo.delete({ id: 1 }), (err) => { return (err instanceof Error) && - /\[MemServer] Photo has no records in the database to delete\. Photo\.delete\(\{ id: 1 \}\) failed/.test(err); + /\[MemServer\] Photo has no records in the database to delete\. Photo\.delete\(\{ id: 1 \}\) failed/.test(err); }); assert.throws(() => PhotoComment.delete({ uuid: '374c7f4a-85d6-429a-bf2a-0719525f5111' }), (err) => { return (err instanceof Error) && diff --git a/test/mem-server.model.insert.js b/test/mem-server.model.insert.js index 31c663a..4bcba01 100644 --- a/test/mem-server.model.insert.js +++ b/test/mem-server.model.insert.js @@ -329,11 +329,11 @@ describe('MemServer.Model Insert Interface', function() { assert.throws(() => Photo.insert({ id: '99' }), (err) => { return (err instanceof Error) && - /MemServer Photo model primaryKey type is 'id'. Instead you've tried to enter id: 99 with string type/.test(err); + /\[MemServer\] Photo model primaryKey type is 'id'. Instead you've tried to enter id: 99 with string type/.test(err); }); assert.throws(() => PhotoComment.insert({ uuid: 1 }), (err) => { return (err instanceof Error) && - /MemServer PhotoComment model primaryKey type is 'uuid'. Instead you've tried to enter uuid: 1 with number type/.test(err); + /\[MemServer\] PhotoComment model primaryKey type is 'uuid'. Instead you've tried to enter uuid: 1 with number type/.test(err); }); }); }); diff --git a/test/mem-server.model.js b/test/mem-server.model.js index 3601e0c..eb4836e 100644 --- a/test/mem-server.model.js +++ b/test/mem-server.model.js @@ -145,6 +145,39 @@ describe('MemServer.Model Interface', function() { }); it('reads the defaultAttributes correctly', function() { + fs.writeFileSync(`${process.cwd()}/memserver/models/photo.js`, ` + import faker from 'faker'; + import Model from '${process.cwd()}/lib/mem-server/model'; + + export default Model({ + defaultAttributes: { + is_public: true, + name() { + return faker.name.title(); + } + }, + publicPhotos() { + return this.findAll({ is_public: true }); + } + }); + `); + fs.writeFileSync(`${process.cwd()}/memserver/models/photo-comment.js`, ` + import moment from 'moment'; + import Model from '${process.cwd()}/lib/mem-server/model'; + + export default Model({ + defaultAttributes: { + inserted_at() { + return moment().toJSON(); + }, + is_important: true + }, + forPhoto(photo) { + return this.findAll({ photo_id: photo.id }); + } + }); + `); + Object.keys(require.cache).forEach((key) => delete require.cache[key]); const MemServer = require('../index.js'); diff --git a/test/mem-server.model.query.js b/test/mem-server.model.query.js index f985db8..58bc864 100644 --- a/test/mem-server.model.query.js +++ b/test/mem-server.model.query.js @@ -87,11 +87,11 @@ describe('MemServer.Model Query Interface', function() { array.forEach((param) => { assert.throws(() => Photo.find(param), (err) => { return (err instanceof Error) && - /MemServer Photo.find\(id\) cannot be called without a valid id/.test(err); + /\[MemServer\] Photo.find\(id\) cannot be called without a valid id/.test(err); }); assert.throws(() => PhotoComment.find(param), (err) => { return (err instanceof Error) && - /MemServer PhotoComment.find\(id\) cannot be called without a valid id/.test(err); + /\[MemServer\] PhotoComment.find\(id\) cannot be called without a valid id/.test(err); }); }); }); @@ -134,7 +134,7 @@ describe('MemServer.Model Query Interface', function() { assert.throws(() => Photo.findBy(), (err) => { return (err instanceof Error) && - /MemServer Photo.findBy\(id\) cannot be called without a parameter/.test(err); + /\[MemServer\] Photo.findBy\(id\) cannot be called without a parameter/.test(err); }); }); diff --git a/test/mem-server.model.relationships.js b/test/mem-server.model.relationships.js index 2e089f2..03a27ff 100644 --- a/test/mem-server.model.relationships.js +++ b/test/mem-server.model.relationships.js @@ -10,14 +10,22 @@ describe('MemServer.Model Relationships Interface', function() { fs.mkdirSync(`./memserver/models`); fs.writeFileSync(`${process.cwd()}/memserver/models/photo.js`, ` import Model from '${process.cwd()}/lib/mem-server/model'; + import PhotoComment from '${process.cwd()}/memserver/models/photo-comment.js'; export default Model({ + embedReferences: { + comments: PhotoComment + } }); `); fs.writeFileSync(`${process.cwd()}/memserver/models/photo-comment.js`, ` import Model from '${process.cwd()}/lib/mem-server/model'; + import User from '${process.cwd()}/memserver/models/user.js'; export default Model({ + embedReferences: { + author: User + } }); `); fs.writeFileSync(`${process.cwd()}/memserver/models/user.js`, ` @@ -111,70 +119,209 @@ describe('MemServer.Model Relationships Interface', function() { done(); }); - // it('can register relationship embeds before runtime', function() { - // const MemServer = require('../index.js'); - // const { Photo, PhotoComment } = MemServer.Models; - // - // MemServer.start(); - // - // - // }); - - // it('can register relationships embeds during runtime', function() { - // - // }); - - it('works for hasOne/belongsTo relationships both sides', function() { - const MemServer = require('../index.js'); - const { Photo, Activity } = MemServer.Models; - - MemServer.start(); - - const activity = Photo.getRelationship(Photo.find(1), 'activity'); - - assert.deepEqual(activity, [{ id: 1, user_id: 1, photo_id: 1 }]); - assert.deepEqual(Photo.getRelationship(Photo.find(2), 'activity'), null); - assert.deepEqual(Activity.getRelationship(activity, 'photo'), [ - { id: 1, name: 'Ski trip', href: 'ski-trip.jpeg', is_public: false } - ]); - assert.deepEqual(Activity.getRelationship(Activity.find(2), 'photo'), null); + describe('$Model.getRelationship method', function() { + it('works for hasOne/belongsTo relationships both sides', function() { + const MemServer = require('../index.js'); + const { Photo, Activity } = MemServer.Models; + + MemServer.start(); + + const activity = Photo.getRelationship(Photo.find(1), 'activity'); + + assert.deepEqual(activity, { id: 1, user_id: 1, photo_id: 1 }); + assert.deepEqual(Photo.getRelationship(Photo.find(2), 'activity'), null); + assert.deepEqual(Activity.getRelationship(activity, 'photo'), Photo.find(1)); + assert.deepEqual(Activity.getRelationship(Activity.find(2), 'photo'), null); + }); + + it('works for hasMany/belongsTo relationships both sides', function() { + const photoCommentCode = fs.readFileSync(`${process.cwd()}/memserver/models/photo-comment.js`); + const commentFixtures = fs.readFileSync(`${process.cwd()}/memserver/fixtures/photo-comments.js`); + + fs.writeFileSync(`${process.cwd()}/memserver/models/comment.js`, photoCommentCode); + fs.writeFileSync(`${process.cwd()}/memserver/fixtures/comments.js`, commentFixtures); + + const MemServer = require('../index.js'); + const { Photo, Comment } = MemServer.Models; + + MemServer.start(); + + const firstPhotoComments = Photo.getRelationship(Photo.find(1), 'comments'); + const secondPhotoComments = Photo.getRelationship(Photo.find(2), 'comments'); + const thirdPhotoComments = Photo.getRelationship(Photo.find(3), 'comments'); + + assert.deepEqual(firstPhotoComments, [ + { + uuid: '499ec646-493f-4eea-b92e-e383d94182f4', content: 'What a nice photo!', photo_id: 1, + user_id: 1 + }, + { + uuid: '77653ad3-47e4-4ec2-b49f-57ea36a627e7', content: 'I agree', photo_id: 1, + user_id: 2 + }, + { + uuid: 'd351963d-e725-4092-a37c-1ca1823b57d3', content: 'I was kidding', photo_id: 1, + user_id: 1 + } + ]); + assert.deepEqual(secondPhotoComments, [ + { + uuid: '374c7f4a-85d6-429a-bf2a-0719525f5f29', content: 'Interesting indeed', photo_id: 2, + user_id: 1 + } + ]); + assert.deepEqual(thirdPhotoComments, []); + assert.throws(() => Comment.getRelationship(firstPhotoComments, 'photo'), (err) => { + return (err instanceof Error) && + /\[MemServer\] Comment\.getRelationship expects model input to be an object not an array/.test(err); + }); + assert.deepEqual(Comment.getRelationship(firstPhotoComments[0], 'photo'), { + id: 1, + name: 'Ski trip', + href: 'ski-trip.jpeg', + is_public: false + }); + assert.deepEqual(Comment.getRelationship(secondPhotoComments[0], 'photo'), { + id: 2, + name: 'Family photo', + href: 'family-photo.jpeg', + is_public: true + }); + + fs.unlinkSync(`${process.cwd()}/memserver/models/comment.js`); + fs.unlinkSync(`${process.cwd()}/memserver/fixtures/comments.js`); + }); + + it('works for custom named hasOne/belongsTo and relationships both side', function() { + const MemServer = require('../index.js'); + const { Photo, Activity } = MemServer.Models; + + MemServer.start(); + + const activity = Photo.getRelationship(Photo.find(1), 'userActivity', Activity); + + assert.deepEqual(activity, { id: 1, user_id: 1, photo_id: 1 }); + assert.deepEqual(Photo.getRelationship(Photo.find(2), 'userActivity', Activity), null); + assert.deepEqual(Activity.getRelationship(activity, 'userPhoto', Photo), Photo.find(1)); + assert.deepEqual(Activity.getRelationship(Activity.find(2), 'userPhoto', Photo), null); + }); + + it('works for custom named hasMany/belongsTo relationships both side', function() { + const MemServer = require('../index.js'); + const { Photo, PhotoComment } = MemServer.Models; + + MemServer.start(); + + const firstPhotoComments = Photo.getRelationship(Photo.find(1), 'comments', PhotoComment); + const secondPhotoComments = Photo.getRelationship(Photo.find(2), 'comments', PhotoComment); + const thirdPhotoComments = Photo.getRelationship(Photo.find(3), 'comments', PhotoComment); + + assert.deepEqual(firstPhotoComments, [ + { + uuid: '499ec646-493f-4eea-b92e-e383d94182f4', content: 'What a nice photo!', photo_id: 1, + user_id: 1 + }, + { + uuid: '77653ad3-47e4-4ec2-b49f-57ea36a627e7', content: 'I agree', photo_id: 1, + user_id: 2 + }, + { + uuid: 'd351963d-e725-4092-a37c-1ca1823b57d3', content: 'I was kidding', photo_id: 1, + user_id: 1 + } + ]); + assert.deepEqual(secondPhotoComments, [ + { + uuid: '374c7f4a-85d6-429a-bf2a-0719525f5f29', content: 'Interesting indeed', photo_id: 2, + user_id: 1 + } + ]); + assert.deepEqual(thirdPhotoComments, []); + assert.throws(() => PhotoComment.getRelationship(firstPhotoComments, 'photo'), (err) => { + return (err instanceof Error) && + /\[MemServer\] PhotoComment\.getRelationship expects model input to be an object not an array/.test(err); + }); + assert.deepEqual(PhotoComment.getRelationship(firstPhotoComments[0], 'photo'), { + id: 1, + name: 'Ski trip', + href: 'ski-trip.jpeg', + is_public: false + }); + assert.deepEqual(PhotoComment.getRelationship(secondPhotoComments[0], 'photo'), { + id: 2, + name: 'Family photo', + href: 'family-photo.jpeg', + is_public: true + }); + }); + + it('throws an error when relationship reference is invalid', function() { + const MemServer = require('../index.js'); + const { Photo, PhotoComment } = MemServer.Models; + + MemServer.start(); + + assert.throws(() => Photo.getRelationship(Photo.find(1), 'comments'), (err) => { + return (err instanceof Error) && + /\[MemServer\] comments relationship could not be found on Photo model\. Please put the comments Model object as the third parameter to Photo\.getRelationship function/.test(err); + }); + assert.throws(() => Photo.getRelationship(Photo.find(2), 'userActivity'), (err) => { + return (err instanceof Error) && + /\[MemServer\] userActivity relationship could not be found on Photo model\. Please put the userActivity Model object as the third parameter to Photo\.getRelationship function/.test(err); + }); + }); }); - // it('works for hasMany/belongsTo relationships both side', function() { - // const MemServer = require('../index.js'); - // const { Photo, PhotoComment } = MemServer.Models; - // - // MemServer.start(); - // - // const firstPhotoComments = Photo.getRelationship(Photo.find(1), 'comments'); - // const secondPhotoComments = Photo.getRelationship(Photo.find(2), 'comments'); - // const thirdPhotoComments = Photo.getRelationship(Photo.find(3), 'comments'); - // - // assert.deepEqual(firstPhotoComments, [ - // - // ]); - // assert.deepEqual(secondPhotoComments, [ - // - // ]); - // assert.deepEqual(thirdPhotoComments, [ - // - // ]); - // assert.deepEqual(PhotoComment.getRelationship(firstPhotoComments, 'photo'), [ - // - // ]); - // assert.deepEqual(PhotoComment.getRelationship(secondPhotoComments, 'photo'), [ - // - // ]); - // assert.deepEqual(PhotoComment.getRelationship(thirdPhotoComments, 'photo'), [ - // - // ]); - // }); - // - // it('works for custom named hasOne/belongsTo and hasMany/belongsTo relationships both side', function() { - // - // }); - // - // it('throws an error when relationship reference is invalid', function() { - // // NOTE: setup userActivity <-> Photo relationship - // }); + describe('$Model relationship embedding', function() { + it('can register relationship embeds before runtime', function() { + const MemServer = require('../index.js'); + const { Photo, PhotoComment, User } = MemServer.Models; + + MemServer.start(); + + assert.deepEqual(Photo.embedReferences, { comments: PhotoComment }); + assert.deepEqual(PhotoComment.embedReferences, { author: User }); + }); + + it('can register relationships embeds during runtime', function() { + const MemServer = require('../index.js'); + const { Activity, Photo, PhotoComment, User } = MemServer.Models; + + MemServer.start(); + + Photo.embed({ userActivity: Activity }); + User.embed({ activities: Activity }); + + assert.deepEqual(Photo.embedReferences, { comments: PhotoComment, userActivity: Activity }); + assert.deepEqual(User.embedReferences, { activities: Activity }); + }); + + it('throws error when runtime $Model.embed() doesnt receive an object parameter', function() { + const MemServer = require('../index.js'); + const { Activity, User } = MemServer.Models; + + MemServer.start(); + + assert.throws(() => User.embed(), (err) => { + return (err instanceof Error) && + /\[MemServer\] User\.embed\(relationshipObject\) requires an object as a parameter: { relationshipKey: \$RelationshipModel }/.test(err); + }); + assert.throws(() => User.embed(Activity), (err) => { + return (err instanceof Error) && + /\[MemServer\] User\.embed\(relationshipObject\) requires an object as a parameter: { relationshipKey: \$RelationshipModel }/.test(err); + }); + }); + + it('throws error when runtime $Model.embed(relationship) called with a Model that doesnt exist', function() { + const MemServer = require('../index.js'); + const { Activity, User } = MemServer.Models; + + MemServer.start(); + + assert.throws(() => User.embed({ activities: undefined }), (err) => { + return (err instanceof Error) && + /\[MemServer\] User\.embed\(\) fails: activities Model reference is not a valid\. Please put a valid \$ModelName to User\.embed\(\)/.test(err); + }); + }); + }); }); diff --git a/test/mem-server.utils.js b/test/mem-server.utils.js index 26db083..273566a 100644 --- a/test/mem-server.utils.js +++ b/test/mem-server.utils.js @@ -19,12 +19,12 @@ describe('MemServer Utils Unit tests', function() { it('exports primaryKeyTypeSafetyCheck correctly', function() { assert.throws(() => primaryKeyTypeSafetyCheck('id', '22', 'Photo'), (err) => { return (err instanceof Error) && - /MemServer Photo model primaryKey type is 'id'. Instead you've tried to enter id: 22 with string type/.test(err); + /\[MemServer\] Photo model primaryKey type is 'id'. Instead you've tried to enter id: 22 with string type/.test(err); }); assert.doesNotThrow(() => primaryKeyTypeSafetyCheck('id', 22, 'Photo'), Error); assert.throws(() => primaryKeyTypeSafetyCheck('uuid', 22, 'PhotoComment'), (err) => { return (err instanceof Error) && - /MemServer PhotoComment model primaryKey type is 'uuid'. Instead you've tried to enter uuid: 22 with number type/.test(err); + /\[MemServer\] PhotoComment model primaryKey type is 'uuid'. Instead you've tried to enter uuid: 22 with number type/.test(err); }); assert.doesNotThrow(() => primaryKeyTypeSafetyCheck('uuid', '166a435d-ad3d-4662-9f6f-04373280a38b', 'PhotoComment'), Error); });