@things-factory/shell 7.0.0-alpha.0 → 7.0.0-alpha.18
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/client/bootstrap.js +5 -0
- package/config/license.json +12 -12
- package/dist-server/graphql-local-client.d.ts +19 -0
- package/dist-server/graphql-local-client.js +17 -3
- package/dist-server/graphql-local-client.js.map +1 -1
- package/dist-server/index.d.ts +2 -0
- package/dist-server/index.js +2 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/initializers/database.d.ts +26 -0
- package/dist-server/initializers/database.js +26 -0
- package/dist-server/initializers/database.js.map +1 -1
- package/dist-server/pubsub-log-transport.d.ts +27 -0
- package/dist-server/pubsub-log-transport.js +15 -0
- package/dist-server/pubsub-log-transport.js.map +1 -1
- package/dist-server/pubsub.d.ts +9 -1
- package/dist-server/pubsub.js +14 -2
- package/dist-server/pubsub.js.map +1 -1
- package/dist-server/schema.d.ts +4 -0
- package/dist-server/schema.js +7 -3
- package/dist-server/schema.js.map +1 -1
- package/dist-server/server-dev.js +4 -1
- package/dist-server/server-dev.js.map +1 -1
- package/dist-server/server.js +4 -1
- package/dist-server/server.js.map +1 -1
- package/dist-server/service/subscription-data/data-resolver.js +6 -12
- package/dist-server/service/subscription-data/data-resolver.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/dist-server/typeorm/encrypt-transform.d.ts +5 -0
- package/dist-server/typeorm/encrypt-transform.js +25 -0
- package/dist-server/typeorm/encrypt-transform.js.map +1 -1
- package/dist-server/typeorm/json5-transform.d.ts +2 -0
- package/dist-server/typeorm/json5-transform.js +29 -0
- package/dist-server/typeorm/json5-transform.js.map +1 -0
- package/dist-server/typeorm/round-transform.d.ts +5 -0
- package/dist-server/typeorm/round-transform.js +21 -0
- package/dist-server/typeorm/round-transform.js.map +1 -0
- package/dist-server/utils/condition-builder.d.ts +11 -0
- package/dist-server/utils/condition-builder.js +11 -0
- package/dist-server/utils/condition-builder.js.map +1 -1
- package/dist-server/utils/get-domain.d.ts +46 -0
- package/dist-server/utils/get-domain.js +70 -0
- package/dist-server/utils/get-domain.js.map +1 -1
- package/dist-server/utils/get-query-builder-from-list-params.d.ts +12 -2
- package/dist-server/utils/get-query-builder-from-list-params.js +24 -8
- package/dist-server/utils/get-query-builder-from-list-params.js.map +1 -1
- package/dist-server/utils/get-times-for-period.d.ts +14 -0
- package/dist-server/utils/get-times-for-period.js +14 -0
- package/dist-server/utils/get-times-for-period.js.map +1 -1
- package/dist-server/utils/list-param-adjuster.d.ts +9 -0
- package/dist-server/utils/list-param-adjuster.js +9 -0
- package/dist-server/utils/list-param-adjuster.js.map +1 -1
- package/dist-server/utils/list-params-converter.d.ts +6 -0
- package/dist-server/utils/list-params-converter.js +27 -0
- package/dist-server/utils/list-params-converter.js.map +1 -1
- package/dist-server/utils/list-query-builder.d.ts +10 -1
- package/dist-server/utils/list-query-builder.js +10 -1
- package/dist-server/utils/list-query-builder.js.map +1 -1
- package/dist-server/utils/publish-progress.d.ts +9 -0
- package/dist-server/utils/publish-progress.js +9 -0
- package/dist-server/utils/publish-progress.js.map +1 -1
- package/package.json +7 -7
- package/server/graphql-local-client.ts +23 -3
- package/server/index.ts +3 -0
- package/server/initializers/database.ts +26 -0
- package/server/pubsub-log-transport.ts +29 -0
- package/server/pubsub.ts +17 -3
- package/server/schema.ts +9 -12
- package/server/server-dev.ts +7 -8
- package/server/server.ts +7 -8
- package/server/service/subscription-data/data-resolver.ts +9 -18
- package/server/typeorm/encrypt-transform.ts +26 -0
- package/server/typeorm/json5-transform.ts +26 -0
- package/server/typeorm/round-transform.ts +20 -0
- package/server/utils/condition-builder.ts +12 -8
- package/server/utils/get-domain.ts +70 -0
- package/server/utils/get-query-builder-from-list-params.ts +26 -16
- package/server/utils/get-times-for-period.ts +15 -4
- package/server/utils/list-param-adjuster.ts +9 -0
- package/server/utils/list-params-converter.ts +28 -4
- package/server/utils/list-query-builder.ts +13 -17
- package/server/utils/publish-progress.ts +9 -0
- package/dist-server/webpack/koa-webpack/client.d.ts +0 -1
- package/dist-server/webpack/koa-webpack/client.js +0 -24
- package/dist-server/webpack/koa-webpack/client.js.map +0 -1
- package/dist-server/webpack/koa-webpack/index.d.ts +0 -2
- package/dist-server/webpack/koa-webpack/index.js +0 -58
- package/dist-server/webpack/koa-webpack/index.js.map +0 -1
- package/dist-server/webpack/koa-webpack/middleware.d.ts +0 -0
- package/dist-server/webpack/koa-webpack/middleware.js +0 -42
- package/dist-server/webpack/koa-webpack/middleware.js.map +0 -1
- package/dist-server/webpack/koa-webpack/validate.d.ts +0 -1
- package/dist-server/webpack/koa-webpack/validate.js +0 -26
- package/dist-server/webpack/koa-webpack/validate.js.map +0 -1
- package/server/webpack/koa-webpack/client.ts +0 -26
- package/server/webpack/koa-webpack/index.ts +0 -71
- package/server/webpack/koa-webpack/middleware.ts +0 -47
- package/server/webpack/koa-webpack/validate.ts +0 -27
@@ -13,26 +13,52 @@ try {
|
|
13
13
|
|
14
14
|
const dataSources: { [name: string]: DataSource } = {}
|
15
15
|
|
16
|
+
/**
|
17
|
+
* Returns the specified DataSource by name.
|
18
|
+
* @param {string} name - The name of the DataSource.
|
19
|
+
* @returns {DataSource} - The DataSource with the specified name.
|
20
|
+
*/
|
16
21
|
export function getDataSource(name?: string): DataSource {
|
17
22
|
return dataSources[name || 'default']
|
18
23
|
}
|
19
24
|
|
25
|
+
/**
|
26
|
+
* Adds a new DataSource with the specified name.
|
27
|
+
* @param {string} name - The name of the DataSource to add.
|
28
|
+
* @param {DataSource} dataSource - The DataSource to add.
|
29
|
+
*/
|
20
30
|
export function addDataSource(name: string, dataSource: DataSource) {
|
21
31
|
dataSources[name] = dataSource
|
22
32
|
}
|
23
33
|
|
34
|
+
/**
|
35
|
+
* Removes a DataSource with the specified name.
|
36
|
+
* @param {string} name - The name of the DataSource to remove.
|
37
|
+
*/
|
24
38
|
export function removeDataSource(name: string) {
|
25
39
|
delete dataSources[name]
|
26
40
|
}
|
27
41
|
|
42
|
+
/**
|
43
|
+
* Returns an array of all registered DataSource names.
|
44
|
+
* @returns {string[]} - An array of DataSource names.
|
45
|
+
*/
|
28
46
|
export function getDataSourceNames() {
|
29
47
|
return Object.keys(dataSources)
|
30
48
|
}
|
31
49
|
|
50
|
+
/**
|
51
|
+
* Returns a repository for the specified entity.
|
52
|
+
* @param {EntityTarget<X>} target - The target entity for which to get the repository.
|
53
|
+
* @returns {Repository<X>} - The repository for the specified entity.
|
54
|
+
*/
|
32
55
|
export function getRepository<X>(target: EntityTarget<X>): Repository<X> {
|
33
56
|
return getDataSource('default').getRepository<X>(target)
|
34
57
|
}
|
35
58
|
|
59
|
+
/**
|
60
|
+
* Initializes the database connections and data sources.
|
61
|
+
*/
|
36
62
|
export const databaseInitializer = async () => {
|
37
63
|
try {
|
38
64
|
const readConnectionConfig = config.get('ormconfig')
|
@@ -2,11 +2,35 @@ import camelCase from 'lodash/camelCase'
|
|
2
2
|
import Transport from 'winston-transport'
|
3
3
|
import { pubsub } from './pubsub'
|
4
4
|
|
5
|
+
/**
|
6
|
+
* PubSubLogTransport is a custom Winston transport that publishes log messages to a GraphQL Pub/Sub topic.
|
7
|
+
*/
|
5
8
|
export class PubSubLogTransport extends Transport {
|
9
|
+
/**
|
10
|
+
* The source object providing the log messages.
|
11
|
+
* @type {object}
|
12
|
+
*/
|
6
13
|
source: object
|
14
|
+
|
15
|
+
/**
|
16
|
+
* The Pub/Sub topic to which log messages will be published.
|
17
|
+
* @type {string}
|
18
|
+
*/
|
7
19
|
topic: string
|
20
|
+
|
21
|
+
/**
|
22
|
+
* The name of the field resolver for log messages.
|
23
|
+
* @type {string}
|
24
|
+
*/
|
8
25
|
resolver: string /* field resolver name */
|
9
26
|
|
27
|
+
/**
|
28
|
+
* Creates an instance of PubSubLogTransport.
|
29
|
+
* @param {object} opts - Options for configuring the transport.
|
30
|
+
* @param {string} opts.topic - The Pub/Sub topic to which log messages will be published.
|
31
|
+
* @param {object} opts.source - The source object providing the log messages.
|
32
|
+
* @param {string} opts.resolver - The name of the field resolver for log messages (default: derived from the topic).
|
33
|
+
*/
|
10
34
|
constructor(opts) {
|
11
35
|
super(opts)
|
12
36
|
|
@@ -15,6 +39,11 @@ export class PubSubLogTransport extends Transport {
|
|
15
39
|
this.resolver = opts.resolver || camelCase(this.topic)
|
16
40
|
}
|
17
41
|
|
42
|
+
/**
|
43
|
+
* Publishes a log message to the configured Pub/Sub topic.
|
44
|
+
* @param {object} info - The log message information.
|
45
|
+
* @param {Function} callback - The callback function to be called after publishing the message.
|
46
|
+
*/
|
18
47
|
log(info, callback) {
|
19
48
|
setImmediate(() => {
|
20
49
|
pubsub.publish(this.topic, {
|
package/server/pubsub.ts
CHANGED
@@ -1,17 +1,27 @@
|
|
1
|
+
/**
|
2
|
+
* @module pubsub
|
3
|
+
* @description
|
4
|
+
* This module provides a Pub/Sub (Publish/Subscribe) mechanism for handling messages and events.
|
5
|
+
* Developers can use various middleware options such as MQTT, Redis, Redis Cluster, or Kafka
|
6
|
+
* to implement Pub/Sub functionality.
|
7
|
+
*/
|
8
|
+
|
1
9
|
import { MQTTPubSub } from 'graphql-mqtt-subscriptions'
|
2
10
|
import { RedisPubSub } from 'graphql-redis-subscriptions'
|
3
|
-
import {
|
11
|
+
import { createPubSub } from 'graphql-yoga'
|
4
12
|
import Redis from 'ioredis'
|
5
13
|
import { connect } from 'mqtt'
|
6
14
|
|
7
15
|
import { config, logger } from '@things-factory/env'
|
16
|
+
import { PubSub } from 'type-graphql'
|
8
17
|
|
9
18
|
const { middleware, host, port, nodes, topic, options } = config.get('pubsub', {})
|
10
19
|
|
11
|
-
let pubsub:
|
20
|
+
let pubsub: PubSub
|
12
21
|
|
13
22
|
switch (middleware) {
|
14
23
|
case 'mqtt':
|
24
|
+
//@ts-ignore
|
15
25
|
pubsub = new MQTTPubSub({
|
16
26
|
client: connect('mqtt://' + host, {
|
17
27
|
reconnectPeriod: 1000,
|
@@ -29,6 +39,7 @@ switch (middleware) {
|
|
29
39
|
},
|
30
40
|
...options
|
31
41
|
}
|
42
|
+
//@ts-ignore
|
32
43
|
pubsub = new RedisPubSub({
|
33
44
|
publisher: new Redis(redisOption),
|
34
45
|
subscriber: new Redis(redisOption)
|
@@ -36,6 +47,7 @@ switch (middleware) {
|
|
36
47
|
break
|
37
48
|
case 'redisCluster':
|
38
49
|
const cluster = new Redis.Cluster(nodes, options)
|
50
|
+
//@ts-ignore
|
39
51
|
pubsub = new RedisPubSub({
|
40
52
|
publisher: cluster,
|
41
53
|
subscriber: cluster
|
@@ -59,14 +71,16 @@ switch (middleware) {
|
|
59
71
|
}
|
60
72
|
break
|
61
73
|
default:
|
62
|
-
pubsub =
|
74
|
+
pubsub = createPubSub()
|
63
75
|
break
|
64
76
|
}
|
65
77
|
|
66
78
|
// kafka pubsub keeps connection and app port with 'ctrl+c' termination.
|
67
79
|
const exitHandler = async evt => {
|
80
|
+
//@ts-ignore
|
68
81
|
if (pubsub.close) {
|
69
82
|
try {
|
83
|
+
//@ts-ignore
|
70
84
|
await pubsub.close()
|
71
85
|
} catch (err) {
|
72
86
|
logger.error(err)
|
package/server/schema.ts
CHANGED
@@ -6,9 +6,14 @@ import { typeDefs as scalarTypeDefs, resolvers as scalarResolvers } from 'graphq
|
|
6
6
|
import { mergeSchemas } from '@graphql-tools/schema'
|
7
7
|
import { loader, orderedModuleNames } from '@things-factory/env'
|
8
8
|
import { deepMerge } from '@things-factory/utils'
|
9
|
+
import { pubsub } from './pubsub'
|
9
10
|
|
10
11
|
const path = require('path')
|
11
12
|
|
13
|
+
/**
|
14
|
+
* Generates and returns a GraphQL schema by merging schemas and resolvers from various modules.
|
15
|
+
* @returns {GraphQLSchema} The merged GraphQL schema.
|
16
|
+
*/
|
12
17
|
export async function schema() {
|
13
18
|
const schemas = orderedModuleNames
|
14
19
|
.map(dep => loader(dep).schema)
|
@@ -16,12 +21,7 @@ export async function schema() {
|
|
16
21
|
.reduce(
|
17
22
|
(sum, schema) => {
|
18
23
|
const { typeDefs, resolvers, resolverClasses, directives } = sum
|
19
|
-
let {
|
20
|
-
typeDefs: sTypeDefs = {},
|
21
|
-
resolvers: sResolvers = {},
|
22
|
-
resolverClasses: sResolverClasses = [],
|
23
|
-
directives: sDirectives = {}
|
24
|
-
} = schema
|
24
|
+
let { typeDefs: sTypeDefs = {}, resolvers: sResolvers = {}, resolverClasses: sResolverClasses = [], directives: sDirectives = {} } = schema
|
25
25
|
|
26
26
|
return {
|
27
27
|
typeDefs: deepMerge(typeDefs, sTypeDefs),
|
@@ -60,12 +60,8 @@ export async function schema() {
|
|
60
60
|
|
61
61
|
const defs = {
|
62
62
|
query: queries.length > 0 ? ['type Query {', ...queries, '}'].join('\n') : 'type Query { _ : Boolean }',
|
63
|
-
mutation:
|
64
|
-
|
65
|
-
subscription:
|
66
|
-
subscriptions.length > 0
|
67
|
-
? ['type Subscription {', ...subscriptions, '}'].join('\n')
|
68
|
-
: 'type Subscription { _ : Boolean }'
|
63
|
+
mutation: mutations.length > 0 ? ['type Mutation {', ...mutations, '}'].join('\n') : 'type Mutation { _ : Boolean }',
|
64
|
+
subscription: subscriptions.length > 0 ? ['type Subscription {', ...subscriptions, '}'].join('\n') : 'type Subscription { _ : Boolean }'
|
69
65
|
}
|
70
66
|
|
71
67
|
typeDefs = [
|
@@ -146,6 +142,7 @@ export async function schema() {
|
|
146
142
|
var merged = mergeSchemas({
|
147
143
|
schemas: [
|
148
144
|
await buildSchema({
|
145
|
+
pubSub: pubsub,
|
149
146
|
resolvers: schemas.resolverClasses,
|
150
147
|
// automatically create `schema.gql` file with schema definition
|
151
148
|
// in project's working directory
|
package/server/server-dev.ts
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
// ts-import-sorter: disable
|
2
2
|
|
3
|
-
/* following
|
3
|
+
/* following 7 lines should be located in top of the file */
|
4
|
+
const OS = require('os')
|
5
|
+
process.env.UV_THREADPOOL_SIZE = OS.cpus().length
|
6
|
+
|
7
|
+
console.log('UV_THREADPOOL_SIZE', process.env.UV_THREADPOOL_SIZE)
|
8
|
+
|
4
9
|
process.env.NODE_ENV = 'development'
|
5
10
|
process.setMaxListeners(0)
|
6
11
|
|
@@ -29,13 +34,7 @@ import { initLicense, checkValidity } from '@things-factory/operato-license-chec
|
|
29
34
|
|
30
35
|
import { GraphqlLocalClient } from './graphql-local-client'
|
31
36
|
import { databaseInitializer } from './initializers/database'
|
32
|
-
import {
|
33
|
-
domainPrivateRouter,
|
34
|
-
domainPublicRouter,
|
35
|
-
globalPrivateRouter,
|
36
|
-
globalPublicRouter,
|
37
|
-
graphqlRouter
|
38
|
-
} from './routers'
|
37
|
+
import { domainPrivateRouter, domainPublicRouter, globalPrivateRouter, globalPublicRouter, graphqlRouter } from './routers'
|
39
38
|
import { schema } from './schema'
|
40
39
|
import { Domain } from './service'
|
41
40
|
import { EntityManager } from 'typeorm'
|
package/server/server.ts
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
// ts-import-sorter: disable
|
2
2
|
|
3
|
-
/* following
|
3
|
+
/* following 5 lines should be located in top of the file */
|
4
|
+
const OS = require('os')
|
5
|
+
process.env.UV_THREADPOOL_SIZE = OS.cpus().length
|
6
|
+
|
7
|
+
console.log('UV_THREADPOOL_SIZE', process.env.UV_THREADPOOL_SIZE)
|
8
|
+
|
4
9
|
process.env.NODE_ENV = 'production'
|
5
10
|
process.setMaxListeners(0)
|
6
11
|
|
@@ -28,13 +33,7 @@ import { initLicense, checkValidity } from '@things-factory/operato-license-chec
|
|
28
33
|
|
29
34
|
import { GraphqlLocalClient } from './graphql-local-client'
|
30
35
|
import { databaseInitializer } from './initializers/database'
|
31
|
-
import {
|
32
|
-
domainPrivateRouter,
|
33
|
-
domainPublicRouter,
|
34
|
-
globalPrivateRouter,
|
35
|
-
globalPublicRouter,
|
36
|
-
graphqlRouter
|
37
|
-
} from './routers'
|
36
|
+
import { domainPrivateRouter, domainPublicRouter, globalPrivateRouter, globalPublicRouter, graphqlRouter } from './routers'
|
38
37
|
import { schema } from './schema'
|
39
38
|
import { domainMiddleware } from './middlewares'
|
40
39
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { filter, pipe } from 'graphql-yoga'
|
2
2
|
import { Arg, Resolver, Root, Subscription } from 'type-graphql'
|
3
3
|
|
4
4
|
import { pubsub } from '../../pubsub'
|
@@ -7,7 +7,7 @@ import { Data } from './data-types'
|
|
7
7
|
@Resolver()
|
8
8
|
export class DataResolver {
|
9
9
|
@Subscription({
|
10
|
-
subscribe: (
|
10
|
+
subscribe: ({ args, context, info }) => {
|
11
11
|
const { domain, user } = context.state
|
12
12
|
const { tag } = args
|
13
13
|
const subdomain = domain?.subdomain
|
@@ -21,22 +21,13 @@ export class DataResolver {
|
|
21
21
|
throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
|
22
22
|
}
|
23
23
|
|
24
|
-
return
|
25
|
-
|
26
|
-
(payload
|
27
|
-
const { domain: pdomain, tag } = payload.data
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
}
|
32
|
-
|
33
|
-
if (subdomain !== pdomain?.subdomain) {
|
34
|
-
return false
|
35
|
-
}
|
36
|
-
|
37
|
-
return true
|
38
|
-
}
|
39
|
-
)(_, args, context, info)
|
24
|
+
return pipe(
|
25
|
+
pubsub.subscribe('data'),
|
26
|
+
filter((payload: { data: Data }) => {
|
27
|
+
const { domain: pdomain, tag: ptag, data } = payload.data
|
28
|
+
return tag === ptag && subdomain === pdomain?.subdomain
|
29
|
+
})
|
30
|
+
)
|
40
31
|
}
|
41
32
|
})
|
42
33
|
data(@Root() payload: { data: Data }, @Arg('tag') tag: string): Data {
|
@@ -8,11 +8,32 @@ const KEY_LENGTH = 32
|
|
8
8
|
const SALT_LENGTH = 16
|
9
9
|
const IV_LENGTH = 16
|
10
10
|
|
11
|
+
/**
|
12
|
+
* ValueTransformer object for encrypting and decrypting database entity field values.
|
13
|
+
* Used in TypeORM entities to encrypt field values before storing them in the database
|
14
|
+
* and decrypt values when retrieving them from the database.
|
15
|
+
*/
|
11
16
|
export const encryptTransformer: ValueTransformer = {
|
17
|
+
/**
|
18
|
+
* Encrypts the entity field value before storing it in the database.
|
19
|
+
* @param {string} entityValue - Unencrypted entity field value
|
20
|
+
* @returns {string} - Encrypted string
|
21
|
+
*/
|
12
22
|
to: (entityValue: string) => encrypt(entityValue), // DB에 저장하기 전에 암호화
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Decrypts the encrypted database value when retrieving it from the database.
|
26
|
+
* @param {string} databaseValue - Encrypted database field value
|
27
|
+
* @returns {string} - Decrypted string
|
28
|
+
*/
|
13
29
|
from: (databaseValue: string) => decrypt(databaseValue) // DB에서 값을 가져올 때 복호화
|
14
30
|
}
|
15
31
|
|
32
|
+
/**
|
33
|
+
* Encrypts the given text using the AES-256-CBC algorithm.
|
34
|
+
* @param {string} text - Text to encrypt
|
35
|
+
* @returns {string} - Encrypted string
|
36
|
+
*/
|
16
37
|
function encrypt(text: string): string {
|
17
38
|
if (!text) {
|
18
39
|
return null
|
@@ -25,6 +46,11 @@ function encrypt(text: string): string {
|
|
25
46
|
return `${iv.toString('hex')}:${encrypted.toString('hex')}`
|
26
47
|
}
|
27
48
|
|
49
|
+
/**
|
50
|
+
* Decrypts the given encrypted text.
|
51
|
+
* @param {string} text - Encrypted text to decrypt
|
52
|
+
* @returns {string} - Decrypted string
|
53
|
+
*/
|
28
54
|
function decrypt(text: string): string {
|
29
55
|
if (!text) {
|
30
56
|
return null
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { ValueTransformer } from 'typeorm'
|
2
|
+
import json5 from 'json5'
|
3
|
+
|
4
|
+
export const json5Transformer: ValueTransformer = {
|
5
|
+
/**
|
6
|
+
* Converts the entity's value to a JSON5 string before storing it in the database.
|
7
|
+
* @param {any} entityValue - The unencrypted entity field value.
|
8
|
+
* @returns {string} - The stringified JSON5 representation of the entityValue.
|
9
|
+
*/
|
10
|
+
to(entityValue: any) {
|
11
|
+
return json5.stringify(entityValue)
|
12
|
+
},
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Converts a JSON5 string from the database back into its original type when retrieving it.
|
16
|
+
* @param {string} databaseValue - The JSON5 string stored in the database.
|
17
|
+
* @returns {any} - The original type of the entityValue, parsed from the JSON5 string.
|
18
|
+
*/
|
19
|
+
from(databaseValue: string) {
|
20
|
+
try {
|
21
|
+
return json5.parse(databaseValue)
|
22
|
+
} finally {
|
23
|
+
return databaseValue
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { ValueTransformer } from 'typeorm'
|
2
|
+
|
3
|
+
/**
|
4
|
+
* ValueTransformer object for rounding floating point values.
|
5
|
+
*/
|
6
|
+
export const roundTransformer: ValueTransformer = {
|
7
|
+
/**
|
8
|
+
* Rounds the entity field value before storing it in the database.
|
9
|
+
* @param {number | null} value - Floating point value to round or null
|
10
|
+
* @returns {number | null} - Rounded number or null
|
11
|
+
*/
|
12
|
+
to: (value: number | null) => (value !== null && !isNaN(value) ? Math.round(value * 100) / 100 : null),
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Returns the entity field value as it is without any transformation when reading from the database.
|
16
|
+
* @param {number} value - Number value read from the database
|
17
|
+
* @returns {number} - The number value as is
|
18
|
+
*/
|
19
|
+
from: (value: number) => value
|
20
|
+
}
|
@@ -1,13 +1,17 @@
|
|
1
1
|
import _ from 'lodash'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
/**
|
4
|
+
* Generates and returns a condition clause based on the provided parameters.
|
5
|
+
*
|
6
|
+
* @param alias {string} Alias or table name of the entity.
|
7
|
+
* @param fieldName {string} Field or column name.
|
8
|
+
* @param operator {string} Comparison operator.
|
9
|
+
* @param value {any} Value or an array of values to compare.
|
10
|
+
* @param relation {boolean | string} Indicates if it's a related field or the name of the relation (optional).
|
11
|
+
* @param seq {number} Integer representing the order of condition generation (internal use).
|
12
|
+
* @returns {Object} An object containing the generated condition clause and parameters.
|
13
|
+
*/
|
14
|
+
export const buildCondition = function (alias: string, fieldName: string, operator: string, value: any, relation: boolean | string, seq: number) {
|
11
15
|
seq++
|
12
16
|
|
13
17
|
fieldName = _.snakeCase(fieldName)
|
@@ -11,6 +11,13 @@ const protocol: string = config.get('protocol')
|
|
11
11
|
const fixed = config.get('subdomain')
|
12
12
|
const subdomainOffset = config.getNumber('subdomainOffset', 2)
|
13
13
|
|
14
|
+
/**
|
15
|
+
* Creates a URL based on the given context and path.
|
16
|
+
*
|
17
|
+
* @param context {Object} An object containing the current request context information.
|
18
|
+
* @param path {string} The path to be added to the created URL (optional).
|
19
|
+
* @returns {URL} The generated URL object.
|
20
|
+
*/
|
14
21
|
export function getUrlFromContext(context, path = '') {
|
15
22
|
const { method, href, host, header } = context
|
16
23
|
const { referer } = header || {}
|
@@ -44,12 +51,24 @@ export function getUrlFromContext(context, path = '') {
|
|
44
51
|
return url
|
45
52
|
}
|
46
53
|
|
54
|
+
/**
|
55
|
+
* Extracts subdomains from the Host header.
|
56
|
+
*
|
57
|
+
* @param context {Object} An object containing the current request context information.
|
58
|
+
* @returns {string[]} An array of extracted subdomains.
|
59
|
+
*/
|
47
60
|
function getSubdomainsFromHost(context: any) {
|
48
61
|
const { request } = context
|
49
62
|
var subdomains = request.headers.host.split('.').reverse()
|
50
63
|
return subdomains.slice(subdomainOffset)
|
51
64
|
}
|
52
65
|
|
66
|
+
/**
|
67
|
+
* Extracts a subdomain from the path.
|
68
|
+
*
|
69
|
+
* @param context {Object} An object containing the current request context information.
|
70
|
+
* @returns {string} The extracted subdomain.
|
71
|
+
*/
|
53
72
|
function getSubdomainFromPath(context: any) {
|
54
73
|
var { path } = context
|
55
74
|
|
@@ -68,16 +87,34 @@ function getSubdomainFromPath(context: any) {
|
|
68
87
|
}
|
69
88
|
}
|
70
89
|
|
90
|
+
/**
|
91
|
+
* Extracts a subdomain based on virtual host.
|
92
|
+
*
|
93
|
+
* @param context {Object} An object containing the current request context information.
|
94
|
+
* @returns {string} The extracted subdomain.
|
95
|
+
*/
|
71
96
|
function getSubdomainFromVhost(context: any) {
|
72
97
|
const subdomain = (context.subdomains || getSubdomainsFromHost(context)).slice(-1)[0]
|
73
98
|
|
74
99
|
return subdomain
|
75
100
|
}
|
76
101
|
|
102
|
+
/**
|
103
|
+
* Extracts a subdomain from the URL context.
|
104
|
+
*
|
105
|
+
* @param context {Object} An object containing the current request context information.
|
106
|
+
* @returns {string} The extracted subdomain.
|
107
|
+
*/
|
77
108
|
function getSubdomainFromURL(context) {
|
78
109
|
return fixed || (useVirtualHostBasedDomain ? getSubdomainFromVhost(context) : getSubdomainFromPath(context))
|
79
110
|
}
|
80
111
|
|
112
|
+
/**
|
113
|
+
* Asynchronously searches for a domain object based on the URL context.
|
114
|
+
*
|
115
|
+
* @param context {Object} An object containing the current request context information.
|
116
|
+
* @returns {Promise<Domain>} A promise that resolves to the domain object.
|
117
|
+
*/
|
81
118
|
export async function getDomainFromURL(context: any): Promise<Domain> {
|
82
119
|
const { header } = context
|
83
120
|
|
@@ -88,16 +125,36 @@ export async function getDomainFromURL(context: any): Promise<Domain> {
|
|
88
125
|
}
|
89
126
|
}
|
90
127
|
|
128
|
+
/**
|
129
|
+
* Extracts the cookie domain from the hostname.
|
130
|
+
*
|
131
|
+
* @param hostname {string} The hostname.
|
132
|
+
* @returns {string} The extracted cookie domain.
|
133
|
+
*/
|
91
134
|
export function getCookieDomainFromHostname(hostname) {
|
92
135
|
if (useVirtualHostBasedDomain) {
|
93
136
|
return hostname.split('.').slice(-subdomainOffset).join('.')
|
94
137
|
}
|
95
138
|
}
|
96
139
|
|
140
|
+
/**
|
141
|
+
* Generates a context path based on the subdomain.
|
142
|
+
*
|
143
|
+
* @param subdomain {string} The subdomain.
|
144
|
+
* @returns {string} The generated context path.
|
145
|
+
*/
|
97
146
|
export function getContextPath(subdomain) {
|
98
147
|
return fixed || useVirtualHostBasedDomain ? '' : '/domain/' + subdomain
|
99
148
|
}
|
100
149
|
|
150
|
+
/**
|
151
|
+
* Generates a redirection path considering the subdomain.
|
152
|
+
*
|
153
|
+
* @param context {Object} An object containing the current request context information.
|
154
|
+
* @param subdomain {string} The subdomain.
|
155
|
+
* @param redirectTo {string} The path to redirect to (optional).
|
156
|
+
* @returns {string} The generated redirection path.
|
157
|
+
*/
|
101
158
|
export function getRedirectSubdomainPath(context, subdomain, redirectTo = '/') {
|
102
159
|
if (fixed) {
|
103
160
|
return redirectTo || '/'
|
@@ -127,6 +184,13 @@ export function getRedirectSubdomainPath(context, subdomain, redirectTo = '/') {
|
|
127
184
|
return parsed.toString()
|
128
185
|
}
|
129
186
|
|
187
|
+
/**
|
188
|
+
* Finds a subdomain from the given path.
|
189
|
+
*
|
190
|
+
* @param context {Object} An object containing the current request context information.
|
191
|
+
* @param path {string} The path to search in.
|
192
|
+
* @returns {string} The found subdomain.
|
193
|
+
*/
|
130
194
|
export function findSubdomainFromPath(context, path) {
|
131
195
|
if (fixed) {
|
132
196
|
return fixed
|
@@ -143,6 +207,12 @@ export function findSubdomainFromPath(context, path) {
|
|
143
207
|
return match && match[1]
|
144
208
|
}
|
145
209
|
|
210
|
+
/**
|
211
|
+
* Generates a site root path based on the current environment.
|
212
|
+
*
|
213
|
+
* @param context {Object} An object containing the current request context information.
|
214
|
+
* @returns {string} The generated site root path.
|
215
|
+
*/
|
146
216
|
export function getSiteRootPath(context) {
|
147
217
|
if (useVirtualHostBasedDomain) {
|
148
218
|
var { protocol, host } = context
|
@@ -5,9 +5,19 @@ import { Filter, ListParam, InheritedValueType } from '../service/common-types/l
|
|
5
5
|
import { Domain } from '../service/domain/domain'
|
6
6
|
|
7
7
|
/**
|
8
|
+
* Function to create a TypeORM SelectQueryBuilder for database queries.
|
8
9
|
*
|
9
|
-
* @param options
|
10
|
-
* @
|
10
|
+
* @param options - An object containing options for querying and building.
|
11
|
+
* @param options.repository - TypeORM repository used for database operations.
|
12
|
+
* @param options.params - ListParam object for data retrieval and manipulation.
|
13
|
+
* @param [options.domain] - Optional domain object for applying domain-related filters.
|
14
|
+
* @param [options.alias] - Alias to be used in SQL queries (optional).
|
15
|
+
* @param [options.searchables] - List of searchable columns (optional).
|
16
|
+
* @param [options.filtersMap] - Mapping of filter names to their corresponding columns or relation columns (optional).
|
17
|
+
* @param [options.filtersMap.name] - Filter name.
|
18
|
+
* @param [options.filtersMap.columnName] - Name of the column where the filter is applied.
|
19
|
+
* @param [options.filtersMap.relationColumn] - If the filter is applied to a related column, the name of that relation column (optional).
|
20
|
+
* @returns {SelectQueryBuilder<Type>} - The generated SelectQueryBuilder object.
|
11
21
|
*/
|
12
22
|
export function getQueryBuilderFromListParams<Type>(options: {
|
13
23
|
repository: Repository<Type>
|
@@ -29,10 +39,7 @@ export function getQueryBuilderFromListParams<Type>(options: {
|
|
29
39
|
return false
|
30
40
|
}
|
31
41
|
if (filter.operator.toLowerCase().includes('like') && (!searchables || !searchables.includes(filter.name))) {
|
32
|
-
console.warn(
|
33
|
-
'"searchables" setting is required for like searches with a heavy database query load',
|
34
|
-
filter.name
|
35
|
-
)
|
42
|
+
console.warn('"searchables" setting is required for like searches with a heavy database query load', filter.name)
|
36
43
|
return false
|
37
44
|
}
|
38
45
|
return true
|
@@ -44,10 +51,7 @@ export function getQueryBuilderFromListParams<Type>(options: {
|
|
44
51
|
return false
|
45
52
|
}
|
46
53
|
if (!searchables.includes(filter.name)) {
|
47
|
-
console.warn(
|
48
|
-
'"searchables" setting is required for like searches with a heavy database query load',
|
49
|
-
filter.name
|
50
|
-
)
|
54
|
+
console.warn('"searchables" setting is required for like searches with a heavy database query load', filter.name)
|
51
55
|
return false
|
52
56
|
}
|
53
57
|
return true
|
@@ -107,6 +111,16 @@ export function getQueryBuilderFromListParams<Type>(options: {
|
|
107
111
|
return selectQueryBuilder
|
108
112
|
}
|
109
113
|
|
114
|
+
/**
|
115
|
+
* Add a condition to a TypeORM SelectQueryBuilder based on the provided filter and mapping options.
|
116
|
+
*
|
117
|
+
* @param {EntityMetadata} metadata - The EntityMetadata for the TypeORM entity.
|
118
|
+
* @param {SelectQueryBuilder<Type>} selectQueryBuilder - The SelectQueryBuilder to add the condition to.
|
119
|
+
* @param {WhereExpressionBuilder} whereExpressionBuilder - The WhereExpressionBuilder to build the condition.
|
120
|
+
* @param {Filter} filter - The filter object containing the filter conditions.
|
121
|
+
* @param {Object} filtersMap - A mapping of filter names to column names and relation column names.
|
122
|
+
* @param {boolean} andCondition - Flag indicating whether to use "AND" or "OR" for combining conditions.
|
123
|
+
*/
|
110
124
|
function addCondition<T>(
|
111
125
|
metadata: EntityMetadata,
|
112
126
|
selectQueryBuilder: SelectQueryBuilder<T>,
|
@@ -172,9 +186,7 @@ function addCondition<T>(
|
|
172
186
|
if (relationIdMeta) {
|
173
187
|
columnMeta = relationIdMeta.relation.joinColumns[0]
|
174
188
|
} else {
|
175
|
-
columnName
|
176
|
-
? console.warn(`columnName "${columnName}" in filtersMap for "${name}" is not a column`)
|
177
|
-
: console.warn(`name "${name}" is not a column`)
|
189
|
+
columnName ? console.warn(`columnName "${columnName}" in filtersMap for "${name}" is not a column`) : console.warn(`name "${name}" is not a column`)
|
178
190
|
}
|
179
191
|
} else {
|
180
192
|
var relation = columnMeta.relationMetadata
|
@@ -322,8 +334,6 @@ function addCondition<T>(
|
|
322
334
|
whereExpressionBuilder.orWhere(clause, parameters)
|
323
335
|
}
|
324
336
|
} else {
|
325
|
-
andCondition
|
326
|
-
? whereExpressionBuilder.andWhere(clause, parameters)
|
327
|
-
: whereExpressionBuilder.orWhere(clause, parameters)
|
337
|
+
andCondition ? whereExpressionBuilder.andWhere(clause, parameters) : whereExpressionBuilder.orWhere(clause, parameters)
|
328
338
|
}
|
329
339
|
}
|