Skip to content

Commit

Permalink
feat(core): make em.insert/Many strictly typed (require all propert…
Browse files Browse the repository at this point in the history
…ies)
  • Loading branch information
B4nan committed Nov 5, 2023
1 parent c3d7717 commit 01935e6
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 14 deletions.
10 changes: 5 additions & 5 deletions packages/core/src/EntityManager.ts
Expand Up @@ -1188,7 +1188,7 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
/**
* Fires native insert query. Calling this has no side effects on the context (identity map).
*/
async insert<Entity extends object>(entityNameOrEntity: EntityName<Entity> | Entity, data?: EntityData<Entity> | Entity, options: NativeInsertUpdateOptions<Entity> = {}): Promise<Primary<Entity>> {
async insert<Entity extends object>(entityNameOrEntity: EntityName<Entity> | Entity, data?: RequiredEntityData<Entity> | Entity, options: NativeInsertUpdateOptions<Entity> = {}): Promise<Primary<Entity>> {
const em = this.getContext(false);
options.schema ??= em._schema;

Expand Down Expand Up @@ -1217,17 +1217,17 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
return cs.getPrimaryKey()!;
}

data = QueryHelper.processObjectParams(data) as EntityData<Entity>;
data = QueryHelper.processObjectParams(data);
em.validator.validateParams(data, 'insert data');
const res = await em.driver.nativeInsert(entityName, data, { ctx: em.transactionContext, ...options });
const res = await em.driver.nativeInsert<Entity>(entityName, data, { ctx: em.transactionContext, ...options });

return res.insertId!;
}

