@onivoro/server-typeorm-postgres 24.9.0 → 24.11.0
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/package.json +8 -2
- package/jest.config.ts +0 -11
- package/project.json +0 -32
- package/src/index.ts +0 -33
- package/src/lib/classes/__snapshots__/sql-writer.class.spec.ts.snap +0 -8
- package/src/lib/classes/column-migration-base.class.ts +0 -17
- package/src/lib/classes/columns-migration-base.class.ts +0 -17
- package/src/lib/classes/drop-column-migration-base.class.ts +0 -17
- package/src/lib/classes/drop-table-migration-base.class.ts +0 -17
- package/src/lib/classes/index-migration-base.class.ts +0 -17
- package/src/lib/classes/redshift-repository.class.ts +0 -146
- package/src/lib/classes/sql-writer.class.spec.ts +0 -20
- package/src/lib/classes/sql-writer.class.ts +0 -66
- package/src/lib/classes/table-migration-base.class.ts +0 -17
- package/src/lib/classes/type-orm-paging-repository.class.ts +0 -22
- package/src/lib/classes/type-orm-repository.class.ts +0 -299
- package/src/lib/constants/many-to-one-relation-options.constant.ts +0 -3
- package/src/lib/decorators/nullable-table-column.decorator.ts +0 -9
- package/src/lib/decorators/primary-table-column.decorator.ts +0 -9
- package/src/lib/decorators/table-column.decorator.ts +0 -9
- package/src/lib/decorators/table.decorator.ts +0 -8
- package/src/lib/functions/data-source-config-factory.function.ts +0 -34
- package/src/lib/functions/data-source-factory.function.ts +0 -10
- package/src/lib/functions/generate-date-query.function.ts +0 -20
- package/src/lib/functions/get-api-type-from-column.function.ts +0 -14
- package/src/lib/functions/get-paging-key.function.ts +0 -3
- package/src/lib/functions/get-skip.function.ts +0 -3
- package/src/lib/functions/remove-falsey-keys.function.ts +0 -8
- package/src/lib/server-typeorm-postgres.module.ts +0 -44
- package/src/lib/types/data-source-options.interface.ts +0 -11
- package/src/lib/types/entity-provider.interface.ts +0 -9
- package/src/lib/types/page-params.interface.ts +0 -6
- package/src/lib/types/paged-data.interface.ts +0 -6
- package/src/lib/types/table-meta.type.ts +0 -4
- package/tsconfig.json +0 -17
- package/tsconfig.lib.json +0 -10
- package/tsconfig.spec.json +0 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onivoro/server-typeorm-postgres",
|
|
3
|
-
"version": "24.
|
|
3
|
+
"version": "24.11.0",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -18,5 +18,11 @@
|
|
|
18
18
|
"reflect-metadata": "~0.2.2",
|
|
19
19
|
"typeorm": "^0.3.22",
|
|
20
20
|
"typeorm-naming-strategies": "~4.1.0"
|
|
21
|
-
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"**/*.js",
|
|
24
|
+
"**/*.d.ts",
|
|
25
|
+
"**/*.js.map",
|
|
26
|
+
"README.md"
|
|
27
|
+
]
|
|
22
28
|
}
|
package/jest.config.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
export default {
|
|
3
|
-
displayName: 'lib-server-typeorm-postgres',
|
|
4
|
-
preset: '../../../jest.preset.js',
|
|
5
|
-
testEnvironment: 'node',
|
|
6
|
-
transform: {
|
|
7
|
-
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
|
8
|
-
},
|
|
9
|
-
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
10
|
-
coverageDirectory: '../../../coverage/libs/server/typeorm-postgres',
|
|
11
|
-
};
|
package/project.json
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "lib-server-typeorm-postgres",
|
|
3
|
-
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
-
"sourceRoot": "libs/server/typeorm-postgres/src",
|
|
5
|
-
"projectType": "library",
|
|
6
|
-
"targets": {
|
|
7
|
-
"build": {
|
|
8
|
-
"executor": "@nx/js:tsc",
|
|
9
|
-
"outputs": ["{options.outputPath}"],
|
|
10
|
-
"options": {
|
|
11
|
-
"outputPath": "dist/libs/server/typeorm-postgres",
|
|
12
|
-
"main": "libs/server/typeorm-postgres/src/index.ts",
|
|
13
|
-
"tsConfig": "libs/server/typeorm-postgres/tsconfig.lib.json",
|
|
14
|
-
"assets": [
|
|
15
|
-
"libs/server/typeorm-postgres/README.md",
|
|
16
|
-
"libs/server/typeorm-postgres/package.json"
|
|
17
|
-
],
|
|
18
|
-
"declaration": true,
|
|
19
|
-
"updateBuildableProjectPackageJsonDependencies": true,
|
|
20
|
-
"rootDir": "libs/server/typeorm-postgres/src"
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
"publish": {
|
|
24
|
-
"executor": "@nx/js:npm",
|
|
25
|
-
"outputs": [],
|
|
26
|
-
"options": {
|
|
27
|
-
"packageRoot": "dist/libs/server/typeorm-postgres"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"tags": []
|
|
32
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
export * from './lib/classes/column-migration-base.class';
|
|
2
|
-
export * from './lib/classes/columns-migration-base.class';
|
|
3
|
-
export * from './lib/classes/drop-column-migration-base.class';
|
|
4
|
-
export * from './lib/classes/drop-table-migration-base.class';
|
|
5
|
-
export * from './lib/classes/index-migration-base.class';
|
|
6
|
-
export * from './lib/classes/redshift-repository.class';
|
|
7
|
-
export * from './lib/classes/sql-writer.class';
|
|
8
|
-
export * from './lib/classes/table-migration-base.class';
|
|
9
|
-
export * from './lib/classes/type-orm-paging-repository.class';
|
|
10
|
-
export * from './lib/classes/type-orm-repository.class';
|
|
11
|
-
|
|
12
|
-
export * from './lib/constants/many-to-one-relation-options.constant';
|
|
13
|
-
|
|
14
|
-
export * from './lib/decorators/nullable-table-column.decorator';
|
|
15
|
-
export * from './lib/decorators/primary-table-column.decorator';
|
|
16
|
-
export * from './lib/decorators/table-column.decorator';
|
|
17
|
-
export * from './lib/decorators/table.decorator';
|
|
18
|
-
|
|
19
|
-
export * from './lib/functions/data-source-config-factory.function';
|
|
20
|
-
export * from './lib/functions/data-source-factory.function';
|
|
21
|
-
export * from './lib/functions/generate-date-query.function';
|
|
22
|
-
export * from './lib/functions/get-api-type-from-column.function';
|
|
23
|
-
export * from './lib/functions/get-paging-key.function';
|
|
24
|
-
export * from './lib/functions/get-skip.function';
|
|
25
|
-
export * from './lib/functions/remove-falsey-keys.function';
|
|
26
|
-
|
|
27
|
-
export * from './lib/types/data-source-options.interface';
|
|
28
|
-
export * from './lib/types/entity-provider.interface';
|
|
29
|
-
export * from './lib/types/page-params.interface';
|
|
30
|
-
export * from './lib/types/paged-data.interface';
|
|
31
|
-
export * from './lib/types/table-meta.type';
|
|
32
|
-
|
|
33
|
-
export * from './lib/server-typeorm-postgres.module';
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// Bun Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`SqlWriter addColumn worx 1`] = `"ALTER TABLE "blah" ADD "id" character varying PRIMARY KEY "`;
|
|
4
|
-
|
|
5
|
-
exports[`SqlWriter createTable worx 1`] = `
|
|
6
|
-
"CREATE TABLE "blah" ("id" character varying PRIMARY KEY ,
|
|
7
|
-
"active" boolean NOT NULL );"
|
|
8
|
-
`;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { MigrationInterface, QueryRunner, TableColumnOptions } from "typeorm";
|
|
2
|
-
import { SqlWriter } from "./sql-writer.class";
|
|
3
|
-
|
|
4
|
-
export class ColumnMigrationBase implements MigrationInterface {
|
|
5
|
-
constructor(
|
|
6
|
-
public table: string,
|
|
7
|
-
public option: TableColumnOptions,
|
|
8
|
-
) { }
|
|
9
|
-
|
|
10
|
-
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
11
|
-
await queryRunner.query(SqlWriter.addColumn(this.table, this.option));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
15
|
-
await queryRunner.query(SqlWriter.dropColumn(this.table, this.option));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { MigrationInterface, QueryRunner, TableColumnOptions } from "typeorm";
|
|
2
|
-
import { SqlWriter } from "./sql-writer.class";
|
|
3
|
-
|
|
4
|
-
export class ColumnsMigrationBase implements MigrationInterface {
|
|
5
|
-
constructor(
|
|
6
|
-
public table: string,
|
|
7
|
-
public options: TableColumnOptions[],
|
|
8
|
-
) { }
|
|
9
|
-
|
|
10
|
-
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
11
|
-
await queryRunner.query(SqlWriter.addColumns(this.table, this.options));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
15
|
-
await queryRunner.query(SqlWriter.dropColumns(this.table, this.options));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { MigrationInterface, QueryRunner, TableColumnOptions } from "typeorm";
|
|
2
|
-
import { SqlWriter } from "./sql-writer.class";
|
|
3
|
-
|
|
4
|
-
export class DropColumnMigrationBase implements MigrationInterface {
|
|
5
|
-
constructor(
|
|
6
|
-
public table: string,
|
|
7
|
-
public option: TableColumnOptions,
|
|
8
|
-
) { }
|
|
9
|
-
|
|
10
|
-
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
11
|
-
await queryRunner.query(SqlWriter.addColumn(this.table, this.option));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
15
|
-
await queryRunner.query(SqlWriter.dropColumn(this.table, this.option));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { MigrationInterface, QueryRunner, TableColumnOptions } from "typeorm";
|
|
2
|
-
import { SqlWriter } from "./sql-writer.class";
|
|
3
|
-
|
|
4
|
-
export class DropTableMigrationBase implements MigrationInterface {
|
|
5
|
-
constructor(
|
|
6
|
-
public table: string,
|
|
7
|
-
public options: TableColumnOptions[],
|
|
8
|
-
) { }
|
|
9
|
-
|
|
10
|
-
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
11
|
-
await queryRunner.query(SqlWriter.createTable(this.table, this.options));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
15
|
-
await queryRunner.query(SqlWriter.dropTable(this.table));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { MigrationInterface, QueryRunner, TableColumn, TableColumnOptions } from "typeorm";
|
|
2
|
-
import { SqlWriter } from "./sql-writer.class";
|
|
3
|
-
|
|
4
|
-
export class UniqueIndexMigrationBase implements MigrationInterface {
|
|
5
|
-
constructor(
|
|
6
|
-
public table: string,
|
|
7
|
-
public option: TableColumnOptions,
|
|
8
|
-
) { }
|
|
9
|
-
|
|
10
|
-
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
11
|
-
await queryRunner.query(SqlWriter.createUniqueIndex(this.table, this.option.name));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
15
|
-
await queryRunner.query(SqlWriter.dropIndex(SqlWriter.getIndexName(this.table, this.option.name)));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { Injectable, NotImplementedException } from '@nestjs/common';
|
|
2
|
-
import { DataSource, EntityManager, FindManyOptions, FindOneOptions, FindOptionsWhere } from 'typeorm';
|
|
3
|
-
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
|
|
4
|
-
import { TypeOrmRepository } from './type-orm-repository.class';
|
|
5
|
-
import { TTableMeta } from '../types/table-meta.type';
|
|
6
|
-
import { TKeysOf } from '@onivoro/isomorphic-common';
|
|
7
|
-
|
|
8
|
-
@Injectable()
|
|
9
|
-
export class RedshiftRepository<TEntity> extends TypeOrmRepository<TEntity> {
|
|
10
|
-
|
|
11
|
-
constructor(public entityType: any, public entityManager: EntityManager) {
|
|
12
|
-
super(entityType, entityManager);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
override async getMany(options: FindManyOptions<TEntity>): Promise<TEntity[]> {
|
|
16
|
-
const { query, queryParams } = this.buildSelectStatement(options);
|
|
17
|
-
|
|
18
|
-
return await this.queryAndMap(query, queryParams.map(_ => (_ as any).value ? (_ as any).value : _));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
override async getOne(options: FindOneOptions<TEntity>): Promise<TEntity> {
|
|
22
|
-
const results = await this.getMany(options);
|
|
23
|
-
|
|
24
|
-
if (results.length > 1) {
|
|
25
|
-
throw new Error(`RedshiftRepository.getOne expected one result but found ${results.length} results`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return results[0];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
override async delete(where: FindOptionsWhere<TEntity>): Promise<void> {
|
|
32
|
-
const { query, queryParams } = this.buildDeleteStatement(where);
|
|
33
|
-
|
|
34
|
-
await this.query(query, queryParams);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
override async patch(where: FindOptionsWhere<TEntity>, body: QueryDeepPartialEntity<TEntity>): Promise<void> {
|
|
38
|
-
const queryParams: any[] = [];
|
|
39
|
-
let whereClause = '';
|
|
40
|
-
|
|
41
|
-
Object.entries(where).forEach(([propertyPath, value], index) => {
|
|
42
|
-
const key = this.columns[propertyPath as keyof TEntity].databasePath;
|
|
43
|
-
if (index === 0) {
|
|
44
|
-
whereClause += ` WHERE ${key} = ${this.mapPlaceholderExpression(0, index, propertyPath)}`;
|
|
45
|
-
} else {
|
|
46
|
-
whereClause += ` AND ${key} = ${this.mapPlaceholderExpression(0, index, propertyPath)}`;
|
|
47
|
-
}
|
|
48
|
-
queryParams.push(value);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const setParams: any[] = [];
|
|
52
|
-
let setExpressions: string[] = [];
|
|
53
|
-
|
|
54
|
-
const length = queryParams?.length;
|
|
55
|
-
|
|
56
|
-
Object.entries(body).forEach(([key, value], index) => {
|
|
57
|
-
setExpressions.push(`${this.columns[key as keyof TEntity].databasePath} = ${this.mapPlaceholderExpression(length, index, key)}`);
|
|
58
|
-
setParams.push(value);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
let query = `UPDATE ${this.getTableNameExpression()} SET ${setExpressions.join(', ')} ${whereClause}`;
|
|
62
|
-
|
|
63
|
-
await this.query(query, [...queryParams, ...setParams]);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
override async postOne(entity: Partial<TEntity>): Promise<TEntity> {
|
|
67
|
-
await this.postOneWithoutReturn(entity);
|
|
68
|
-
|
|
69
|
-
return await this.getOne({ where: entity as any });
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
override async postMany(entities: Partial<TEntity>[]): Promise<TEntity[]> {
|
|
73
|
-
if (entities?.length) {
|
|
74
|
-
const { insertQuery, values } = this.buildInsertManyQuery(entities);
|
|
75
|
-
|
|
76
|
-
await this.query(insertQuery, values);
|
|
77
|
-
|
|
78
|
-
const { selectQuery, values: selectValues } = this.buildSelectManyQuery(entities);
|
|
79
|
-
|
|
80
|
-
return await this.queryAndMap(selectQuery, selectValues);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return [];
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
override async put(options: FindOptionsWhere<TEntity>, body: QueryDeepPartialEntity<TEntity>): Promise<void> {
|
|
87
|
-
this.throwNotImplemented('put');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
override forTransaction(entityManager: EntityManager): TypeOrmRepository<TEntity> {
|
|
91
|
-
this.throwNotImplemented('forTransaction');
|
|
92
|
-
return this;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
override async getManyAndCount(options: FindManyOptions<TEntity>): Promise<[TEntity[], number]> {
|
|
96
|
-
this.throwNotImplemented('getManyAndCount');
|
|
97
|
-
return [[], 0];
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
override async softDelete(where: FindOptionsWhere<TEntity>): Promise<void> {
|
|
101
|
-
await this.patch(where, { deletedAt: new Date().toISOString() } as any);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async postOneWithoutReturn(entity: Partial<TEntity>): Promise<void> {
|
|
105
|
-
// PERFORM AN INSERT BUT NOT THE RETRIEVAL QUERY FOR PERFORMANCE
|
|
106
|
-
const { insertQuery, values } = this.buildInsertQuery(entity);
|
|
107
|
-
|
|
108
|
-
await this.query(insertQuery, values);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async postManyWithoutReturn(entities: Partial<TEntity>[]): Promise<void> {
|
|
112
|
-
// TODO: PERFORM AN INSERT BUT NOT THE RETRIEVAL QUERY FOR PERFORMANCE
|
|
113
|
-
// TODO: THIS IS ACTUALLY NEEDED TO HELP WITH LARGE DATASETS
|
|
114
|
-
this.throwNotImplemented('postManyWithoutReturn');
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
private throwNotImplemented(feature: string) {
|
|
118
|
-
throw new NotImplementedException(`RedshiftRepository of type "${this.entityType?.name}" has no implementation for "${feature}"`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
protected override mapPlaceholderExpression(length: number, index: number, column: string) {
|
|
122
|
-
const exp = `$${length + index + 1}`;
|
|
123
|
-
const meta: TTableMeta = this.columns[column as keyof TEntity];
|
|
124
|
-
return meta.type === 'jsonb' ? `JSON_PARSE(${exp})` : exp;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
static buildFromMetadata<TGenericEntity>(dataSource: DataSource, _: {schema: string, table: string, columns: TKeysOf<TGenericEntity, TTableMeta>}) {
|
|
128
|
-
|
|
129
|
-
class GenericRepository extends RedshiftRepository<TGenericEntity> {
|
|
130
|
-
constructor() {
|
|
131
|
-
const entityManager = dataSource.createEntityManager();
|
|
132
|
-
super(Object, {
|
|
133
|
-
...entityManager,
|
|
134
|
-
getRepository: () => entityManager as any
|
|
135
|
-
} as any);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const genericRepository = new GenericRepository();
|
|
140
|
-
(genericRepository as any).schema = _.schema;
|
|
141
|
-
(genericRepository as any).table = _.table;
|
|
142
|
-
(genericRepository as any).columns = _.columns;
|
|
143
|
-
|
|
144
|
-
return genericRepository as RedshiftRepository<TGenericEntity>;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { SqlWriter } from './sql-writer.class';
|
|
2
|
-
|
|
3
|
-
describe(SqlWriter.name, () => {
|
|
4
|
-
describe(SqlWriter.addColumn.name, () => {
|
|
5
|
-
it('worx', () => {
|
|
6
|
-
expect(SqlWriter.addColumn('blah', {
|
|
7
|
-
isPrimary: true, name: 'id', type: 'character varying'
|
|
8
|
-
})).toMatchSnapshot();
|
|
9
|
-
});
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
describe(SqlWriter.createTable.name, () => {
|
|
13
|
-
it('worx', () => {
|
|
14
|
-
expect(SqlWriter.createTable('blah', [
|
|
15
|
-
{ isPrimary: true, name: 'id', type: 'character varying' },
|
|
16
|
-
{ isPrimary: false, name: 'active', type: 'boolean' },
|
|
17
|
-
])).toMatchSnapshot();
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
});
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { TableColumnOptions } from "typeorm";
|
|
2
|
-
|
|
3
|
-
export class SqlWriter {
|
|
4
|
-
|
|
5
|
-
public static addColumn(table: string, option: TableColumnOptions) {
|
|
6
|
-
const notNullExpression = option.isPrimary ? ` PRIMARY KEY ` : (option.isNullable ? '' : ' NOT NULL ');
|
|
7
|
-
const foreignKey = option.foreignKeyConstraintName ? ` REFERENCES ${option.foreignKeyConstraintName} ` : '';
|
|
8
|
-
const uniqueExpression = option.isUnique ? ' UNIQUE ' : '';
|
|
9
|
-
return `ALTER TABLE "${table}" ADD "${option.name}" ${option.type}${notNullExpression}${uniqueExpression}${SqlWriter.getDefaultValueExpression(option)}${foreignKey}`;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
public static createTable(table: string, options: TableColumnOptions[]) {
|
|
13
|
-
const cols = options.map(option => SqlWriter.addColumn(table, option).replace(`ALTER TABLE "${table}" ADD `, '')).join(',\n');
|
|
14
|
-
|
|
15
|
-
return `CREATE TABLE "${table}" (${cols});`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
public static dropTable(table: string) {
|
|
19
|
-
return `DROP TABLE "${table}";\n`;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
public static addColumns(table: string, options: TableColumnOptions[]) {
|
|
23
|
-
return options.map(option => SqlWriter.addColumn(table, option)).join('; \n');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public static dropColumn(table: string, option: TableColumnOptions) {
|
|
27
|
-
return `ALTER TABLE "${table}" DROP COLUMN ${option.name}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public static dropColumns(table: string, options: TableColumnOptions[]) {
|
|
31
|
-
return options.map(option => SqlWriter.dropColumn(table, option)).join('; \n');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
public static dropIndex(index: string): string {
|
|
35
|
-
return `DROP INDEX IF EXISTS ${index}`;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
public static createIndex(table: string, column: string, unique: boolean): string {
|
|
39
|
-
const index = SqlWriter.getIndexName(table, column);
|
|
40
|
-
return `CREATE ${unique ? 'UNIQUE' : ''} INDEX IF NOT EXISTS ${index} ON "${table}"(${column})`;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
public static getIndexName(table: string, column: string): string {
|
|
44
|
-
return `${table}_${column}`;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
public static createUniqueIndex(table: string, column: string): string {
|
|
48
|
-
return SqlWriter.createIndex(table, column, true);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
public static getDefaultValueExpression(option: TableColumnOptions) {
|
|
52
|
-
if (typeof option.default === 'undefined') {
|
|
53
|
-
return '';
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (['json', 'jsonb'].includes(option.type)) {
|
|
57
|
-
return ` DEFAULT '${JSON.stringify(option.default)}'::${option.type} `;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (['boolean', 'bigint', 'int'].includes(option.type)) {
|
|
61
|
-
return ` DEFAULT ${option.default.toString().toUpperCase()} `;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return ` DEFAULT '${option.default}' `;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { MigrationInterface, QueryRunner, TableColumnOptions } from "typeorm";
|
|
2
|
-
import { SqlWriter } from "./sql-writer.class";
|
|
3
|
-
|
|
4
|
-
export class TableMigrationBase implements MigrationInterface {
|
|
5
|
-
constructor(
|
|
6
|
-
public table: string,
|
|
7
|
-
public options: TableColumnOptions[],
|
|
8
|
-
) { }
|
|
9
|
-
|
|
10
|
-
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
11
|
-
await queryRunner.query(SqlWriter.createTable(this.table, this.options));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public async down(queryRunner: QueryRunner): Promise<void> {
|
|
15
|
-
await queryRunner.query(SqlWriter.dropTable(this.table));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
EntityManager,
|
|
3
|
-
} from 'typeorm';
|
|
4
|
-
|
|
5
|
-
import { TypeOrmRepository } from './type-orm-repository.class';
|
|
6
|
-
import { IPagedData } from '../types/paged-data.interface';
|
|
7
|
-
import { getSkip } from '../functions/get-skip.function';
|
|
8
|
-
import { removeFalseyKeys } from '../functions/remove-falsey-keys.function';
|
|
9
|
-
import { getPagingKey } from '../functions/get-paging-key.function';
|
|
10
|
-
import { IPageParams } from '../types/page-params.interface';
|
|
11
|
-
|
|
12
|
-
export abstract class TypeOrmPagingRepository<TEntity, TEntityParams> extends TypeOrmRepository<TEntity> {
|
|
13
|
-
protected getPagingKey = getPagingKey;
|
|
14
|
-
protected getSkip = getSkip;
|
|
15
|
-
protected removeFalseyKeys = removeFalseyKeys;
|
|
16
|
-
|
|
17
|
-
constructor(entityType: any, entityManager: EntityManager) {
|
|
18
|
-
super(entityType, entityManager);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
abstract getPage(pageParams: IPageParams, params: TEntityParams): Promise<IPagedData<TEntity>>;
|
|
22
|
-
}
|
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DataSource,
|
|
3
|
-
EntityManager,
|
|
4
|
-
FindManyOptions,
|
|
5
|
-
FindOneOptions,
|
|
6
|
-
FindOptionsWhere,
|
|
7
|
-
ILike,
|
|
8
|
-
} from 'typeorm';
|
|
9
|
-
|
|
10
|
-
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
|
|
11
|
-
import { IEntityProvider } from '../types/entity-provider.interface';
|
|
12
|
-
import { TKeysOf } from '@onivoro/isomorphic-common';
|
|
13
|
-
import { TTableMeta } from '../types/table-meta.type';
|
|
14
|
-
|
|
15
|
-
export class TypeOrmRepository<TEntity> implements IEntityProvider<
|
|
16
|
-
TEntity,
|
|
17
|
-
FindOneOptions<TEntity>,
|
|
18
|
-
FindManyOptions<TEntity>,
|
|
19
|
-
FindOptionsWhere<TEntity>,
|
|
20
|
-
QueryDeepPartialEntity<TEntity>
|
|
21
|
-
> {
|
|
22
|
-
columns: TKeysOf<TEntity, TTableMeta> = {} as any;
|
|
23
|
-
table: string;
|
|
24
|
-
schema: string;
|
|
25
|
-
debug = false;
|
|
26
|
-
|
|
27
|
-
constructor(public entityType: any, public entityManager: EntityManager) {
|
|
28
|
-
|
|
29
|
-
const { tableName, schema } = this.repo.metadata;
|
|
30
|
-
|
|
31
|
-
this.table = tableName;
|
|
32
|
-
this.schema = schema!;
|
|
33
|
-
|
|
34
|
-
this.repo.metadata.columns.forEach((_) => {
|
|
35
|
-
const { databasePath, propertyPath, type, isPrimary } = _;
|
|
36
|
-
this.columns[propertyPath as keyof TEntity] = { databasePath, type, propertyPath, isPrimary, default: _.default };
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
forTransaction(entityManager: EntityManager): TypeOrmRepository<TEntity> {
|
|
41
|
-
return new (this.constructor as typeof TypeOrmRepository<TEntity>)(this.entityType, entityManager);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async getMany(options: FindManyOptions<TEntity>): Promise<TEntity[]> {
|
|
45
|
-
return await (this.repo.find as any)(options);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async getManyAndCount(options: FindManyOptions<TEntity>): Promise<[TEntity[], number]> {
|
|
49
|
-
return await (this.repo.findAndCount as any)(options);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async getOne(options: FindOneOptions<TEntity>): Promise<TEntity> {
|
|
53
|
-
const results = await this.getMany(options);
|
|
54
|
-
|
|
55
|
-
if (results?.length > 1) {
|
|
56
|
-
throw new Error(`${TypeOrmRepository.prototype.getOne.name} expects only 1 result but found ${results.length} results of entity type "${this.entityType}" for criteria ${JSON.stringify(options, null, 2)}`);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return results[0];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async postOne(body: Partial<TEntity>): Promise<TEntity> {
|
|
63
|
-
return await this.insertAndReturn(body as TEntity);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async postMany(body: Partial<TEntity>[]): Promise<TEntity[]> {
|
|
67
|
-
return (await this.insertAndReturnMany(body as TEntity[])) as any;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async delete(options: FindOptionsWhere<TEntity>): Promise<void> {
|
|
71
|
-
return await (this.repo.delete as any)(options);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async softDelete(options: FindOptionsWhere<TEntity>): Promise<void> {
|
|
75
|
-
return await (this.repo.softDelete as any)(options);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async put(options: FindOptionsWhere<TEntity>, body: QueryDeepPartialEntity<TEntity>) {
|
|
79
|
-
await this.repo.save(options, body);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async patch(options: FindOptionsWhere<TEntity>, body: QueryDeepPartialEntity<TEntity>) {
|
|
83
|
-
await this.repo.update(options, body);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
get repo() {
|
|
87
|
-
return this.entityManager.getRepository(this.entityType as any);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
protected async insertAndReturn(entityToInsert: TEntity): Promise<TEntity> {
|
|
91
|
-
return (await this.insertAndReturnMany([entityToInsert]))[0];
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
protected async insertAndReturnMany(entitiesToInsert: TEntity[]): Promise<TEntity[]> {
|
|
95
|
-
const insertionResult = await this.repo
|
|
96
|
-
.createQueryBuilder()
|
|
97
|
-
.insert()
|
|
98
|
-
.values(entitiesToInsert)
|
|
99
|
-
.returning('*')
|
|
100
|
-
.execute();
|
|
101
|
-
|
|
102
|
-
const insertedEntity: TEntity[] =
|
|
103
|
-
insertionResult.generatedMaps as TEntity[];
|
|
104
|
-
|
|
105
|
-
return insertedEntity;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
protected getSchemaPrefix() {
|
|
109
|
-
return this.schema ? `"${this.schema}".` : '';
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
protected getTableNameExpression() {
|
|
113
|
-
const schemaPrefix = this.getSchemaPrefix();
|
|
114
|
-
return `${schemaPrefix}"${this.table}"`;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
protected buildSelectStatement(options: FindManyOptions<TEntity>): { query: string; queryParams: any[]; } {
|
|
118
|
-
const { whereClause, queryParams } = this.buildWhereExpression(options.where as FindOptionsWhere<TEntity>);
|
|
119
|
-
const query = `SELECT * FROM ${this.getTableNameExpression()}${whereClause};`;
|
|
120
|
-
return { query, queryParams };
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
protected buildDeleteStatement(where: FindManyOptions<TEntity>): { query: string; queryParams: any[]; } {
|
|
124
|
-
const { whereClause, queryParams } = this.buildWhereExpression(where as FindOptionsWhere<TEntity>);
|
|
125
|
-
const query = `DELETE FROM ${this.getTableNameExpression()}${whereClause};`;
|
|
126
|
-
return { query, queryParams };
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
protected buildWhereExpression(where?: FindOptionsWhere<TEntity>) {
|
|
130
|
-
const queryParams: any[] = [];
|
|
131
|
-
let whereClause = '';
|
|
132
|
-
|
|
133
|
-
Object.entries(where || {}).forEach(([propertyPath, value], index) => {
|
|
134
|
-
const key = this.columns[propertyPath as keyof TEntity].databasePath;
|
|
135
|
-
|
|
136
|
-
const where = Array.isArray((value as any).value)
|
|
137
|
-
? `${key} = ANY($${index + 1})`
|
|
138
|
-
: `${key} = $${index + 1}`;
|
|
139
|
-
|
|
140
|
-
if (index === 0) {
|
|
141
|
-
whereClause += ` WHERE ${where}`;
|
|
142
|
-
} else {
|
|
143
|
-
whereClause += ` AND ${where}`;
|
|
144
|
-
}
|
|
145
|
-
queryParams.push(value);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
return { queryParams, whereClause };
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
protected buildInsertQuery(entity: Partial<TEntity>): { insertQuery: string, values: any[] } {
|
|
152
|
-
const keys: Array<keyof TEntity> = Object.keys(entity) as any;
|
|
153
|
-
const values = Object.values(entity);
|
|
154
|
-
|
|
155
|
-
const columnNames = keys.map(key => this.columns[key].databasePath).join(', ');
|
|
156
|
-
const paramPlaceholders = keys.map((key, index) => this.mapPlaceholderExpression(0, index, key as string)).join(', ');
|
|
157
|
-
|
|
158
|
-
const insertQuery = `INSERT INTO ${this.getTableNameExpression()} (${columnNames}) VALUES (${paramPlaceholders})`;
|
|
159
|
-
|
|
160
|
-
return { insertQuery, values };
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
protected buildInsertManyQuery(entities: Partial<TEntity>[]): { insertQuery: string, values: any[] } {
|
|
164
|
-
const keyMap: Record<keyof TEntity, boolean> = {} as any;
|
|
165
|
-
|
|
166
|
-
entities.forEach(entity => {
|
|
167
|
-
(Object.keys(entity) as Array<keyof TEntity>)
|
|
168
|
-
.forEach(key => {
|
|
169
|
-
keyMap[key] = true;
|
|
170
|
-
});
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const columnNames = (Object.keys(keyMap) as Array<keyof TEntity>).map(key => this.columns[key].databasePath).join(', ');
|
|
174
|
-
|
|
175
|
-
const valuesExpressions: string[] = [];
|
|
176
|
-
const values: any[] = [];
|
|
177
|
-
|
|
178
|
-
entities.forEach(entity => {
|
|
179
|
-
const length = values.length;
|
|
180
|
-
|
|
181
|
-
(Object.keys(keyMap) as Array<keyof TEntity>).forEach((key) => {
|
|
182
|
-
values.push((typeof entity[key] === 'undefined') ? this.columns[key].default : entity[key]);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
const paramPlaceholders = Object.keys(keyMap).map((_, index) => this.mapPlaceholderExpression(length, index, _)).join(', ');
|
|
186
|
-
|
|
187
|
-
valuesExpressions.push(`(${paramPlaceholders})`);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
const insertQuery = `INSERT INTO ${this.getTableNameExpression()} (${columnNames}) VALUES ${valuesExpressions.join(', ')}`;
|
|
191
|
-
|
|
192
|
-
return { insertQuery, values };
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
protected mapPlaceholderExpression(length: number, index: number, column: string) {
|
|
196
|
-
const exp = `$${length + index + 1}`;
|
|
197
|
-
|
|
198
|
-
const meta: TTableMeta = this.columns[column as keyof TEntity];
|
|
199
|
-
return meta.type === 'jsonb' ? exp : exp; // TODO: figure out how to handle this for postgres... $1::jsonb equivalent
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
protected buildSelectManyQuery(entities: Partial<TEntity>[]): { selectQuery: string, values: any[] } {
|
|
203
|
-
const keyMap: any = {};
|
|
204
|
-
|
|
205
|
-
entities.forEach(entity => {
|
|
206
|
-
Object.keys(entity)
|
|
207
|
-
.forEach(key => {
|
|
208
|
-
keyMap[key] = true;
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
const selectExpressions: string[] = [];
|
|
213
|
-
const values: any[] = [];
|
|
214
|
-
|
|
215
|
-
entities.forEach(entity => {
|
|
216
|
-
const length = values.length;
|
|
217
|
-
|
|
218
|
-
(Object.keys(keyMap) as Array<keyof Partial<TEntity>>).forEach(key => {
|
|
219
|
-
values.push((typeof entity[key] === 'undefined') ? this.columns[key].default : entity[key]);
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
const whereExpression = Object.keys(keyMap).map((_, index) => `(${(this.columns as any)[_].databasePath} = $${length + index + 1})`).join(' AND ');
|
|
223
|
-
|
|
224
|
-
selectExpressions.push(`(select * from ${this.getTableNameExpression()} where (${whereExpression}))`);
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
const selectQuery = selectExpressions.join(' UNION ');
|
|
228
|
-
|
|
229
|
-
return { selectQuery, values };
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
map(raw: any): TEntity {
|
|
233
|
-
const mapped = (Object.values(this.columns) as TTableMeta[])
|
|
234
|
-
.reduce((entity: any, { propertyPath, databasePath }: TTableMeta) => {
|
|
235
|
-
entity[propertyPath] = raw[databasePath];
|
|
236
|
-
return entity;
|
|
237
|
-
}, {} as any) as TEntity;
|
|
238
|
-
|
|
239
|
-
return mapped;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
async query(query: string, parameters: any[]) {
|
|
243
|
-
if (this.debug) {
|
|
244
|
-
console.log({ schema: this.schema, table: this.table, query, parameters });
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const result = await this.repo.query(query, parameters);
|
|
248
|
-
|
|
249
|
-
if (this.debug) {
|
|
250
|
-
console.log({ schema: this.schema, table: this.table, query, parameters, result });
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return result as any[];
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
async queryAndMap(query: string, parameters: any[]) {
|
|
257
|
-
const result = await this.query(query, parameters);
|
|
258
|
-
|
|
259
|
-
return result?.map((_: any) => this.map(_)) as TEntity[];
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
static buildFromMetadata<TGenericEntity>(dataSource: DataSource, _: {schema: string, table: string, columns: TKeysOf<TGenericEntity, TTableMeta>}) {
|
|
263
|
-
|
|
264
|
-
class GenericRepository extends TypeOrmRepository<TGenericEntity> {
|
|
265
|
-
constructor() {
|
|
266
|
-
const entityManager = dataSource.createEntityManager();
|
|
267
|
-
super(Object, {
|
|
268
|
-
...entityManager,
|
|
269
|
-
getRepository: () => entityManager as any
|
|
270
|
-
} as any);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const genericRepository = new GenericRepository();
|
|
275
|
-
(genericRepository as any).schema = _.schema;
|
|
276
|
-
(genericRepository as any).table = _.table;
|
|
277
|
-
(genericRepository as any).columns = _.columns;
|
|
278
|
-
|
|
279
|
-
return genericRepository as TypeOrmRepository<TGenericEntity>;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
buildWhereILike(filters?: Record<string, any>): FindOptionsWhere<TEntity> {
|
|
284
|
-
|
|
285
|
-
if(!filters) {
|
|
286
|
-
return {};
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return Object.entries(filters || {})
|
|
290
|
-
.reduce(
|
|
291
|
-
(_, [column, filter]) => (
|
|
292
|
-
filter
|
|
293
|
-
? { ..._, [column]: ILike(`%${filter}%`) }
|
|
294
|
-
: _
|
|
295
|
-
),
|
|
296
|
-
{}
|
|
297
|
-
) as any;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { applyDecorators } from "@nestjs/common";
|
|
2
|
-
import { Column, ColumnOptions } from "typeorm";
|
|
3
|
-
import { ApiPropertyOptional } from '@nestjs/swagger';
|
|
4
|
-
import { getApiTypeFromColumn } from "../functions/get-api-type-from-column.function";
|
|
5
|
-
|
|
6
|
-
export const NullableTableColumn = (options?: Pick<ColumnOptions, 'type'>) => {
|
|
7
|
-
const apiType = getApiTypeFromColumn(options?.type);
|
|
8
|
-
return applyDecorators(Column({ type: options?.type, nullable: true }), ApiPropertyOptional({type: apiType}));
|
|
9
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { applyDecorators } from "@nestjs/common";
|
|
2
|
-
import { Column, ColumnOptions } from "typeorm";
|
|
3
|
-
import { ApiProperty } from '@nestjs/swagger';
|
|
4
|
-
import { getApiTypeFromColumn } from "../functions/get-api-type-from-column.function";
|
|
5
|
-
|
|
6
|
-
export const PrimaryTableColumn = (options?: Pick<ColumnOptions, 'type'>) => {
|
|
7
|
-
const apiType = getApiTypeFromColumn(options?.type);
|
|
8
|
-
return applyDecorators(Column({ type: options?.type, nullable: false }), ApiProperty({type: apiType}));
|
|
9
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { applyDecorators } from "@nestjs/common";
|
|
2
|
-
import { Column, ColumnOptions } from "typeorm";
|
|
3
|
-
import { ApiProperty } from '@nestjs/swagger';
|
|
4
|
-
import { getApiTypeFromColumn } from "../functions/get-api-type-from-column.function";
|
|
5
|
-
|
|
6
|
-
export const TableColumn = (options?: Pick<ColumnOptions, 'type'>) => {
|
|
7
|
-
const apiType = getApiTypeFromColumn(options?.type);
|
|
8
|
-
return applyDecorators(Column({ type: options?.type, nullable: false }), ApiProperty({type: apiType}));
|
|
9
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { applyDecorators } from "@nestjs/common";
|
|
2
|
-
import { Entity } from "typeorm";
|
|
3
|
-
import { snakeCase } from '@onivoro/isomorphic-common';
|
|
4
|
-
|
|
5
|
-
export const Table = (EntityClass: { name: string }) => {
|
|
6
|
-
const tableName = snakeCase(EntityClass.name);
|
|
7
|
-
return applyDecorators(Entity(tableName));
|
|
8
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
|
2
|
-
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions';
|
|
3
|
-
import { IDataSourceOptions } from '../types/data-source-options.interface';
|
|
4
|
-
|
|
5
|
-
export function dataSourceConfigFactory(
|
|
6
|
-
name: string,
|
|
7
|
-
options: IDataSourceOptions,
|
|
8
|
-
entities: any[]
|
|
9
|
-
): PostgresConnectionOptions {
|
|
10
|
-
|
|
11
|
-
const {
|
|
12
|
-
ca, database, host, password, port, username, synchronize = false, logging = false, schema,
|
|
13
|
-
} = options;
|
|
14
|
-
|
|
15
|
-
const config: PostgresConnectionOptions = {
|
|
16
|
-
name,
|
|
17
|
-
type: 'postgres',
|
|
18
|
-
host,
|
|
19
|
-
port: port as any,
|
|
20
|
-
username,
|
|
21
|
-
password,
|
|
22
|
-
ssl: ca ? { ca } : undefined,
|
|
23
|
-
database,
|
|
24
|
-
synchronize,
|
|
25
|
-
logging,
|
|
26
|
-
entities,
|
|
27
|
-
schema,
|
|
28
|
-
subscribers: [],
|
|
29
|
-
migrations: [],
|
|
30
|
-
namingStrategy: new SnakeNamingStrategy(),
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
return config;
|
|
34
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { DataSource } from 'typeorm';
|
|
2
|
-
import { dataSourceConfigFactory } from './data-source-config-factory.function';
|
|
3
|
-
import { IDataSourceOptions } from '../types/data-source-options.interface';
|
|
4
|
-
|
|
5
|
-
export const dataSourceFactory = (
|
|
6
|
-
name: string,
|
|
7
|
-
options: IDataSourceOptions,
|
|
8
|
-
entities: any[]
|
|
9
|
-
) =>
|
|
10
|
-
new DataSource(dataSourceConfigFactory(name, options, entities));
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Between, FindOperator, LessThanOrEqual, MoreThanOrEqual } from "typeorm";
|
|
2
|
-
|
|
3
|
-
export function generateDateQuery(
|
|
4
|
-
minDueDate: string,
|
|
5
|
-
maxDueDate: string
|
|
6
|
-
): FindOperator<Date> | undefined {
|
|
7
|
-
if (minDueDate && maxDueDate) {
|
|
8
|
-
return Between(minDueDate as any, maxDueDate as any);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
if (maxDueDate) {
|
|
12
|
-
return LessThanOrEqual(new Date(maxDueDate));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (minDueDate) {
|
|
16
|
-
return MoreThanOrEqual(new Date(minDueDate));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { ColumnOptions } from "typeorm";
|
|
2
|
-
|
|
3
|
-
export function getApiTypeFromColumn(columnType: ColumnOptions['type']) {
|
|
4
|
-
if(!columnType) {
|
|
5
|
-
return 'string';
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
switch (columnType) {
|
|
9
|
-
case 'boolean':
|
|
10
|
-
return columnType;
|
|
11
|
-
default:
|
|
12
|
-
return 'string';
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { DynamicModule, Module } from '@nestjs/common';
|
|
2
|
-
import { DataSource, EntityManager } from 'typeorm';
|
|
3
|
-
import { dataSourceFactory } from './functions/data-source-factory.function';
|
|
4
|
-
import { IDataSourceOptions } from './types/data-source-options.interface';
|
|
5
|
-
|
|
6
|
-
const dataSourceMap = new Map();
|
|
7
|
-
|
|
8
|
-
@Module({})
|
|
9
|
-
export class ServerTypeormPostgresModule {
|
|
10
|
-
static configure(
|
|
11
|
-
injectables: any[],
|
|
12
|
-
entities: any[],
|
|
13
|
-
options: IDataSourceOptions,
|
|
14
|
-
name = 'default'
|
|
15
|
-
): DynamicModule {
|
|
16
|
-
const providers = [
|
|
17
|
-
{
|
|
18
|
-
provide: DataSource,
|
|
19
|
-
useFactory: async () => {
|
|
20
|
-
const cachedDataSource = dataSourceMap.get(name);
|
|
21
|
-
if (!cachedDataSource) {
|
|
22
|
-
const dataSource: DataSource = dataSourceFactory(name, options, entities);
|
|
23
|
-
await dataSource.initialize();
|
|
24
|
-
dataSourceMap.set(name, dataSource);
|
|
25
|
-
}
|
|
26
|
-
return dataSourceMap.get(name);
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
provide: EntityManager,
|
|
31
|
-
useFactory: (dataSource: DataSource) => {
|
|
32
|
-
return dataSource.manager;
|
|
33
|
-
},
|
|
34
|
-
inject: [DataSource]
|
|
35
|
-
},
|
|
36
|
-
...injectables,
|
|
37
|
-
];
|
|
38
|
-
return {
|
|
39
|
-
module: ServerTypeormPostgresModule,
|
|
40
|
-
exports: providers,
|
|
41
|
-
providers,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export interface IEntityProvider<TEntity, TFindOneOptions, TFindManyOptions, TFindOptionsWhere, TQueryDeepPartialEntity> {
|
|
2
|
-
getOne: (options: TFindOneOptions) => Promise<TEntity>;
|
|
3
|
-
getMany: (options: TFindManyOptions) => Promise<TEntity[]>;
|
|
4
|
-
postOne: (body: Partial<TEntity>) => Promise<TEntity>;
|
|
5
|
-
postMany: (body: Partial<TEntity>[]) => Promise<TEntity[]>;
|
|
6
|
-
delete: (options: TFindOptionsWhere) => Promise<void>;
|
|
7
|
-
put: (options: TFindOptionsWhere, body: TQueryDeepPartialEntity) => Promise<void>;
|
|
8
|
-
patch: (options: TFindOptionsWhere, body: TQueryDeepPartialEntity) => Promise<void>;
|
|
9
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../../tsconfig.server.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "../../../dist/out-tsc",
|
|
5
|
-
"strict": false
|
|
6
|
-
},
|
|
7
|
-
"files": [],
|
|
8
|
-
"include": [],
|
|
9
|
-
"references": [
|
|
10
|
-
{
|
|
11
|
-
"path": "./tsconfig.lib.json"
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
"path": "./tsconfig.spec.json"
|
|
15
|
-
}
|
|
16
|
-
]
|
|
17
|
-
}
|
package/tsconfig.lib.json
DELETED
package/tsconfig.spec.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "./tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"types": [
|
|
5
|
-
"jest",
|
|
6
|
-
"node"
|
|
7
|
-
]
|
|
8
|
-
},
|
|
9
|
-
"include": [
|
|
10
|
-
"jest.config.ts",
|
|
11
|
-
"**/*.test.ts",
|
|
12
|
-
"**/*.spec.ts",
|
|
13
|
-
"**/*.test.tsx",
|
|
14
|
-
"**/*.spec.tsx",
|
|
15
|
-
"**/*.test.js",
|
|
16
|
-
"**/*.spec.js",
|
|
17
|
-
"**/*.test.jsx",
|
|
18
|
-
"**/*.spec.jsx",
|
|
19
|
-
"**/*.d.ts"
|
|
20
|
-
]
|
|
21
|
-
}
|