@cuboapp/api-backend 1.0.7 → 1.0.9
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-lock.json +512 -0
- package/package.json +7 -10
- package/src/constants/index.ts +73 -2
- package/src/helpers/convert.ts +24 -49
- package/src/helpers/data.ts +3 -4
- package/src/helpers/index.ts +189 -47
- package/src/helpers/withes.ts +4 -4
- package/src/index.ts +45 -103
- package/src/types/basic.ts +1 -1
- package/src/types/db.ts +3 -1
- package/pnpm-lock.yaml +0 -378
- package/src/constants/backend.ts +0 -74
- package/src/constants/base.ts +0 -11
- package/src/helpers/entities.ts +0 -30
- package/src/helpers/query.ts +0 -155
- package/src/helpers/users.ts +0 -37
- package/src/utils/index.ts +0 -128
package/src/helpers/convert.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { CuboApiEntitiesMap, CuboEntity, CuboEntityField } from '@cuboapp/types'
|
|
2
|
-
import get from '
|
|
3
|
-
import set from 'lodash-es/set'
|
|
4
|
-
import unset from 'lodash-es/unset'
|
|
2
|
+
import { get, set, unset } from '@cuboapp/utils'
|
|
5
3
|
|
|
6
|
-
import { CUBO_CRUD_DEFAULT_FIELDS
|
|
4
|
+
import { CUBO_CRUD_DEFAULT_FIELDS } from '../constants'
|
|
7
5
|
import { CuboCrudFindQuery, CuboCrudRequest } from '../types'
|
|
8
6
|
|
|
7
|
+
import { CUBO_ENTITY_FIELD_TYPE } from '@cuboapp/constants'
|
|
9
8
|
import { ApiHelpers } from '.'
|
|
10
9
|
|
|
11
10
|
export class ApiHelpersConvert<T extends CuboApiEntitiesMap<T>> {
|
|
@@ -42,58 +41,34 @@ export class ApiHelpersConvert<T extends CuboApiEntitiesMap<T>> {
|
|
|
42
41
|
|
|
43
42
|
const rowValue = get(row, initialValueKey, undefined)
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
if (!withEl.entity && withEl.entity.alias === 'users') {
|
|
47
|
-
userFieldsPrepared.push(withEl.full_key)
|
|
48
|
-
|
|
49
|
-
switch (rowValue) {
|
|
50
|
-
case null:
|
|
51
|
-
case undefined:
|
|
52
|
-
set(row, withEl.full_key, null)
|
|
53
|
-
break
|
|
54
|
-
case 0:
|
|
55
|
-
set(row, withEl.full_key, { id: 0, name: this.helpers.api.account.name })
|
|
56
|
-
break
|
|
57
|
-
default:
|
|
58
|
-
const user = await this.helpers.users.getById(rowValue)
|
|
59
|
-
|
|
60
|
-
set(
|
|
61
|
-
row,
|
|
62
|
-
withEl.full_key,
|
|
63
|
-
user ? { id: user.id, name: user.name, email: user.email } : { id: rowValue, name: `User #${rowValue}` }
|
|
64
|
-
)
|
|
65
|
-
break
|
|
66
|
-
}
|
|
67
|
-
} else {
|
|
68
|
-
const rowValueEmpty = [0, '0', '', null, 'null'].includes(rowValue)
|
|
44
|
+
const rowValueEmpty = [0, '0', '', null, 'null'].includes(rowValue)
|
|
69
45
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
46
|
+
if (rowValueEmpty) {
|
|
47
|
+
set(row, withEl.full_key, null)
|
|
48
|
+
}
|
|
73
49
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
50
|
+
if (toPrepare[withEl.key]) {
|
|
51
|
+
delete toPrepare[withEl.key]
|
|
52
|
+
}
|
|
77
53
|
|
|
78
|
-
|
|
54
|
+
// console.log('rowValue', withEl.full_key, { rowValueEmpty, rowValue })
|
|
79
55
|
|
|
80
|
-
|
|
81
|
-
|
|
56
|
+
for (const field of [...withEl.entity.fields, ...CUBO_CRUD_DEFAULT_FIELDS]) {
|
|
57
|
+
const fieldValueKey = withEl.table_name.toLowerCase() + '_' + field.alias
|
|
82
58
|
|
|
83
|
-
|
|
59
|
+
// console.log('add field', field.alias, rowValueEmpty)
|
|
84
60
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
61
|
+
if (!rowValueEmpty && !usersDefaultFields.includes(field.alias)) {
|
|
62
|
+
const fieldKeyPath = withEl.full_key + '.' + field.alias
|
|
63
|
+
const rowRelationValue = get(row, fieldValueKey, undefined)
|
|
88
64
|
|
|
89
|
-
|
|
65
|
+
set(row, fieldKeyPath, this.prepareFieldValue(field, rowRelationValue))
|
|
90
66
|
|
|
91
|
-
|
|
92
|
-
|
|
67
|
+
toPrepare[fieldKeyPath] = field
|
|
68
|
+
}
|
|
93
69
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
70
|
+
if (field.alias !== 'id') {
|
|
71
|
+
toRemove.push(fieldValueKey)
|
|
97
72
|
}
|
|
98
73
|
}
|
|
99
74
|
}
|
|
@@ -113,8 +88,8 @@ export class ApiHelpersConvert<T extends CuboApiEntitiesMap<T>> {
|
|
|
113
88
|
return row
|
|
114
89
|
}
|
|
115
90
|
|
|
116
|
-
private prepareFieldValue(field: Pick<CuboEntityField, '
|
|
117
|
-
switch (field.
|
|
91
|
+
private prepareFieldValue(field: Pick<CuboEntityField, 'type' | 'alias' | 'extra'>, value: any) {
|
|
92
|
+
switch (field.type) {
|
|
118
93
|
case CUBO_ENTITY_FIELD_TYPE.BOOLEAN:
|
|
119
94
|
return value !== undefined ? (['true', true].includes(value) ? true : false) : null
|
|
120
95
|
case CUBO_ENTITY_FIELD_TYPE.DATE:
|
package/src/helpers/data.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import { CUBO_ENTITY_FIELD_TYPE } from '@cuboapp/constants'
|
|
1
2
|
import { CuboApiEntitiesMap, CuboEntityField } from '@cuboapp/types'
|
|
2
|
-
import keyBy from '
|
|
3
|
-
|
|
4
|
-
import { CUBO_ENTITY_FIELD_TYPE } from '../constants'
|
|
3
|
+
import { keyBy } from '@cuboapp/utils'
|
|
5
4
|
|
|
6
5
|
import { ApiHelpers } from '.'
|
|
7
6
|
|
|
@@ -43,7 +42,7 @@ export class ApiHelpersData<T extends CuboApiEntitiesMap<T>> {
|
|
|
43
42
|
const value = dto[key]
|
|
44
43
|
const tval = typeof value
|
|
45
44
|
|
|
46
|
-
switch (fieldsByAlias[key].
|
|
45
|
+
switch (fieldsByAlias[key].type) {
|
|
47
46
|
case CUBO_ENTITY_FIELD_TYPE.TEXT:
|
|
48
47
|
{
|
|
49
48
|
if (value === null) {
|
package/src/helpers/index.ts
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import { CuboBackendApi } from '../..'
|
|
6
|
-
import {
|
|
1
|
+
import { CUBO_ENTITY_FIELD_TYPE } from '@cuboapp/constants'
|
|
2
|
+
import { Database, createDatabase, type Options } from '@cuboapp/database'
|
|
3
|
+
import { CuboApiEntitiesMap, CuboEntity, CuboEntityField, CuboEntityFieldExtra, CuboEntityFieldType } from '@cuboapp/types'
|
|
4
|
+
|
|
5
|
+
import { CuboBackendApi, CuboBackendApiDbConnectionType, CuboCrudFindQuery, CuboCrudRequest } from '../..'
|
|
6
|
+
import {
|
|
7
|
+
CUBO_CRUD_DEFAULT_FIELDS,
|
|
8
|
+
CUBO_CRUD_DEFAULT_PAGE_LIMIT,
|
|
9
|
+
CUBO_CRUD_MAX_PAGE_LIMIT,
|
|
10
|
+
CUBO_CRUD_QUERY_CONDITION,
|
|
11
|
+
CUBO_CRUD_QUERY_KEY_REGEX,
|
|
12
|
+
CUBO_CRUD_QUERY_SYMBOL_NOT
|
|
13
|
+
} from '../constants'
|
|
7
14
|
|
|
8
15
|
import { ApiHelpersConvert } from './convert'
|
|
9
16
|
import { ApiHelpersData } from './data'
|
|
10
|
-
|
|
11
|
-
import { ApiHelpersQuery } from './query'
|
|
12
|
-
import { ApiHelpersUsers } from './users'
|
|
17
|
+
|
|
13
18
|
import { ApiHelpersWithes } from './withes'
|
|
14
19
|
|
|
15
20
|
export class ApiHelpers<T extends CuboApiEntitiesMap<T>> {
|
|
16
21
|
constructor(public api: CuboBackendApi<T>) {}
|
|
17
22
|
|
|
18
23
|
public withes = new ApiHelpersWithes<T>(this)
|
|
19
|
-
public query = new ApiHelpersQuery<T>(this)
|
|
20
24
|
public convert = new ApiHelpersConvert<T>(this)
|
|
21
|
-
public users = new ApiHelpersUsers<T>(this)
|
|
22
|
-
public entities = new ApiHelpersEntities<T>(this)
|
|
23
25
|
public data = new ApiHelpersData<T>(this)
|
|
24
26
|
|
|
25
27
|
private cache: Record<string, any> = {}
|
|
26
28
|
private fetching: Record<string, Promise<any> | null> = {}
|
|
27
|
-
private connections: Record<
|
|
28
|
-
private connecting: Record<string, Promise<
|
|
29
|
+
private connections: Partial<Record<CuboBackendApiDbConnectionType, Database>> = {}
|
|
30
|
+
private connecting: Record<string, Promise<Database>> = {}
|
|
29
31
|
|
|
30
32
|
public getCached(alias: string, cb: (force: boolean) => Promise<any>, force = false) {
|
|
31
33
|
if (!force && this.cache[alias] !== undefined) return this.cache[alias]
|
|
@@ -49,7 +51,10 @@ export class ApiHelpers<T extends CuboApiEntitiesMap<T>> {
|
|
|
49
51
|
return this.fetching[alias]
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
public clearFieldConditionValue(
|
|
54
|
+
public clearFieldConditionValue(
|
|
55
|
+
field: CuboEntityField | { type: CuboEntityFieldType; alias: string; extra?: CuboEntityFieldExtra },
|
|
56
|
+
value: any
|
|
57
|
+
) {
|
|
53
58
|
const type = typeof value
|
|
54
59
|
|
|
55
60
|
const parts = `${value}`.split(':')
|
|
@@ -87,7 +92,7 @@ export class ApiHelpers<T extends CuboApiEntitiesMap<T>> {
|
|
|
87
92
|
throw new Error(`"${field.alias}": incorrect condition value "${value}"`)
|
|
88
93
|
}
|
|
89
94
|
|
|
90
|
-
switch (field.
|
|
95
|
+
switch (field.type) {
|
|
91
96
|
case CUBO_ENTITY_FIELD_TYPE.TEXT:
|
|
92
97
|
case CUBO_ENTITY_FIELD_TYPE.TEXTAREA:
|
|
93
98
|
switch (type) {
|
|
@@ -265,25 +270,23 @@ export class ApiHelpers<T extends CuboApiEntitiesMap<T>> {
|
|
|
265
270
|
}
|
|
266
271
|
}
|
|
267
272
|
|
|
268
|
-
public async dropConnection(
|
|
269
|
-
if (this.connections[
|
|
270
|
-
await this.connections[
|
|
271
|
-
delete this.connections[
|
|
273
|
+
public async dropConnection(type: CuboBackendApiDbConnectionType) {
|
|
274
|
+
if (this.connections[type]) {
|
|
275
|
+
await this.connections[type].disconnect()
|
|
276
|
+
delete this.connections[type]
|
|
272
277
|
}
|
|
273
278
|
}
|
|
274
279
|
|
|
275
|
-
public async getConnection(type:
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (this.connections[cacheKey]) {
|
|
279
|
-
return this.connections[cacheKey]
|
|
280
|
+
public async getConnection(type: CuboBackendApiDbConnectionType) {
|
|
281
|
+
if (this.connections[type]) {
|
|
282
|
+
return this.connections[type]
|
|
280
283
|
}
|
|
281
284
|
|
|
282
|
-
if (this.connecting[
|
|
283
|
-
return this.connecting[
|
|
285
|
+
if (this.connecting[type] !== undefined) {
|
|
286
|
+
return this.connecting[type]
|
|
284
287
|
}
|
|
285
288
|
|
|
286
|
-
this.connecting[
|
|
289
|
+
this.connecting[type] = new Promise(async (success) => {
|
|
287
290
|
let database: string = ''
|
|
288
291
|
let host: string = ''
|
|
289
292
|
let port: number = 0
|
|
@@ -293,22 +296,23 @@ export class ApiHelpers<T extends CuboApiEntitiesMap<T>> {
|
|
|
293
296
|
let dialect: string = ''
|
|
294
297
|
let dialectModule: any = undefined
|
|
295
298
|
|
|
296
|
-
if (!this.api.
|
|
299
|
+
if (!this.api.options.db.options) {
|
|
297
300
|
throw 'DB connection is not configured'
|
|
298
301
|
}
|
|
299
302
|
|
|
300
|
-
const dbConfig = this.api.
|
|
301
|
-
|
|
303
|
+
const dbConfig = this.api.options.db.options
|
|
304
|
+
|
|
305
|
+
let cfg: Options = {}
|
|
302
306
|
if (dbConfig) {
|
|
303
307
|
if (dbConfig[type]) {
|
|
304
308
|
cfg = dbConfig[type]
|
|
305
309
|
} else {
|
|
306
|
-
cfg = dbConfig as
|
|
310
|
+
cfg = dbConfig as Options
|
|
307
311
|
}
|
|
308
312
|
}
|
|
309
313
|
|
|
310
314
|
database = cfg.database as string
|
|
311
|
-
dialectModule = cfg.dialectModule
|
|
315
|
+
dialectModule = cfg.dialectModule
|
|
312
316
|
host = cfg.host as string
|
|
313
317
|
port = cfg.port as number
|
|
314
318
|
username = cfg.username as string
|
|
@@ -316,10 +320,6 @@ export class ApiHelpers<T extends CuboApiEntitiesMap<T>> {
|
|
|
316
320
|
schema = cfg.schema as string
|
|
317
321
|
dialect = cfg.dialect as string
|
|
318
322
|
|
|
319
|
-
if (!schema) {
|
|
320
|
-
schema = `account_${this.api.account.id}`
|
|
321
|
-
}
|
|
322
|
-
|
|
323
323
|
const config: Options = {
|
|
324
324
|
host,
|
|
325
325
|
port,
|
|
@@ -351,26 +351,168 @@ export class ApiHelpers<T extends CuboApiEntitiesMap<T>> {
|
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
this.connections[cacheKey] = db
|
|
357
|
-
await db.authenticate()
|
|
354
|
+
this.connections[type] = createDatabase(config)
|
|
355
|
+
await this.connections[type].connect()
|
|
358
356
|
|
|
359
357
|
if (dialect === 'postgres') {
|
|
360
|
-
await
|
|
358
|
+
await this.connections[type].connection.query(`SET schema '${schema}';`)
|
|
361
359
|
}
|
|
362
360
|
|
|
363
|
-
success(
|
|
361
|
+
success(this.connections[type])
|
|
364
362
|
|
|
365
|
-
delete this.connecting[
|
|
363
|
+
delete this.connecting[type]
|
|
366
364
|
})
|
|
367
365
|
|
|
368
|
-
return this.connecting[
|
|
366
|
+
return this.connecting[type]
|
|
369
367
|
}
|
|
370
368
|
|
|
371
|
-
public async transaction(type:
|
|
369
|
+
public async transaction(type: CuboBackendApiDbConnectionType) {
|
|
372
370
|
const db = await this.getConnection(type)
|
|
373
371
|
|
|
374
|
-
return db.transaction()
|
|
372
|
+
return db.connection.transaction()
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
public async getEntityByAlias(alias: keyof T): Promise<CuboEntity | undefined> {
|
|
376
|
+
return this.api.options.entities.find((e) => e.alias === alias)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
public async getEntityById(id: number): Promise<CuboEntity | undefined> {
|
|
380
|
+
return this.api.options.entities.find((e) => e.id === id)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
public async createFindQuery(
|
|
384
|
+
req: CuboCrudRequest,
|
|
385
|
+
entity: CuboEntity,
|
|
386
|
+
queryDto?: Partial<CuboCrudFindQuery>,
|
|
387
|
+
isCount?: boolean
|
|
388
|
+
): Promise<Partial<CuboCrudFindQuery>> {
|
|
389
|
+
const withes = queryDto?.withes !== undefined ? queryDto.withes : []
|
|
390
|
+
const selects = queryDto?.selects !== undefined ? queryDto.selects : []
|
|
391
|
+
const joins = queryDto?.joins !== undefined ? queryDto.joins : []
|
|
392
|
+
const conditions = queryDto?.conditions !== undefined ? queryDto.conditions : []
|
|
393
|
+
const havings = queryDto?.havings !== undefined ? queryDto.havings : []
|
|
394
|
+
const sorts = queryDto?.sorts !== undefined ? queryDto.sorts : []
|
|
395
|
+
const replacements = queryDto?.replacements !== undefined ? queryDto?.replacements : {}
|
|
396
|
+
const groupBy = queryDto?.groupBy !== undefined ? queryDto?.groupBy : undefined
|
|
397
|
+
|
|
398
|
+
const { sort, limit: _limit, page, with: _withes, ...query } = req.query || {}
|
|
399
|
+
|
|
400
|
+
// plain conditions (nested are in withes.ts)
|
|
401
|
+
for (const key in query || {}) {
|
|
402
|
+
const parts = key.replace(CUBO_CRUD_QUERY_KEY_REGEX, '')?.split('.')
|
|
403
|
+
|
|
404
|
+
if (parts.length === 1) {
|
|
405
|
+
const conditionField = entity.fields?.find((f) => f.alias === parts[0])
|
|
406
|
+
const defaultField = CUBO_CRUD_DEFAULT_FIELDS.find((f) => f.alias === parts[0])
|
|
407
|
+
|
|
408
|
+
if (!conditionField && !defaultField) {
|
|
409
|
+
throw new Error('condition field "' + parts[0] + '" not found in entity "' + entity.alias + '"')
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const fieldAlias = conditionField ? conditionField.alias : defaultField!.alias
|
|
413
|
+
const preparedCondition = this.clearFieldConditionValue(conditionField ? conditionField : defaultField!, query[key])
|
|
414
|
+
const prepared = this.prepareConditionSql(
|
|
415
|
+
`t1.${fieldAlias}`,
|
|
416
|
+
`c_1_${fieldAlias}_value`,
|
|
417
|
+
preparedCondition.value,
|
|
418
|
+
preparedCondition.condition,
|
|
419
|
+
preparedCondition.is_not
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
conditions.push(...(prepared.conditions || []))
|
|
423
|
+
Object.assign(replacements, prepared.replacements || {})
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// sort
|
|
428
|
+
if (!sorts.length) {
|
|
429
|
+
if (sort !== undefined && typeof sort === 'string') {
|
|
430
|
+
const sortParts = sort.split(',')
|
|
431
|
+
|
|
432
|
+
for (const sortPart of sortParts) {
|
|
433
|
+
const parts = sortPart.replace(CUBO_CRUD_QUERY_KEY_REGEX, '')?.split('.')
|
|
434
|
+
|
|
435
|
+
if (parts.length === 1) {
|
|
436
|
+
const sortDirection = sortPart[0] === '-' ? 'desc' : 'asc'
|
|
437
|
+
const sortKey = sortPart[0] === '-' ? sortPart.slice(1) : sortPart
|
|
438
|
+
|
|
439
|
+
const conditionField = entity.fields?.find((f) => f.alias === sortKey)
|
|
440
|
+
const defaultField = CUBO_CRUD_DEFAULT_FIELDS.find((f) => f.alias === sortKey)
|
|
441
|
+
|
|
442
|
+
if (!conditionField && !defaultField) {
|
|
443
|
+
throw new Error('sortPart field "' + sortKey + '" not found')
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
sorts.push('t1.' + sortKey + ' ' + sortDirection)
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
} else {
|
|
450
|
+
sorts.push('t1.id desc')
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// limit & offset
|
|
455
|
+
let perPage = _limit !== undefined && !isNaN(+_limit) ? _limit : CUBO_CRUD_DEFAULT_PAGE_LIMIT
|
|
456
|
+
let pageNumber = page !== undefined && !isNaN(+page) ? +page : 1
|
|
457
|
+
if (pageNumber < 1) {
|
|
458
|
+
pageNumber = 1
|
|
459
|
+
}
|
|
460
|
+
if (perPage > CUBO_CRUD_MAX_PAGE_LIMIT) {
|
|
461
|
+
perPage = CUBO_CRUD_MAX_PAGE_LIMIT
|
|
462
|
+
}
|
|
463
|
+
if (perPage < 0) {
|
|
464
|
+
perPage = 0
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const filtersLimit = perPage
|
|
468
|
+
const filtersOffset = (pageNumber - 1) * perPage
|
|
469
|
+
|
|
470
|
+
let offsetString = ''
|
|
471
|
+
let limitString = ''
|
|
472
|
+
let groupByString = queryDto?.groupBy ?? ''
|
|
473
|
+
|
|
474
|
+
if (!isCount && perPage > 0) {
|
|
475
|
+
if (filtersOffset > 0) {
|
|
476
|
+
offsetString = `offset ${filtersOffset}`
|
|
477
|
+
}
|
|
478
|
+
limitString = `limit ${filtersLimit}`
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
selects.push(...CUBO_CRUD_DEFAULT_FIELDS.map((f) => `t1.${f.alias}`))
|
|
482
|
+
selects.push(...entity.fields.map((f) => `t1.${f.alias}`))
|
|
483
|
+
|
|
484
|
+
// remove deleted rows
|
|
485
|
+
if (!queryDto?.withDeleted) {
|
|
486
|
+
conditions.push('t1.deleted_at is null')
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const sql = `
|
|
490
|
+
select
|
|
491
|
+
${isCount ? 'count(t1.id) total' : selects.join(',\n')}
|
|
492
|
+
from
|
|
493
|
+
${entity.alias} t1
|
|
494
|
+
${joins.join('\n')}
|
|
495
|
+
${conditions.length > 0 ? `where (${conditions.join(') and (')})` : ''}
|
|
496
|
+
${groupByString}
|
|
497
|
+
${havings.length > 0 ? `having (${havings.join(') and (')})` : ''}
|
|
498
|
+
${sorts.length > 0 && !isCount ? 'order by ' + sorts.join(', ') : ''}
|
|
499
|
+
${limitString}
|
|
500
|
+
${offsetString}
|
|
501
|
+
`
|
|
502
|
+
|
|
503
|
+
// console.log('conditions', { conditions })
|
|
504
|
+
// console.log('sql', sql)
|
|
505
|
+
|
|
506
|
+
return {
|
|
507
|
+
withes,
|
|
508
|
+
selects,
|
|
509
|
+
joins,
|
|
510
|
+
conditions,
|
|
511
|
+
groupBy,
|
|
512
|
+
havings,
|
|
513
|
+
sorts,
|
|
514
|
+
replacements,
|
|
515
|
+
sql
|
|
516
|
+
}
|
|
375
517
|
}
|
|
376
518
|
}
|
package/src/helpers/withes.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CuboApiEntitiesMap, CuboApiEntityDefaultUsersKeys, CuboEntity, CuboEntityField } from '@cuboapp/types'
|
|
2
|
-
import cloneDeep from '
|
|
2
|
+
import { cloneDeep } from '@cuboapp/utils'
|
|
3
3
|
|
|
4
4
|
import { CUBO_CRUD_DEFAULT_FIELDS, CUBO_CRUD_QUERY_KEY_REGEX } from '../constants'
|
|
5
5
|
import { CuboCrudFindQuery, CuboCrudMethodOptions, CuboCrudRequest, CuboCrudWith } from '../types'
|
|
@@ -79,11 +79,11 @@ export class ApiHelpersWithes<T extends CuboApiEntitiesMap<T>> {
|
|
|
79
79
|
let relationEntity: CuboEntity | undefined
|
|
80
80
|
|
|
81
81
|
if (relation_entity_id) {
|
|
82
|
-
relationEntity = await this.helpers.
|
|
82
|
+
relationEntity = await this.helpers.getEntityById(relation_entity_id)
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
if (!relationEntity && relation_entity_alias) {
|
|
86
|
-
relationEntity = await this.helpers.
|
|
86
|
+
relationEntity = await this.helpers.getEntityByAlias(relation_entity_alias)
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
lastEntity = relationEntity
|
|
@@ -238,9 +238,9 @@ export class ApiHelpersWithes<T extends CuboApiEntitiesMap<T>> {
|
|
|
238
238
|
const havings: string[] = [...(opts?.queryOptions?.havings || [])]
|
|
239
239
|
const replacements: Record<string, any> = { ...(opts?.queryOptions?.replacements || {}) }
|
|
240
240
|
const groupBy: string = opts?.queryOptions?.groupBy || undefined
|
|
241
|
+
const sorts: string[] = opts?.queryOptions?.sorts || []
|
|
241
242
|
|
|
242
243
|
const withes: CuboCrudWith[] = []
|
|
243
|
-
const sorts: string[] = []
|
|
244
244
|
|
|
245
245
|
// from sort key
|
|
246
246
|
if (_sort) {
|