/**
* Fires native multi-insert query. Calling this has no side effects on the context (identity map).
*/
async insertMany<Entity extends object>(entityNameOrEntities: EntityName<Entity> | Entity[], data?: EntityData<Entity>[] | Entity[], options: NativeInsertUpdateOptions<Entity> = {}): Promise<Primary<Entity>[]> {
async insertMany<Entity extends object>(entityNameOrEntities: EntityName<Entity> | Entity[], data?: RequiredEntityData<Entity>[] | Entity[], options: NativeInsertUpdateOptions<Entity> = {}): Promise<Primary<Entity>[]> {
const em = this.getContext(false);
options.schema ??= em._schema;

Expand Down Expand Up @@ -1264,7 +1264,7 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {

data = data.map(row => QueryHelper.processObjectParams(row));
data.forEach(row => em.validator.validateParams(row, 'insert data'));
const res = await em.driver.nativeInsertMany(entityName, data, { ctx: em.transactionContext, ...options });
const res = await em.driver.nativeInsertMany<Entity>(entityName, data, { ctx: em.transactionContext, ...options });

return res.insertedIds!;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/entity/EntityRepository.ts
Expand Up @@ -144,14 +144,14 @@ export class EntityRepository<Entity extends object> {
/**
* @inheritDoc EntityManager.insert
*/
async insert(data: Entity | EntityData<Entity>, options?: NativeInsertUpdateOptions<Entity>): Promise<Primary<Entity>> {
async insert(data: Entity | RequiredEntityData<Entity>, options?: NativeInsertUpdateOptions<Entity>): Promise<Primary<Entity>> {
return this.getEntityManager().insert<Entity>(this.entityName, data, options);
}

/**
* @inheritDoc EntityManager.insert
*/
async insertMany(data: Entity[] | EntityData<Entity>[], options?: NativeInsertUpdateOptions<Entity>): Promise<Primary<Entity>[]> {
async insertMany(data: Entity[] | RequiredEntityData<Entity>[], options?: NativeInsertUpdateOptions<Entity>): Promise<Primary<Entity>[]> {
return this.getEntityManager().insertMany<Entity>(this.entityName, data, options);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/utils/QueryHelper.ts
Expand Up @@ -48,8 +48,8 @@ export class QueryHelper {
return params;
}

static processObjectParams(params: Dictionary = {}): any {
Object.keys(params).forEach(k => {
static processObjectParams<T extends object>(params: T = {} as T): T {
Utils.keys(params).forEach(k => {
params[k] = QueryHelper.processParams(params[k]);
});

Expand Down
8 changes: 4 additions & 4 deletions tests/EntityManager.mongo.test.ts
Expand Up @@ -1502,7 +1502,7 @@ describe('EntityManagerMongo', () => {
const mock = mockLogger(orm);


const res1 = await orm.em.insert(Author, { name: 'native name 1' });
const res1 = await orm.em.insert(Author, { name: 'native name 1', email: 'e1' });
expect(res1).toBeInstanceOf(ObjectId);

const res2 = await orm.em.nativeUpdate(Author, { name: 'native name 1' }, { name: 'new native name' });
Expand All @@ -1515,7 +1515,7 @@ describe('EntityManagerMongo', () => {
const res4 = await orm.em.nativeDelete(Author, { name: 'new native name' });
expect(res4).toBe(1);

const res5 = await orm.em.insert(Author, { createdAt: new Date('1989-11-17'), updatedAt: new Date('2018-10-28'), name: 'native name 2' });
const res5 = await orm.em.insert(Author, { createdAt: new Date('1989-11-17'), updatedAt: new Date('2018-10-28'), name: 'native name 2', email: 'e2' });
expect(res5).toBeInstanceOf(ObjectId);

const res6 = await orm.em.nativeUpdate(Author, { name: 'native name 2' }, { name: 'new native name', updatedAt: new Date('2018-10-28') });
Expand All @@ -1531,11 +1531,11 @@ describe('EntityManagerMongo', () => {
expect(res9).toBe(1);

expect(mock.mock.calls.length).toBe(9);
expect(mock.mock.calls[0][0]).toMatch(/db\.getCollection\('author'\)\.insertOne\({ name: 'native name 1' }, {}\);/);
expect(mock.mock.calls[0][0]).toMatch(/db\.getCollection\('author'\)\.insertOne\({ name: 'native name 1', email: 'e1' }, {}\);/);
expect(mock.mock.calls[1][0]).toMatch(/db\.getCollection\('author'\)\.updateMany\({ name: 'native name 1' }, { '\$set': { name: 'new native name' } }, {}\);/);
expect(mock.mock.calls[2][0]).toMatch(/db\.getCollection\('author'\)\.aggregate\(\[ { '\$match': { name: 'new native name' } } ], {}\)\.toArray\(\);/);
expect(mock.mock.calls[3][0]).toMatch(/db\.getCollection\('author'\)\.deleteMany\({ name: 'new native name' }, {}\)/);
expect(mock.mock.calls[4][0]).toMatch(/db\.getCollection\('author'\)\.insertOne\({ createdAt: ISODate\('.*'\), updatedAt: ISODate\('.*'\), name: 'native name 2' }, {}\);/);
expect(mock.mock.calls[4][0]).toMatch(/db\.getCollection\('author'\)\.insertOne\({ createdAt: ISODate\('.*'\), updatedAt: ISODate\('.*'\), name: 'native name 2', email: 'e2' }, {}\);/);
expect(mock.mock.calls[5][0]).toMatch(/db\.getCollection\('author'\)\.updateMany\({ name: 'native name 2' }, { '\$set': { name: 'new native name', updatedAt: ISODate\('.*'\) } }, {}\);/);
expect(mock.mock.calls[6][0]).toMatch(/db\.getCollection\('test'\)\.insertOne\({ name: 'native name 1', test: 'abc' }, {}\);/);
expect(mock.mock.calls[7][0]).toMatch(/db\.getCollection\('test'\)\.updateMany\({ name: 'native name 1' }, { '\$unset': { test: 1 } }, {}\);/);
Expand Down
3 changes: 2 additions & 1 deletion tests/entities/FooBar.ts
Expand Up @@ -8,7 +8,7 @@ import {
OneToOne,
PrimaryKey,
Property,
SerializedPrimaryKey,
SerializedPrimaryKey, OptionalProps,
} from '@mikro-orm/core';
import { FooBaz } from './FooBaz';

Expand All @@ -20,6 +20,7 @@ import { FooBaz } from './FooBaz';
export default class FooBar {

[EagerProps]?: 'baz';
[OptionalProps]?: 'meta';

@PrimaryKey()
_id!: ObjectId;
Expand Down

0 comments on commit 01935e6

Please sign in to comment.