@companix/xeo-server 0.0.2
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/.eslintrc +54 -0
- package/dist/common/decorators.d.ts +3 -0
- package/dist/common/decorators.js +14 -0
- package/dist/common/decorators.js.map +1 -0
- package/dist/common/index.d.ts +3 -0
- package/dist/common/index.js +20 -0
- package/dist/common/index.js.map +1 -0
- package/dist/common/tokens.d.ts +3 -0
- package/dist/common/tokens.js +14 -0
- package/dist/common/tokens.js.map +1 -0
- package/dist/common/utils.d.ts +2 -0
- package/dist/common/utils.js +19 -0
- package/dist/common/utils.js.map +1 -0
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +8 -0
- package/dist/constants.js.map +1 -0
- package/dist/driver.module.d.ts +7 -0
- package/dist/driver.module.js +41 -0
- package/dist/driver.module.js.map +1 -0
- package/dist/drivers/collection.driver.d.ts +21 -0
- package/dist/drivers/collection.driver.js +101 -0
- package/dist/drivers/collection.driver.js.map +1 -0
- package/dist/drivers/table.driver.d.ts +13 -0
- package/dist/drivers/table.driver.js +79 -0
- package/dist/drivers/table.driver.js.map +1 -0
- package/dist/factories/definitions.factory.d.ts +11 -0
- package/dist/factories/definitions.factory.js +116 -0
- package/dist/factories/definitions.factory.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/mongoose-options.interface.d.ts +12 -0
- package/dist/mongoose-options.interface.js +3 -0
- package/dist/mongoose-options.interface.js.map +1 -0
- package/dist/mongoose.module.d.ts +11 -0
- package/dist/mongoose.module.js +108 -0
- package/dist/mongoose.module.js.map +1 -0
- package/dist/storages/data-source.d.ts +10 -0
- package/dist/storages/data-source.js +34 -0
- package/dist/storages/data-source.js.map +1 -0
- package/jest.cases.config.cjs +14 -0
- package/lib/common/decorators.ts +17 -0
- package/lib/common/index.ts +3 -0
- package/lib/common/tokens.ts +17 -0
- package/lib/common/utils.ts +29 -0
- package/lib/constants.ts +4 -0
- package/lib/driver.module.ts +37 -0
- package/lib/drivers/collection.driver.ts +157 -0
- package/lib/drivers/table.driver.ts +109 -0
- package/lib/factories/definitions.factory.ts +129 -0
- package/lib/index.ts +3 -0
- package/lib/mongoose-options.interface.ts +19 -0
- package/lib/mongoose.module.ts +95 -0
- package/lib/storages/data-source.ts +37 -0
- package/package.json +42 -0
- package/tests/app/bootstrap.ts +16 -0
- package/tests/app/db.ts +22 -0
- package/tests/app/filters.ts +25 -0
- package/tests/app/helpers/is-one-of.ts +58 -0
- package/tests/app/main.ts +3 -0
- package/tests/app/module/app.controller.ts +67 -0
- package/tests/app/module/app.dto.ts +394 -0
- package/tests/app/module/app.module.ts +12 -0
- package/tests/app/module/app.service.ts +76 -0
- package/tests/app/root.module.ts +12 -0
- package/tests/globals.d.ts +6 -0
- package/tests/integrations/cases.test.ts +154 -0
- package/tests/integrations/custom.test.ts +69 -0
- package/tests/unit/definitions.test.ts +31 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +17 -0
- package/tsconfig.test-app.json +10 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CollectionScheme,
|
|
3
|
+
DataScheme,
|
|
4
|
+
ModelProperties,
|
|
5
|
+
PropertyRelation,
|
|
6
|
+
PropertyMetadata,
|
|
7
|
+
ModelScheme
|
|
8
|
+
} from '@companix/xeo-scheme'
|
|
9
|
+
import type { SchemaDefinition, SchemaDefinitionProperty } from 'mongoose'
|
|
10
|
+
import { Schema } from 'mongoose'
|
|
11
|
+
|
|
12
|
+
const TypesTranslator = {
|
|
13
|
+
string: String,
|
|
14
|
+
number: Number,
|
|
15
|
+
json: Object,
|
|
16
|
+
boolean: Boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class DefinitionsFactory<T extends CollectionScheme> {
|
|
20
|
+
constructor(private dataScheme: DataScheme<T>) {}
|
|
21
|
+
|
|
22
|
+
createForCollection(name: keyof T): SchemaDefinition {
|
|
23
|
+
return this.createForScheme(this.dataScheme.models[this.dataScheme.collections[name].name].scheme)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
createForScheme(scheme: ModelScheme): SchemaDefinition {
|
|
27
|
+
return {
|
|
28
|
+
[scheme.identifier.propertyKey]: {
|
|
29
|
+
index: true,
|
|
30
|
+
type: TypesTranslator[scheme.identifier.options.type],
|
|
31
|
+
unique: true
|
|
32
|
+
},
|
|
33
|
+
...this.createDefinitionScheme(scheme)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
createDefinitionScheme({ properties, references }: ModelProperties): SchemaDefinition {
|
|
38
|
+
const map: SchemaDefinition = {}
|
|
39
|
+
|
|
40
|
+
for (const property of properties) {
|
|
41
|
+
map[property.propertyKey] = this.getPropertyDefinition(property)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (const reference of references) {
|
|
45
|
+
map[reference.propertyKey] = this.getRelationDefinition(reference)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return map
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private getPropertyDefinition({ primitive }: PropertyMetadata): SchemaDefinitionProperty {
|
|
52
|
+
switch (primitive.type) {
|
|
53
|
+
case 'embedded': {
|
|
54
|
+
return {
|
|
55
|
+
_id: false, // prevent creating _id (без указания mongodb создавал бы _id для всех вложенных объектов)
|
|
56
|
+
type: this.createDefinitionScheme(primitive),
|
|
57
|
+
required: true
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
case 'array': {
|
|
61
|
+
return {
|
|
62
|
+
type: [TypesTranslator[primitive.itemType]],
|
|
63
|
+
required: true
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
case 'literal': {
|
|
67
|
+
return {
|
|
68
|
+
type: Schema.Types.Mixed, // сузить до String и Number
|
|
69
|
+
enum: primitive.values,
|
|
70
|
+
required: !primitive.nullable
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
case 'enum': {
|
|
74
|
+
return {
|
|
75
|
+
type: [String], // может быть и Number
|
|
76
|
+
enum: primitive.values,
|
|
77
|
+
required: !primitive.nullable
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
default: {
|
|
81
|
+
return {
|
|
82
|
+
type: TypesTranslator[primitive.type]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private getRelationDefinition(reference: PropertyRelation): SchemaDefinitionProperty {
|
|
89
|
+
const refModel = this.dataScheme.metadata.getModelSchemaByTarget(reference.referenceModel)
|
|
90
|
+
|
|
91
|
+
switch (reference.refType) {
|
|
92
|
+
case 'reference-to': {
|
|
93
|
+
return {
|
|
94
|
+
type: TypesTranslator[refModel.identifier.options.type],
|
|
95
|
+
required: (reference.options?.onRefDeleting ?? 'restrict') === 'restrict'
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
case 'reference-set': {
|
|
99
|
+
return {
|
|
100
|
+
type: [TypesTranslator[refModel.identifier.options.type]]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
case 'belongs-to': {
|
|
104
|
+
return {
|
|
105
|
+
type: TypesTranslator[refModel.identifier.options.type],
|
|
106
|
+
required: true
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
case 'has-many': {
|
|
110
|
+
return {
|
|
111
|
+
type: [TypesTranslator[refModel.identifier.options.type]],
|
|
112
|
+
required: true
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
case 'owner': {
|
|
116
|
+
return {
|
|
117
|
+
type: TypesTranslator[refModel.identifier.options.type],
|
|
118
|
+
required: true
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
case 'owner-fallback': {
|
|
122
|
+
return {
|
|
123
|
+
type: TypesTranslator[refModel.identifier.options.type],
|
|
124
|
+
refType: 'owner-fallback'
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
package/lib/index.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ConnectOptions, Connection, MongooseError } from 'mongoose'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @publicApi
|
|
5
|
+
*/
|
|
6
|
+
export interface MongooseModuleOptions extends ConnectOptions {
|
|
7
|
+
uri?: string
|
|
8
|
+
retryAttempts?: number
|
|
9
|
+
retryDelay?: number
|
|
10
|
+
connectionName?: string
|
|
11
|
+
connectionFactory?: (connection: any, name: string) => any
|
|
12
|
+
connectionErrorFactory?: (error: MongooseError) => MongooseError
|
|
13
|
+
lazyConnection?: boolean
|
|
14
|
+
onConnectionCreate?: (connection: Connection) => void
|
|
15
|
+
/**
|
|
16
|
+
* If `true`, will show verbose error messages on each connection retry.
|
|
17
|
+
*/
|
|
18
|
+
verboseRetryLog?: boolean
|
|
19
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as mongoose from 'mongoose'
|
|
2
|
+
import { DynamicModule, Global, Inject, Module, OnApplicationShutdown } from '@nestjs/common'
|
|
3
|
+
import { ModuleRef } from '@nestjs/core'
|
|
4
|
+
import { ConnectOptions, Connection } from 'mongoose'
|
|
5
|
+
import { defer, lastValueFrom } from 'rxjs'
|
|
6
|
+
import { catchError } from 'rxjs/operators'
|
|
7
|
+
import { MONGOOSE_CONNECTION_NAME } from './constants'
|
|
8
|
+
import { getConnectionToken, handleRetry } from './common'
|
|
9
|
+
import { MongooseModuleOptions } from './mongoose-options.interface'
|
|
10
|
+
|
|
11
|
+
@Global()
|
|
12
|
+
@Module({})
|
|
13
|
+
export class MongooseCoreModule implements OnApplicationShutdown {
|
|
14
|
+
constructor(
|
|
15
|
+
@Inject(MONGOOSE_CONNECTION_NAME) private readonly connectionName: string,
|
|
16
|
+
private readonly moduleRef: ModuleRef
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
static forRoot(uri: string, options: MongooseModuleOptions = {}): DynamicModule {
|
|
20
|
+
const {
|
|
21
|
+
retryAttempts,
|
|
22
|
+
retryDelay,
|
|
23
|
+
connectionName,
|
|
24
|
+
connectionFactory,
|
|
25
|
+
connectionErrorFactory,
|
|
26
|
+
lazyConnection,
|
|
27
|
+
onConnectionCreate,
|
|
28
|
+
verboseRetryLog,
|
|
29
|
+
...mongooseOptions
|
|
30
|
+
} = options
|
|
31
|
+
|
|
32
|
+
const mongooseConnectionFactory = connectionFactory || ((connection) => connection)
|
|
33
|
+
|
|
34
|
+
const mongooseConnectionError = connectionErrorFactory || ((error) => error)
|
|
35
|
+
|
|
36
|
+
const mongooseConnectionName = getConnectionToken(connectionName)
|
|
37
|
+
|
|
38
|
+
const mongooseConnectionNameProvider = {
|
|
39
|
+
provide: MONGOOSE_CONNECTION_NAME,
|
|
40
|
+
useValue: mongooseConnectionName
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const connectionProvider = {
|
|
44
|
+
provide: mongooseConnectionName,
|
|
45
|
+
useFactory: async (): Promise<any> =>
|
|
46
|
+
await lastValueFrom(
|
|
47
|
+
defer(async () =>
|
|
48
|
+
mongooseConnectionFactory(
|
|
49
|
+
await this.createMongooseConnection(uri, mongooseOptions, {
|
|
50
|
+
lazyConnection,
|
|
51
|
+
onConnectionCreate
|
|
52
|
+
}),
|
|
53
|
+
mongooseConnectionName
|
|
54
|
+
)
|
|
55
|
+
).pipe(
|
|
56
|
+
handleRetry(retryAttempts, retryDelay, verboseRetryLog),
|
|
57
|
+
catchError((error) => {
|
|
58
|
+
throw mongooseConnectionError(error)
|
|
59
|
+
})
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
module: MongooseCoreModule,
|
|
65
|
+
providers: [connectionProvider, mongooseConnectionNameProvider],
|
|
66
|
+
exports: [connectionProvider]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private static async createMongooseConnection(
|
|
71
|
+
uri: string,
|
|
72
|
+
mongooseOptions: ConnectOptions,
|
|
73
|
+
factoryOptions: {
|
|
74
|
+
lazyConnection?: boolean
|
|
75
|
+
onConnectionCreate?: MongooseModuleOptions['onConnectionCreate']
|
|
76
|
+
}
|
|
77
|
+
): Promise<Connection> {
|
|
78
|
+
const connection = mongoose.createConnection(uri, mongooseOptions)
|
|
79
|
+
|
|
80
|
+
if (factoryOptions?.lazyConnection) {
|
|
81
|
+
return connection
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
factoryOptions?.onConnectionCreate?.(connection)
|
|
85
|
+
|
|
86
|
+
return connection.asPromise()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async onApplicationShutdown() {
|
|
90
|
+
const connection = this.moduleRef.get<any>(this.connectionName)
|
|
91
|
+
if (connection) {
|
|
92
|
+
await connection.close()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { CollectionScheme, DataScheme, DataSource } from '@companix/xeo-scheme'
|
|
2
|
+
import { Connection } from 'mongoose'
|
|
3
|
+
import { createMongoDriver } from '../drivers/collection.driver'
|
|
4
|
+
import { DATA_SOURCE_TOKEN } from '../constants'
|
|
5
|
+
|
|
6
|
+
class DataSourceStorageService {
|
|
7
|
+
private dataSource: DataSource<CollectionScheme> | null = null
|
|
8
|
+
private dataScheme: DataScheme<CollectionScheme> | null = null
|
|
9
|
+
|
|
10
|
+
getProviderToken(dataScheme: DataScheme<CollectionScheme>) {
|
|
11
|
+
if (this.dataScheme === null) {
|
|
12
|
+
this.dataScheme = dataScheme
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (this.dataScheme !== dataScheme) {
|
|
16
|
+
throw new Error(`[MongoDriver] driver cannot work with several dataSchemes`)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return DATA_SOURCE_TOKEN
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getSource(dataScheme: DataScheme<CollectionScheme>, connection: Connection) {
|
|
23
|
+
if (this.dataScheme !== dataScheme) {
|
|
24
|
+
throw new Error(`[MongoDriver] driver cannot work with several dataSchemes`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!this.dataSource) {
|
|
28
|
+
this.dataSource = new DataSource(dataScheme, {
|
|
29
|
+
createDriver: createMongoDriver(connection)
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return this.dataSource
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const DataSourceStorage = new DataSourceStorageService()
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@companix/xeo-server",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"echo": "echo \"@companix/xeo-server\"",
|
|
8
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
9
|
+
"test:unit": "tsc --noEmit && tsx ./tests/unit/definitions.ts",
|
|
10
|
+
"test:app": "nest start --watch --builder tsc --path tsconfig.test-app.json --sourceRoot tests/app --entryFile main",
|
|
11
|
+
"test:custom": "nest start --watch --builder tsc --path tsconfig.test-app.json --sourceRoot tests --entryFile integrations/custom.test",
|
|
12
|
+
"test:cases": "jest --config ./jest.cases.config.cjs --runInBand"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@nestjs/common": "^11.1.17",
|
|
16
|
+
"@nestjs/core": "^11.1.17",
|
|
17
|
+
"@nestjs/platform-express": "^11.1.12",
|
|
18
|
+
"@types/jest": "^30.0.0",
|
|
19
|
+
"class-transformer": "^0.5.1",
|
|
20
|
+
"class-validator": "^0.15.1",
|
|
21
|
+
"eslint-config-react-app": "^7.0.1",
|
|
22
|
+
"eslint-plugin-import": "^2.29.1",
|
|
23
|
+
"eslint-plugin-react": "^7.34.3",
|
|
24
|
+
"eslint-plugin-react-hooks": "^4.6.2",
|
|
25
|
+
"eslint-webpack-plugin": "^4.2.0",
|
|
26
|
+
"jest": "^30.3.0",
|
|
27
|
+
"mongoose": "^9.3.3",
|
|
28
|
+
"rxjs": "^7.8.2",
|
|
29
|
+
"ts-jest": "^29.4.6",
|
|
30
|
+
"zod": "^4.3.6"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@companix/utils-js": "*",
|
|
34
|
+
"@companix/xeo-scheme": "*"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
38
|
+
"@nestjs/core": "^10.0.0 || ^11.0.0",
|
|
39
|
+
"mongoose": "^9.0.0",
|
|
40
|
+
"rxjs": "^7.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { NestFactory } from '@nestjs/core'
|
|
2
|
+
import { RootModule } from './root.module'
|
|
3
|
+
import { ValidationPipe } from '@nestjs/common'
|
|
4
|
+
import { AllExceptionsFilter } from './filters'
|
|
5
|
+
|
|
6
|
+
export const bootstrap = async (port = 3111) => {
|
|
7
|
+
const app = await NestFactory.create(RootModule)
|
|
8
|
+
|
|
9
|
+
app.useGlobalFilters(new AllExceptionsFilter())
|
|
10
|
+
app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }))
|
|
11
|
+
|
|
12
|
+
await app.listen(port)
|
|
13
|
+
console.log(`Application is running on: http://localhost:${port}/app`)
|
|
14
|
+
|
|
15
|
+
return app
|
|
16
|
+
}
|
package/tests/app/db.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { MongooseModuleOptions } from '../../lib/mongoose-options.interface'
|
|
2
|
+
|
|
3
|
+
const DB_NAME = 'xeo-test'
|
|
4
|
+
const DB_PORT = 27017
|
|
5
|
+
const DB_AUTH = 'admin'
|
|
6
|
+
const DB_PASS = 'example'
|
|
7
|
+
const DB_HOST = '127.0.0.1'
|
|
8
|
+
const DB_CERT = ''
|
|
9
|
+
const DB_USER = 'root'
|
|
10
|
+
|
|
11
|
+
export const getMongoConnectionURL = (): string => {
|
|
12
|
+
return `mongodb://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const getMongoConnectionOptions = (): MongooseModuleOptions => {
|
|
16
|
+
return {
|
|
17
|
+
tls: DB_CERT ? true : false,
|
|
18
|
+
tlsCAFile: DB_CERT,
|
|
19
|
+
dbName: DB_NAME,
|
|
20
|
+
authSource: DB_AUTH
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { CoreError } from '@companix/xeo-scheme'
|
|
2
|
+
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common'
|
|
3
|
+
|
|
4
|
+
@Catch()
|
|
5
|
+
export class AllExceptionsFilter implements ExceptionFilter {
|
|
6
|
+
catch(exception: any, host: ArgumentsHost) {
|
|
7
|
+
const ctx = host.switchToHttp()
|
|
8
|
+
const response = ctx.getResponse()
|
|
9
|
+
|
|
10
|
+
// core conflicts
|
|
11
|
+
if (exception instanceof CoreError) {
|
|
12
|
+
console.log('core exception:', exception)
|
|
13
|
+
response.status(HttpStatus.BAD_REQUEST).json(exception)
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// internal server errors
|
|
18
|
+
if (exception instanceof HttpException) {
|
|
19
|
+
response.status(exception.getStatus()).json(exception.getResponse())
|
|
20
|
+
return
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
response.status(HttpStatus.INTERNAL_SERVER_ERROR).json(exception?.response)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { plainToInstance } from 'class-transformer'
|
|
2
|
+
import {
|
|
3
|
+
ValidatorConstraint,
|
|
4
|
+
ValidatorConstraintInterface,
|
|
5
|
+
ValidationArguments,
|
|
6
|
+
validate,
|
|
7
|
+
ValidationOptions,
|
|
8
|
+
registerDecorator
|
|
9
|
+
} from 'class-validator'
|
|
10
|
+
|
|
11
|
+
@ValidatorConstraint({ async: true })
|
|
12
|
+
export class IsOneOfDtoConstraint implements ValidatorConstraintInterface {
|
|
13
|
+
async validate(value: any, args: ValidationArguments) {
|
|
14
|
+
const [dtos, discriptor] = args.constraints as [any[], string]
|
|
15
|
+
|
|
16
|
+
if (!value) {
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const dto = dtos.find((some) => {
|
|
21
|
+
const classDescriptor = new some()[discriptor]
|
|
22
|
+
|
|
23
|
+
if (classDescriptor) {
|
|
24
|
+
return classDescriptor === value[discriptor]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.warn('WARN: Set descriptor value to:', some)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
if (dto) {
|
|
31
|
+
const errors = await validate(plainToInstance(dto, value))
|
|
32
|
+
|
|
33
|
+
if (errors.length === 0) {
|
|
34
|
+
return true
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.error('ERRORs: ', dto, errors)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
defaultMessage(args: ValidationArguments) {
|
|
44
|
+
return 'Data does not match'
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function IsOneOf(dtos: [Function[], string], validationOptions?: ValidationOptions) {
|
|
49
|
+
return function (object: Object, propertyName: string) {
|
|
50
|
+
registerDecorator({
|
|
51
|
+
target: object.constructor,
|
|
52
|
+
propertyName: propertyName,
|
|
53
|
+
options: validationOptions,
|
|
54
|
+
constraints: dtos,
|
|
55
|
+
validator: IsOneOfDtoConstraint
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Body, Controller, Get, Post } from '@nestjs/common'
|
|
2
|
+
import {
|
|
3
|
+
CreateBankCardDto,
|
|
4
|
+
CreateBankDetailDto,
|
|
5
|
+
CreateDictionaryDto,
|
|
6
|
+
CreateOptionDto,
|
|
7
|
+
CreateRoleDto,
|
|
8
|
+
CreateScanDto,
|
|
9
|
+
CreateWorkerDto,
|
|
10
|
+
UpdateOptionDto
|
|
11
|
+
} from './app.dto'
|
|
12
|
+
import { AppService } from './app.service'
|
|
13
|
+
|
|
14
|
+
@Controller('app')
|
|
15
|
+
export class AppController {
|
|
16
|
+
constructor(private readonly appService: AppService) {}
|
|
17
|
+
|
|
18
|
+
@Post('addWorker')
|
|
19
|
+
async addWorker(@Body() dto: CreateWorkerDto) {
|
|
20
|
+
return this.appService.addWorker(dto)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@Post('addScan')
|
|
24
|
+
async addScan(@Body() dto: CreateScanDto) {
|
|
25
|
+
return this.appService.addScan(dto)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@Post('addBankCard')
|
|
29
|
+
async addBankCard(@Body() dto: CreateBankCardDto) {
|
|
30
|
+
return this.appService.addBankCard(dto)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Post('addBankDetail')
|
|
34
|
+
async addBankDetail(@Body() dto: CreateBankDetailDto) {
|
|
35
|
+
return this.appService.addBankDetail(dto)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Post('addRole')
|
|
39
|
+
async addRole(@Body() dto: CreateRoleDto) {
|
|
40
|
+
return this.appService.addRole(dto)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Post('addDictionary')
|
|
44
|
+
async addDictionary(@Body() dto: CreateDictionaryDto) {
|
|
45
|
+
return this.appService.addDictionary(dto)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Post('addOption')
|
|
49
|
+
async addOption(@Body() dto: CreateOptionDto) {
|
|
50
|
+
return this.appService.addOption(dto)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@Post('updateOption')
|
|
54
|
+
async updateOption(@Body() dto: UpdateOptionDto) {
|
|
55
|
+
return this.appService.updateOption(dto)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@Get()
|
|
59
|
+
async getState() {
|
|
60
|
+
return this.appService.getState()
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@Get('tables')
|
|
64
|
+
async getTables() {
|
|
65
|
+
return this.appService.getTables()
|
|
66
|
+
}
|
|
67
|
+
}
|