mikro-orm
Advanced tools
Comparing version 0.6.2 to 0.6.3
@@ -16,3 +16,3 @@ import { Collection as MongoCollection, Db, FilterQuery } from 'mongodb'; | ||
private readonly metadata; | ||
constructor(db: Db, options?: Options); | ||
constructor(db: Db, options: Options); | ||
getCollection(entityName: string): MongoCollection; | ||
@@ -29,3 +29,3 @@ getRepository<T extends BaseEntity>(entityName: string): EntityRepository<T>; | ||
count(entityName: string, where: any): Promise<number>; | ||
persist(entity: BaseEntity, flush?: boolean): Promise<void>; | ||
persist(entity: BaseEntity | BaseEntity[], flush?: boolean): Promise<void>; | ||
/** | ||
@@ -32,0 +32,0 @@ * flush changes to database |
@@ -12,3 +12,3 @@ "use strict"; | ||
class EntityManager { | ||
constructor(db, options = {}) { | ||
constructor(db, options) { | ||
this.db = db; | ||
@@ -24,10 +24,3 @@ this.options = options; | ||
getCollection(entityName) { | ||
let col; | ||
if (Utils_1.Utils.isString(entityName)) { | ||
col = this.metadata[entityName] ? this.metadata[entityName].collection : entityName; | ||
} | ||
else { | ||
entityName = entityName.constructor.name; | ||
col = this.metadata[entityName].collection; | ||
} | ||
const col = this.metadata[entityName] ? this.metadata[entityName].collection : entityName; | ||
return this.db.collection(col); | ||
@@ -47,3 +40,4 @@ } | ||
} | ||
async find(entityName, where = {}, populate = [], orderBy = {}, limit = null, offset = 0) { | ||
async find(entityName, where = {}, populate = [], orderBy = {}, limit = null, offset = null) { | ||
Utils_1.Utils.prepareQuery(where); | ||
let query = `db.getCollection('${this.metadata[entityName].collection}').find(${JSON.stringify(where)})`; | ||
@@ -83,2 +77,3 @@ const resultSet = this.getCollection(entityName).find(where); | ||
} | ||
Utils_1.Utils.prepareQuery(where); | ||
const query = `db.getCollection('${this.metadata[entityName].collection}').find(${JSON.stringify(where)}).limit(1).next();`; | ||
@@ -100,8 +95,3 @@ this.options.logger(`[query-logger] ${query}`); | ||
if (this.identityMap[`${entityName}-${entity.id}`]) { | ||
// TODO populate missing references and rehydrate | ||
// something like Object.assign, but we need to handle references properly | ||
// entity = Object.assign(this.identityMap[`${entityName}-${entity.id}`] as T, data); | ||
if (this.identityMap[`${entityName}-${entity.id}`].isInitialized()) { | ||
delete entity['_initialized']; | ||
} | ||
entity.assign(data); | ||
} | ||
@@ -144,3 +134,10 @@ this.addToIdentityMap(entity); | ||
async persist(entity, flush = true) { | ||
await this.unitOfWork.persist(entity); | ||
if (entity instanceof BaseEntity_1.BaseEntity) { | ||
await this.unitOfWork.persist(entity); | ||
} | ||
else { | ||
for (const e of entity) { | ||
await this.unitOfWork.persist(e); | ||
} | ||
} | ||
if (flush) { | ||
@@ -147,0 +144,0 @@ await this.flush(); |
@@ -14,6 +14,6 @@ "use strict"; | ||
} | ||
async find(where, populate = [], orderBy = {}, limit = null, offset = 0) { | ||
async find(where, populate = [], orderBy = {}, limit = null, offset = null) { | ||
return this.em.find(this.entityName, where, populate, orderBy, limit, offset); | ||
} | ||
async findAll(populate = [], orderBy = {}, limit = null, offset = 0) { | ||
async findAll(populate = [], orderBy = {}, limit = null, offset = null) { | ||
return this.em.find(this.entityName, {}, populate, orderBy, limit, offset); | ||
@@ -20,0 +20,0 @@ } |
@@ -104,3 +104,4 @@ "use strict"; | ||
async immediateCommit(changeSet, removeFromStack = true) { | ||
this.runHooks(`before${changeSet.entity._id ? 'Update' : 'Create'}`, changeSet.entity); | ||
const type = changeSet.entity._id ? 'Update' : 'Create'; | ||
this.runHooks(`before${type}`, changeSet.entity); | ||
const metadata = this.em.entityFactory.getMetadata(); | ||
@@ -146,3 +147,3 @@ const meta = metadata[changeSet.entity.constructor.name]; | ||
} | ||
this.runHooks(`after${changeSet.entity._id ? 'Update' : 'Create'}`, changeSet.entity); | ||
this.runHooks(`after${type}`, changeSet.entity); | ||
if (removeFromStack) { | ||
@@ -149,0 +150,0 @@ this.persistStack.splice(changeSet.index, 1); |
@@ -15,3 +15,6 @@ import { BaseEntity } from './BaseEntity'; | ||
static copy(entity: any): any; | ||
static prepareQuery(query: any): any; | ||
static renameKey(payload: any, from: string, to: string): void; | ||
static convertObjectIds(payload: any): void; | ||
static getParamNames(func: Function | string): string[]; | ||
} |
@@ -5,2 +5,3 @@ "use strict"; | ||
const clone = require("clone"); | ||
const bson_1 = require("bson"); | ||
const BaseEntity_1 = require("./BaseEntity"); | ||
@@ -76,2 +77,26 @@ const Collection_1 = require("./Collection"); | ||
} | ||
static prepareQuery(query) { | ||
Utils.renameKey(query, 'id', '_id'); | ||
Utils.convertObjectIds(query); | ||
} | ||
static renameKey(payload, from, to) { | ||
if (payload[from] && !payload[to]) { | ||
payload[to] = payload[from]; | ||
delete payload[from]; | ||
} | ||
} | ||
static convertObjectIds(payload) { | ||
Object.keys(payload).forEach(k => { | ||
const v = payload[k]; | ||
if (Utils.isString(v) && v.match(/^[0-9a-f]{24}$/i)) { | ||
return payload[k] = new bson_1.ObjectID(v); | ||
} | ||
if (Utils.isArray(v)) { | ||
return payload[k] = v.map((id) => new bson_1.ObjectID(id)); | ||
} | ||
if (Utils.isObject(payload[k])) { | ||
return Utils.convertObjectIds(v); | ||
} | ||
}); | ||
} | ||
static getParamNames(func) { | ||
@@ -78,0 +103,0 @@ const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; |
@@ -19,3 +19,3 @@ import { Collection as MongoCollection, Db, FilterQuery, ObjectID } from 'mongodb'; | ||
constructor(private db: Db, public options = {} as Options) { | ||
constructor(private db: Db, public options: Options) { | ||
this.metadata = getMetadataStorage(); | ||
@@ -25,11 +25,3 @@ } | ||
getCollection(entityName: string): MongoCollection { | ||
let col; | ||
if (Utils.isString(entityName)) { | ||
col = this.metadata[entityName] ? this.metadata[entityName].collection : entityName; | ||
} else { | ||
entityName = entityName.constructor.name; | ||
col = this.metadata[entityName].collection; | ||
} | ||
const col = this.metadata[entityName] ? this.metadata[entityName].collection : entityName; | ||
return this.db.collection(col); | ||
@@ -52,3 +44,4 @@ } | ||
async find<T extends BaseEntity>(entityName: string, where = {} as FilterQuery<T>, populate: string[] = [], orderBy: { [k: string]: 1 | -1 } = {}, limit: number = null, offset = 0): Promise<T[]> { | ||
async find<T extends BaseEntity>(entityName: string, where = {} as FilterQuery<T>, populate: string[] = [], orderBy: { [k: string]: 1 | -1 } = {}, limit: number = null, offset: number = null): Promise<T[]> { | ||
Utils.prepareQuery(where); | ||
let query = `db.getCollection('${this.metadata[entityName].collection}').find(${JSON.stringify(where)})`; | ||
@@ -98,2 +91,4 @@ const resultSet = this.getCollection(entityName).find(where); | ||
Utils.prepareQuery(where); | ||
const query = `db.getCollection('${this.metadata[entityName].collection}').find(${JSON.stringify(where)}).limit(1).next();`; | ||
@@ -121,9 +116,3 @@ this.options.logger(`[query-logger] ${query}`); | ||
if (this.identityMap[`${entityName}-${entity.id}`]) { | ||
// TODO populate missing references and rehydrate | ||
// something like Object.assign, but we need to handle references properly | ||
// entity = Object.assign(this.identityMap[`${entityName}-${entity.id}`] as T, data); | ||
if (this.identityMap[`${entityName}-${entity.id}`].isInitialized()) { | ||
delete entity['_initialized']; | ||
} | ||
entity.assign(data); | ||
} | ||
@@ -177,4 +166,10 @@ | ||
async persist(entity: BaseEntity, flush = true): Promise<void> { | ||
await this.unitOfWork.persist(entity); | ||
async persist(entity: BaseEntity | BaseEntity[], flush = true): Promise<void> { | ||
if (entity instanceof BaseEntity) { | ||
await this.unitOfWork.persist(entity); | ||
} else { | ||
for (const e of entity) { | ||
await this.unitOfWork.persist(e); | ||
} | ||
} | ||
@@ -181,0 +176,0 @@ if (flush) { |
@@ -18,7 +18,7 @@ import { FilterQuery } from 'mongodb'; | ||
async find(where: FilterQuery<T>, populate: string[] = [], orderBy: { [k: string]: 1 | -1 } = {}, limit: number = null, offset = 0): Promise<T[]> { | ||
async find(where: FilterQuery<T>, populate: string[] = [], orderBy: { [k: string]: 1 | -1 } = {}, limit: number = null, offset: number = null): Promise<T[]> { | ||
return this.em.find<T>(this.entityName, where, populate, orderBy, limit, offset); | ||
} | ||
async findAll(populate: string[] = [], orderBy: { [k: string]: 1 | -1 } = {}, limit: number = null, offset = 0): Promise<T[]> { | ||
async findAll(populate: string[] = [], orderBy: { [k: string]: 1 | -1 } = {}, limit: number = null, offset: number = null): Promise<T[]> { | ||
return this.em.find<T>(this.entityName, {}, populate, orderBy, limit, offset); | ||
@@ -25,0 +25,0 @@ } |
@@ -125,3 +125,4 @@ import { Utils } from './Utils'; | ||
private async immediateCommit(changeSet: ChangeSet, removeFromStack = true): Promise<void> { | ||
this.runHooks(`before${changeSet.entity._id ? 'Update' : 'Create'}`, changeSet.entity); | ||
const type = changeSet.entity._id ? 'Update' : 'Create'; | ||
this.runHooks(`before${type}`, changeSet.entity); | ||
@@ -176,3 +177,3 @@ const metadata = this.em.entityFactory.getMetadata(); | ||
this.runHooks(`after${changeSet.entity._id ? 'Update' : 'Create'}`, changeSet.entity); | ||
this.runHooks(`after${type}`, changeSet.entity); | ||
@@ -179,0 +180,0 @@ if (removeFromStack) { |
import * as fastEqual from 'fast-deep-equal'; | ||
import * as clone from 'clone'; | ||
import { ObjectID } from 'bson'; | ||
import { BaseEntity } from './BaseEntity'; | ||
@@ -96,2 +97,32 @@ import { Collection } from './Collection'; | ||
static prepareQuery(query: any): any { | ||
Utils.renameKey(query, 'id', '_id'); | ||
Utils.convertObjectIds(query); | ||
} | ||
static renameKey(payload: any, from: string, to: string): void { | ||
if (payload[from] && !payload[to]) { | ||
payload[to] = payload[from]; | ||
delete payload[from]; | ||
} | ||
} | ||
static convertObjectIds(payload: any): void { | ||
Object.keys(payload).forEach(k => { | ||
const v = payload[k]; | ||
if (Utils.isString(v) && v.match(/^[0-9a-f]{24}$/i)) { | ||
return payload[k] = new ObjectID(v); | ||
} | ||
if (Utils.isArray(v)) { | ||
return payload[k] = v.map((id: string) => new ObjectID(id)); | ||
} | ||
if (Utils.isObject(payload[k])) { | ||
return Utils.convertObjectIds(v); | ||
} | ||
}); | ||
} | ||
static getParamNames(func: Function | string): string[] { | ||
@@ -98,0 +129,0 @@ const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; |
{ | ||
"name": "mikro-orm", | ||
"version": "0.6.2", | ||
"version": "0.6.3", | ||
"description": "Simple typescript mongo ORM for node.js based on data-mapper, unit-of-work and identity-map patterns", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -61,2 +61,3 @@ import { ObjectID } from 'bson'; | ||
const authors = await authorRepository.findAll(['books', 'favouriteBook']); | ||
expect(await authorRepository.findOne({ email: 'not existing' })).toBeNull(); | ||
@@ -70,2 +71,4 @@ // count test | ||
expect(jon).toBe(authors[0]); | ||
expect(jon).toBe(await authorRepository.findOne(jon.id)); | ||
expect(jon).toBe(await authorRepository.findOne(jon._id)); | ||
@@ -113,3 +116,3 @@ // serialization test | ||
const booksByTitleDesc = await booksRepository.find({ author: jon._id }, [], { title: -1 }); | ||
const booksByTitleDesc = await booksRepository.find({ author: jon.id }, [], { title: -1 }); | ||
expect(booksByTitleDesc[0].title).toBe('My Life on The Wall, part 3'); | ||
@@ -124,3 +127,3 @@ expect(booksByTitleDesc[1].title).toBe('My Life on The Wall, part 2'); | ||
const lastBook = await booksRepository.find({ author: jon._id }, ['author'], { title: -1 }, 2, 2); | ||
const lastBook = await booksRepository.find({ author: jon.id }, ['author'], { title: -1 }, 2, 2); | ||
expect(lastBook.length).toBe(1); | ||
@@ -130,2 +133,3 @@ expect(lastBook[0].title).toBe('My Life on The Wall, part 1'); | ||
expect(lastBook[0].author.isInitialized()).toBe(true); | ||
await orm.em.getRepository<Book>(Book.name).remove(lastBook[0]); | ||
}); | ||
@@ -140,2 +144,25 @@ | ||
test('should throw when trying to merge entity without id', async () => { | ||
const author = new Author('test', 'test'); | ||
expect(() => orm.em.merge(Author.name, author)).toThrowError('You cannot merge entity without id!'); | ||
}); | ||
test('findOne should initialize entity that is already in IM', async () => { | ||
const god = new Author('God', 'hello@heaven.god'); | ||
const bible = new Book('Bible', god); | ||
await orm.em.persist(bible); | ||
orm.em.clear(); | ||
const ref = orm.em.getReference(Author.name, god.id); | ||
expect(ref.isInitialized()).toBe(false); | ||
const newGod = await orm.em.findOne(Author.name, god.id); | ||
expect(ref).toBe(newGod); | ||
expect(ref.isInitialized()).toBe(true); | ||
}); | ||
test('should return mongo collection', async () => { | ||
expect(orm.em.getCollection(Author.name).collectionName).toBe('author'); | ||
expect(orm.em.getCollection(Book.name).collectionName).toBe('books-table'); | ||
}); | ||
test('findOne by id', async () => { | ||
@@ -155,2 +182,12 @@ const authorRepository = orm.em.getRepository<Author>(Author.name); | ||
expect(author.name).toBe('Jon Snow'); | ||
orm.em.clear(); | ||
author = await authorRepository.findOne({ id: jon.id }); | ||
expect(author).not.toBeNull(); | ||
expect(author.name).toBe('Jon Snow'); | ||
orm.em.clear(); | ||
author = await authorRepository.findOne({ _id: jon._id }); | ||
expect(author).not.toBeNull(); | ||
expect(author.name).toBe('Jon Snow'); | ||
}); | ||
@@ -219,3 +256,3 @@ | ||
orm.em.clear(); | ||
tags = await tagRepository.findAll(); | ||
tags = await orm.em.find<BookTag>(BookTag.name); | ||
expect(tags[0].books.isInitialized()).toBe(false); | ||
@@ -222,0 +259,0 @@ expect(tags[0].books.isDirty()).toBe(false); |
import { MikroORM, Options, EntityManager } from '../lib'; | ||
/** | ||
* @class MikroORMTest | ||
*/ | ||
describe('MikroORM', () => { | ||
test('should throw when no db name provided', async () => { | ||
await expect(MikroORM.init({ entitiesDirs: ['entities'] } as Options)).rejects.toEqual(new Error('No database specified, please fill in `dbName` option')); | ||
test('should throw when not enough options provided', async () => { | ||
await expect(() => new MikroORM({ entitiesDirs: ['entities'] } as Options)).toThrowError('No database specified, please fill in `dbName` option'); | ||
await expect(() => new MikroORM({ dbName: 'test' } as Options)).toThrowError('No directories for entity discovery specified, please fill in `entitiesDirs` option'); | ||
await expect(() => new MikroORM({ dbName: 'test', entitiesDirs: ['entities'], clientUrl: 'test' } as Options)).not.toThrowError(); | ||
}); | ||
@@ -14,2 +19,3 @@ | ||
baseDir: __dirname, | ||
logger: (): void => null, | ||
}); | ||
@@ -16,0 +22,0 @@ |
@@ -83,2 +83,3 @@ import { Utils } from'../lib/Utils'; | ||
expect(Utils.diff({a: 'a', b: ['c']}, {a: 'b'})).toEqual({a: 'b'}); | ||
expect(Utils.diff({_id: 'a', createdAt: 1, updatedAt: 1}, {_id: 'b', createdAt: 2, updatedAt: 2})).toEqual({}); // ignored fields | ||
}); | ||
@@ -94,2 +95,12 @@ | ||
test('prepareEntity changes entity to string id', async () => { | ||
const author1 = new Author('Name 1', 'e-mail'); | ||
const book = new Book('test', author1); | ||
const author2 = new Author('Name 2', 'e-mail'); | ||
author2.favouriteBook = book; | ||
author2.version = 123; | ||
await orm.em.persist([author1, author2, book]); | ||
expect(Utils.diffEntities(author1, author2)).toEqual({ name: 'Name 2', favouriteBook: book.id }); | ||
}); | ||
/** | ||
@@ -101,2 +112,3 @@ * regression test for running code coverage with nyc, mocha and ts-node and entity has default constructor value as enum parameter | ||
expect(Utils.getParamNames(func)).toEqual([ 'email', 'organization', 'role' ]); | ||
expect(Utils.getParamNames('')).toEqual([]); | ||
}); | ||
@@ -103,0 +115,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
134532
70
3292