@cheetah.js/orm 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/SqlBuilder.d.ts +8 -3
- package/dist/SqlBuilder.js +29 -1
- package/dist/SqlBuilder.js.map +1 -1
- package/dist/bun/index.d.ts +3 -0
- package/dist/bun/index.js +946 -113
- package/dist/bun/index.js.map +28 -14
- package/dist/common/email.vo.d.ts +0 -1
- package/dist/common/email.vo.js +2 -2
- package/dist/common/email.vo.js.map +1 -1
- package/dist/common/uuid.d.ts +4 -0
- package/dist/common/uuid.js +7 -0
- package/dist/common/uuid.js.map +1 -0
- package/dist/common/value-object.d.ts +9 -9
- package/dist/common/value-object.js +1 -2
- package/dist/common/value-object.js.map +1 -1
- package/dist/decorators/property.decorator.d.ts +1 -0
- package/dist/decorators/property.decorator.js.map +1 -1
- package/dist/domain/base-entity.d.ts +4 -3
- package/dist/domain/base-entity.js +0 -6
- package/dist/domain/base-entity.js.map +1 -1
- package/dist/domain/entities.js +3 -1
- package/dist/domain/entities.js.map +1 -1
- package/dist/driver/driver.interface.d.ts +8 -4
- package/dist/driver/pg-driver.js +3 -2
- package/dist/driver/pg-driver.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/migration/diff-calculator.js +38 -9
- package/dist/migration/diff-calculator.js.map +1 -1
- package/dist/utils.js +1 -13
- package/dist/utils.js.map +1 -1
- package/package.json +12 -1
- package/src/SqlBuilder.ts +34 -5
- package/src/common/email.vo.ts +3 -3
- package/src/common/uuid.ts +8 -0
- package/src/common/value-object.ts +11 -12
- package/src/decorators/property.decorator.ts +1 -0
- package/src/domain/base-entity.ts +2 -10
- package/src/domain/entities.ts +3 -1
- package/src/driver/driver.interface.ts +13 -4
- package/src/driver/pg-driver.ts +5 -3
- package/src/index.ts +4 -1
- package/src/migration/diff-calculator.ts +41 -12
- package/src/utils.ts +1 -16
- package/test/domain/base-entity.spec.ts +45 -1
- package/test/migration/{migator.spec.ts → migrator.spec.ts} +45 -0
- package/test/migration/test.sql +1 -5
|
@@ -5,6 +5,16 @@ type VoExtended<T, Vo> = Vo extends ValueObject<T, Vo>
|
|
|
5
5
|
: ValueObject<T, Vo>;
|
|
6
6
|
|
|
7
7
|
export abstract class ValueObject<T, Vo> {
|
|
8
|
+
/**
|
|
9
|
+
* Validates the value of the Value Object.
|
|
10
|
+
* It is abstract so that each Value Object can implement its own validation.
|
|
11
|
+
* It is protected from being called directly.
|
|
12
|
+
*
|
|
13
|
+
* @param value
|
|
14
|
+
* @protected
|
|
15
|
+
*/
|
|
16
|
+
protected abstract validate(value: T): boolean;
|
|
17
|
+
|
|
8
18
|
/**
|
|
9
19
|
* Valor do Value Object.
|
|
10
20
|
* É privado para não ser alterado diretamente.
|
|
@@ -16,8 +26,7 @@ export abstract class ValueObject<T, Vo> {
|
|
|
16
26
|
|
|
17
27
|
constructor(value: T) {
|
|
18
28
|
if (!this.validate(value)) {
|
|
19
|
-
|
|
20
|
-
throw new HttpException(`Invalid value for ${this.name}`, 400);
|
|
29
|
+
throw new HttpException(`Invalid value for ${this.constructor.name}`, 400);
|
|
21
30
|
}
|
|
22
31
|
|
|
23
32
|
this.setValue(value);
|
|
@@ -55,16 +64,6 @@ export abstract class ValueObject<T, Vo> {
|
|
|
55
64
|
return this.getValue() === vo.getValue();
|
|
56
65
|
}
|
|
57
66
|
|
|
58
|
-
/**
|
|
59
|
-
* Validates the value of the Value Object.
|
|
60
|
-
* It is abstract so that each Value Object can implement its own validation.
|
|
61
|
-
* It is protected from being called directly.
|
|
62
|
-
*
|
|
63
|
-
* @param value
|
|
64
|
-
* @protected
|
|
65
|
-
*/
|
|
66
|
-
protected abstract validate(value: T): boolean;
|
|
67
|
-
|
|
68
67
|
/**
|
|
69
68
|
* Sets the value of the Value Object.
|
|
70
69
|
*
|
|
@@ -8,6 +8,7 @@ export type PropertyOptions = {
|
|
|
8
8
|
default?: any;
|
|
9
9
|
length?: number;
|
|
10
10
|
unique?: boolean;
|
|
11
|
+
dbType?: 'varchar' | 'text' | 'int' | 'bigint' | 'float' | 'double' | 'decimal' | 'date' | 'datetime' | 'time' | 'timestamp' | 'boolean' | 'json' | 'jsonb' | 'enum' | 'array' | 'uuid';
|
|
11
12
|
autoIncrement?: boolean;
|
|
12
13
|
onUpdate?: () => any;
|
|
13
14
|
onInsert?: () => any;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SqlBuilder } from '../SqlBuilder';
|
|
2
|
-
import { FilterQuery, FindOneOption, FindOptions, InstanceOf } from '../driver/driver.interface';
|
|
2
|
+
import { FilterQuery, FindOneOption, FindOptions, InstanceOf, ValueOrInstance } from '../driver/driver.interface';
|
|
3
3
|
|
|
4
4
|
export abstract class BaseEntity {
|
|
5
5
|
private _oldValues: any = {};
|
|
@@ -112,21 +112,13 @@ export abstract class BaseEntity {
|
|
|
112
112
|
|
|
113
113
|
static async create<T extends BaseEntity>(
|
|
114
114
|
this: { new(): T } & typeof BaseEntity,
|
|
115
|
-
where: Partial<
|
|
115
|
+
where: Partial<{ [K in keyof T]: ValueOrInstance<T[K]> }>,
|
|
116
116
|
): Promise<T> {
|
|
117
117
|
return this.createQueryBuilder<T>()
|
|
118
118
|
.insert(where)
|
|
119
119
|
.executeAndReturnFirstOrFail();
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
static getTableName(): string {
|
|
123
|
-
if ('tableName' in this) {
|
|
124
|
-
return (this as any).tableName;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return this.name.toLowerCase();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
122
|
public async save() {
|
|
131
123
|
const qb = this.createQueryBuilder()
|
|
132
124
|
|
package/src/domain/entities.ts
CHANGED
|
@@ -72,9 +72,10 @@ export class EntityStorage {
|
|
|
72
72
|
let properties: ColumnsInfo[] = Object.entries(values.showProperties).map(([key, value]) => {
|
|
73
73
|
return {
|
|
74
74
|
name: key,
|
|
75
|
-
type: value.type.name,
|
|
75
|
+
type: value.options.dbType ?? value.type.name,
|
|
76
76
|
nullable: value.options?.nullable,
|
|
77
77
|
default: value.options?.default,
|
|
78
|
+
autoIncrement: value.options?.autoIncrement,
|
|
78
79
|
primary: value.options?.isPrimary,
|
|
79
80
|
unique: value.options?.unique,
|
|
80
81
|
length: value.options?.length,
|
|
@@ -91,6 +92,7 @@ export class EntityStorage {
|
|
|
91
92
|
unique: relation.unique,
|
|
92
93
|
length: relation.length || getDefaultLength(type),
|
|
93
94
|
default: relation.default,
|
|
95
|
+
autoIncrement: relation.autoIncrement,
|
|
94
96
|
primary: relation.isPrimary,
|
|
95
97
|
foreignKeys: [
|
|
96
98
|
{
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PropertyOptions } from '../decorators/property.decorator';
|
|
2
2
|
import { Collection } from '../domain/collection';
|
|
3
3
|
import { Reference } from '../domain/reference';
|
|
4
|
+
import { ValueObject } from '../common/value-object';
|
|
4
5
|
|
|
5
6
|
export interface DriverInterface {
|
|
6
7
|
connectionString: string;
|
|
@@ -37,6 +38,9 @@ export interface DriverInterface {
|
|
|
37
38
|
rollbackTransaction(): Promise<void>;
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
export type ValueOrInstance<T> = T extends ValueObject<any, any> ? T | T['value'] : NonNullable<T>;
|
|
43
|
+
|
|
40
44
|
export type SnapshotConstraintInfo = {
|
|
41
45
|
indexName: string;
|
|
42
46
|
consDef: string;
|
|
@@ -158,6 +162,7 @@ export type ColumnsInfo = {
|
|
|
158
162
|
default?: string | null;
|
|
159
163
|
primary?: boolean;
|
|
160
164
|
unique?: boolean;
|
|
165
|
+
autoIncrement?: boolean;
|
|
161
166
|
length?: number;
|
|
162
167
|
foreignKeys?: ForeignKeyInfo[];
|
|
163
168
|
}
|
|
@@ -175,6 +180,7 @@ export type ColDiff = {
|
|
|
175
180
|
primary?: boolean;
|
|
176
181
|
unique?: boolean;
|
|
177
182
|
nullable?: boolean;
|
|
183
|
+
autoIncrement?: boolean;
|
|
178
184
|
foreignKeys?: ForeignKeyInfo[];
|
|
179
185
|
};
|
|
180
186
|
}
|
|
@@ -226,17 +232,19 @@ export type OperatorMap<T> = {
|
|
|
226
232
|
$like?: string;
|
|
227
233
|
|
|
228
234
|
};
|
|
229
|
-
export type ExcludeFunctions<T, K extends keyof T> = T[K] extends Function ?
|
|
235
|
+
export type ExcludeFunctions<T, K extends keyof T> = T[K] extends Function ? ValueOrInstance<T> : (K extends symbol ? never : K);
|
|
230
236
|
export type Scalar = boolean | number | string | bigint | symbol | Date | RegExp | Uint8Array | {
|
|
231
237
|
toHexString(): string;
|
|
232
238
|
};
|
|
233
239
|
//TODO: editar
|
|
234
|
-
export type ExpandProperty<T> = T extends (infer U)[] ?
|
|
235
|
-
export type ExpandScalar<T> = null | (T extends string ? T | RegExp : T extends Date ? Date | string : T);
|
|
240
|
+
export type ExpandProperty<T> = T extends (infer U)[] ? ValueOrInstance<U> : ValueOrInstance<T> ;
|
|
241
|
+
export type ExpandScalar<T> = null | ValueOrInstance<T> | (T extends string ? T | RegExp : T extends Date ? Date | string : T);
|
|
236
242
|
type ExpandObject<T> = T extends object ? T extends Scalar ? never : {
|
|
243
|
+
// @ts-ignore
|
|
237
244
|
-readonly [K in keyof T as ExcludeFunctions<T, K>]?: Query<ExpandProperty<T[K]>> | FilterValue<ExpandProperty<T[K]>> | null;
|
|
238
245
|
} : never;
|
|
239
246
|
export type EntityProps<T> = {
|
|
247
|
+
// @ts-ignore
|
|
240
248
|
-readonly [K in keyof T as ExcludeFunctions<T, K>]?: T[K];
|
|
241
249
|
};
|
|
242
250
|
export type Query<T> = T extends object ? T extends Scalar ? never : FilterQuery<T> : FilterValue<T>;
|
|
@@ -245,7 +253,7 @@ export type FilterValue<T> = OperatorMap<FilterValue2<T>> | FilterValue2<T> | Fi
|
|
|
245
253
|
export type EntityClass<T> = Function & { prototype: T };
|
|
246
254
|
export type EntityName<T> = string | EntityClass<T> | { name: string };
|
|
247
255
|
export type ObjectQuery<T> = ExpandObject<T> & OperatorMap<T>;
|
|
248
|
-
export type FilterQuery<T> = ObjectQuery<T> | NonNullable<ExpandScalar<Primary<T>>> | NonNullable<EntityProps<T> & OperatorMap<T>> | FilterQuery<T>[];
|
|
256
|
+
export type FilterQuery<T> = ValueOrInstance<T> | ObjectQuery<T> | NonNullable<ExpandScalar<Primary<T>>> | NonNullable<EntityProps<T> & OperatorMap<T>> | FilterQuery<T>[];
|
|
249
257
|
|
|
250
258
|
export type Relationship<T> = {
|
|
251
259
|
isRelation?: boolean;
|
|
@@ -315,6 +323,7 @@ export declare enum QueryOrderNumeric {
|
|
|
315
323
|
export type QueryOrderKeysFlat = QueryOrder | QueryOrderNumeric | keyof typeof QueryOrder;
|
|
316
324
|
export type QueryOrderKeys<T> = QueryOrderKeysFlat | QueryOrderMap<T>;
|
|
317
325
|
export type QueryOrderMap<T> = {
|
|
326
|
+
// @ts-ignore
|
|
318
327
|
[K in keyof T as ExcludeFunctions<T, K>]?: QueryOrderKeys<ExpandProperty<T[K]>>;
|
|
319
328
|
};
|
|
320
329
|
export type EntityField<T, P extends string = never> = AutoPath<T, P, '*'>;
|
package/src/driver/pg-driver.ts
CHANGED
|
@@ -29,9 +29,11 @@ export class PgDriver implements DriverInterface {
|
|
|
29
29
|
|
|
30
30
|
getCreateTableInstruction(schema: string | undefined, tableName: string, creates: ColDiff[]) {
|
|
31
31
|
return `CREATE TABLE "${schema}"."${tableName}" (${creates.map(colDiff => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const isAutoIncrement = colDiff.colChanges?.autoIncrement;
|
|
33
|
+
|
|
34
|
+
let sql = `"${colDiff.colName}" ${isAutoIncrement ? 'SERIAL' : colDiff.colType + (colDiff.colLength ? `(${colDiff.colLength})` : '')}`;
|
|
35
|
+
|
|
36
|
+
if (!isAutoIncrement && !colDiff.colChanges?.nullable) {
|
|
35
37
|
sql += ' NOT NULL';
|
|
36
38
|
}
|
|
37
39
|
|
package/src/index.ts
CHANGED
|
@@ -9,4 +9,7 @@ export * from './domain/base-entity'
|
|
|
9
9
|
export * from './driver/pg-driver'
|
|
10
10
|
export * from './utils'
|
|
11
11
|
export * from './driver/driver.interface'
|
|
12
|
-
export * from './entry'
|
|
12
|
+
export * from './entry'
|
|
13
|
+
export * from './common/value-object'
|
|
14
|
+
export * from './common/email.vo'
|
|
15
|
+
export * from './common/uuid'
|
|
@@ -77,11 +77,14 @@ export class DiffCalculator {
|
|
|
77
77
|
|
|
78
78
|
private checkIndexes(bdTable: SnapshotTable | undefined, entityTable: SnapshotTable | undefined, colDiffs: ColDiff[]) {
|
|
79
79
|
if ((bdTable && bdTable.indexes) || (entityTable && entityTable.indexes)) {
|
|
80
|
-
if (!bdTable || !bdTable.indexes){
|
|
80
|
+
if (!bdTable || !bdTable.indexes) {
|
|
81
81
|
colDiffs.push({
|
|
82
82
|
actionType: 'INDEX',
|
|
83
83
|
colName: '*',
|
|
84
|
-
indexTables: entityTable!.indexes.map(index => ({
|
|
84
|
+
indexTables: entityTable!.indexes.map(index => ({
|
|
85
|
+
name: index.indexName,
|
|
86
|
+
properties: index.columnName.split(','),
|
|
87
|
+
})),
|
|
85
88
|
});
|
|
86
89
|
}
|
|
87
90
|
|
|
@@ -89,7 +92,7 @@ export class DiffCalculator {
|
|
|
89
92
|
colDiffs.push({
|
|
90
93
|
actionType: 'INDEX',
|
|
91
94
|
colName: '*',
|
|
92
|
-
indexTables: bdTable!.indexes.map(index => ({
|
|
95
|
+
indexTables: bdTable!.indexes.map(index => ({name: index.indexName})),
|
|
93
96
|
});
|
|
94
97
|
}
|
|
95
98
|
}
|
|
@@ -119,13 +122,15 @@ export class DiffCalculator {
|
|
|
119
122
|
}
|
|
120
123
|
|
|
121
124
|
private createNewColumn(entityCol: ColumnsInfo, colDiffs: ColDiff[]): ColDiff[] {
|
|
125
|
+
const colType = this.convertEntityTypeToSqlType(entityCol.type);
|
|
122
126
|
|
|
123
127
|
colDiffs.push({
|
|
124
128
|
actionType: 'CREATE',
|
|
125
129
|
colName: entityCol.name,
|
|
126
|
-
colType:
|
|
127
|
-
colLength: entityCol.length,
|
|
130
|
+
colType: colType.type,
|
|
131
|
+
colLength: entityCol.length ?? colType.len,
|
|
128
132
|
colChanges: {
|
|
133
|
+
autoIncrement: entityCol.autoIncrement,
|
|
129
134
|
default: entityCol.default,
|
|
130
135
|
primary: entityCol.primary,
|
|
131
136
|
unique: entityCol.unique,
|
|
@@ -138,12 +143,15 @@ export class DiffCalculator {
|
|
|
138
143
|
}
|
|
139
144
|
|
|
140
145
|
private diffColumnType(bdCol: ColumnsInfo, entityCol: ColumnsInfo, colDiffs: ColDiff[]): void {
|
|
141
|
-
|
|
146
|
+
const colT = this.convertEntityTypeToSqlType(entityCol.type);
|
|
147
|
+
const colType = colT.type;
|
|
148
|
+
const length = entityCol.length ?? colT.len;
|
|
149
|
+
if (bdCol.type !== colType || bdCol.length !== length) {
|
|
142
150
|
colDiffs.push({
|
|
143
151
|
actionType: 'ALTER',
|
|
144
152
|
colName: entityCol.name,
|
|
145
|
-
colType:
|
|
146
|
-
colLength:
|
|
153
|
+
colType: colType,
|
|
154
|
+
colLength: length,
|
|
147
155
|
});
|
|
148
156
|
}
|
|
149
157
|
}
|
|
@@ -244,14 +252,35 @@ export class DiffCalculator {
|
|
|
244
252
|
}
|
|
245
253
|
|
|
246
254
|
// TODO: Precisa ser de acordo com o driver
|
|
247
|
-
|
|
255
|
+
// adicionar 'varchar' | 'text' | 'int' | 'bigint' | 'float' | 'double' | 'decimal' | 'date' | 'datetime' | 'time' | 'timestamp' | 'boolean' | 'json' | 'jsonb' | 'enum' | 'array' | 'uuid'
|
|
256
|
+
private convertEntityTypeToSqlType(entityType: string): { type: string, len?: number } {
|
|
248
257
|
switch (entityType) {
|
|
249
258
|
case "Number":
|
|
250
|
-
|
|
259
|
+
case 'int':
|
|
260
|
+
return {type: 'numeric', len: 11};
|
|
261
|
+
case 'bigint':
|
|
262
|
+
return {type: 'bigint'};
|
|
263
|
+
case 'float':
|
|
264
|
+
return {type: 'float4'};
|
|
265
|
+
case 'double':
|
|
266
|
+
return {type: 'float8'};
|
|
267
|
+
case 'decimal':
|
|
268
|
+
return {type: 'decimal'};
|
|
251
269
|
case "String":
|
|
252
|
-
|
|
270
|
+
case "varchar":
|
|
271
|
+
return {type: 'character varying', len: 255};
|
|
272
|
+
case "Boolean":
|
|
273
|
+
return {type: "boolean"};
|
|
274
|
+
case "Date":
|
|
275
|
+
return {type: "timestamp"};
|
|
276
|
+
case "Object":
|
|
277
|
+
return {type: "json"};
|
|
278
|
+
case 'uuid':
|
|
279
|
+
return {type: 'uuid'};
|
|
280
|
+
case 'text':
|
|
281
|
+
return {type: 'text'};
|
|
253
282
|
default:
|
|
254
|
-
return "character varying"
|
|
283
|
+
return {type: "character varying", len: 255};
|
|
255
284
|
//... mais casos aqui ...
|
|
256
285
|
}
|
|
257
286
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
1
|
export function getDefaultLength(type: string): number {
|
|
2
|
-
|
|
3
|
-
return 255;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
if (type === 'Number') {
|
|
7
|
-
return 11;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
if (type === 'Boolean') {
|
|
11
|
-
return 1;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (type === 'Date') {
|
|
15
|
-
return 6;
|
|
16
|
-
}
|
|
17
|
-
return 255;
|
|
2
|
+
return null;
|
|
18
3
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, jest,
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, jest, setSystemTime, test } from 'bun:test'
|
|
2
2
|
import { app, execute, mockLogger, purgeDatabase, startDatabase } from '../node-database';
|
|
3
3
|
import { BaseEntity, Entity, OneToMany, PrimaryKey, Property } from '../../src';
|
|
4
|
+
import { Email } from '../../src/common/email.vo';
|
|
4
5
|
|
|
5
6
|
@Entity()
|
|
6
7
|
class UserTest extends BaseEntity {
|
|
@@ -14,6 +15,15 @@ class UserTest extends BaseEntity {
|
|
|
14
15
|
updatedAt: Date;
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
@Entity()
|
|
19
|
+
class UserValue extends BaseEntity {
|
|
20
|
+
@PrimaryKey()
|
|
21
|
+
id: number;
|
|
22
|
+
|
|
23
|
+
@Property()
|
|
24
|
+
email: Email
|
|
25
|
+
}
|
|
26
|
+
|
|
17
27
|
describe('Creation, update and deletion of entities', () => {
|
|
18
28
|
|
|
19
29
|
const DLL = `
|
|
@@ -454,6 +464,40 @@ describe('Creation, update and deletion of entities', () => {
|
|
|
454
464
|
expect(created!.updatedAt).toEqual(dateNow);
|
|
455
465
|
})
|
|
456
466
|
|
|
467
|
+
test('When have a column with value-object', async() => {
|
|
468
|
+
const DLL = `
|
|
469
|
+
CREATE TABLE "uservalue"
|
|
470
|
+
(
|
|
471
|
+
"id" SERIAL PRIMARY KEY,
|
|
472
|
+
"email" varchar(255) NOT NULL
|
|
473
|
+
);
|
|
474
|
+
`;
|
|
475
|
+
|
|
476
|
+
await purgeDatabase()
|
|
477
|
+
await startDatabase(import.meta.path)
|
|
478
|
+
await execute(DLL)
|
|
479
|
+
|
|
480
|
+
Entity()(UserValue)
|
|
481
|
+
const created = await UserValue.create({
|
|
482
|
+
id: 1,
|
|
483
|
+
email: Email.from('test@test.com')
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
const find = await UserValue.findOne({
|
|
487
|
+
email: Email.from('test@test.com'),
|
|
488
|
+
id: 1
|
|
489
|
+
})
|
|
490
|
+
|
|
491
|
+
expect(created).toBeInstanceOf(UserValue);
|
|
492
|
+
expect(created!.id).toEqual(1);
|
|
493
|
+
expect(created!.email).toEqual(Email.from('test@test.com'));
|
|
494
|
+
|
|
495
|
+
expect(find).toBeInstanceOf(UserValue);
|
|
496
|
+
expect(find!.id).toEqual(1);
|
|
497
|
+
expect(find!.email).toEqual(Email.from('test@test.com'));
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
|
|
457
501
|
async function createUser() {
|
|
458
502
|
return User.create({
|
|
459
503
|
email: 'test@test.com',
|
|
@@ -9,6 +9,7 @@ import * as fs from 'fs';
|
|
|
9
9
|
import { Metadata } from '@cheetah.js/core';
|
|
10
10
|
import { ENTITIES } from '../../src/constants';
|
|
11
11
|
import { Index } from '../../src/decorators/index.decorator';
|
|
12
|
+
import { Email } from '../../src/common/email.vo';
|
|
12
13
|
|
|
13
14
|
describe('Migration', () => {
|
|
14
15
|
|
|
@@ -248,4 +249,48 @@ describe('Migration', () => {
|
|
|
248
249
|
expect(migrationContent.split('\n').length).toEqual(5)
|
|
249
250
|
await execute(migrationContent);
|
|
250
251
|
});
|
|
252
|
+
|
|
253
|
+
it('should create with value-objects', async () => {
|
|
254
|
+
class User extends BaseEntity {
|
|
255
|
+
@PrimaryKey()
|
|
256
|
+
id: number;
|
|
257
|
+
|
|
258
|
+
@Property({ dbType: 'text' })
|
|
259
|
+
email: Email;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
Entity()(User);
|
|
263
|
+
|
|
264
|
+
const migrator = new Migrator();
|
|
265
|
+
await migrator.initConfigFile();
|
|
266
|
+
await migrator.createMigration( 'test');
|
|
267
|
+
const migrationFilePath = path.join(__dirname, '/test.sql');
|
|
268
|
+
const migrationContent = fs.readFileSync(migrationFilePath, {encoding: 'utf-8'});
|
|
269
|
+
|
|
270
|
+
expect(migrationContent).toContain("CREATE TABLE \"public\".\"user\" (\"id\" numeric(11) NOT NULL PRIMARY KEY UNIQUE,\"email\" text NOT NULL);")
|
|
271
|
+
expect(migrationContent.split('\n').length).toEqual(1)
|
|
272
|
+
await execute(migrationContent);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('should create with auto-increment', async () => {
|
|
276
|
+
class User extends BaseEntity {
|
|
277
|
+
@PrimaryKey({ autoIncrement: true })
|
|
278
|
+
id: number;
|
|
279
|
+
|
|
280
|
+
@Property({ dbType: 'text' })
|
|
281
|
+
email: Email;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
Entity()(User);
|
|
285
|
+
|
|
286
|
+
const migrator = new Migrator();
|
|
287
|
+
await migrator.initConfigFile();
|
|
288
|
+
await migrator.createMigration( 'test');
|
|
289
|
+
const migrationFilePath = path.join(__dirname, '/test.sql');
|
|
290
|
+
const migrationContent = fs.readFileSync(migrationFilePath, {encoding: 'utf-8'});
|
|
291
|
+
|
|
292
|
+
expect(migrationContent).toContain("CREATE TABLE \"public\".\"user\" (\"id\" SERIAL PRIMARY KEY UNIQUE,\"email\" text NOT NULL);")
|
|
293
|
+
expect(migrationContent.split('\n').length).toEqual(1)
|
|
294
|
+
await execute(migrationContent);
|
|
295
|
+
});
|
|
251
296
|
})
|
package/test/migration/test.sql
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
CREATE TABLE "public"."user" ("id"
|
|
2
|
-
CREATE INDEX "id_email_index" ON "public"."user" ("id", "email");
|
|
3
|
-
CREATE INDEX "email_index" ON "public"."user" ("email");
|
|
4
|
-
CREATE TABLE "public"."address" ("id" numeric(11) NOT NULL PRIMARY KEY UNIQUE,"user" numeric(11) NOT NULL);
|
|
5
|
-
ALTER TABLE "public"."address" ADD CONSTRAINT "address_user_fk" FOREIGN KEY ("user") REFERENCES "user" ("id");
|
|
1
|
+
CREATE TABLE "public"."user" ("id" SERIAL PRIMARY KEY UNIQUE,"email" text NOT NULL);
|