@cuboapp/api-backend 1.0.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.
@@ -0,0 +1,29 @@
1
+ import { CuboApiEntitiesMap } from '@cuboapp/types'
2
+
3
+ import { CuboCrudGetManyResponse, CuboCrudRequest } from './basic'
4
+ import { CuboCrudMethodOptions, CuboCrudQueryOptions } from './db'
5
+
6
+ export type CuboCrudAugmentationsStore<T extends CuboApiEntitiesMap<T>> = {
7
+ [K in Extract<keyof T, string>]?: CuboCrudAugmentationInstance<T[K]>
8
+ }
9
+
10
+ export interface CuboCrudAugmentationInstance<T = unknown> {
11
+ beforeGetMany?: (req: CuboCrudRequest, opts?: CuboCrudMethodOptions) => Promise<CuboCrudQueryOptions>
12
+ afterGetMany?: (
13
+ result: CuboCrudGetManyResponse<T>,
14
+ req: CuboCrudRequest,
15
+ opts?: CuboCrudMethodOptions
16
+ ) => Promise<CuboCrudGetManyResponse<T>>
17
+
18
+ beforeGetOne?: (req: CuboCrudRequest, opts?: CuboCrudMethodOptions) => Promise<CuboCrudQueryOptions>
19
+ afterGetOne?: (result: T, req: CuboCrudRequest, opts?: CuboCrudMethodOptions) => Promise<T | undefined>
20
+
21
+ beforeCreate?: (req: CuboCrudRequest, opts?: CuboCrudMethodOptions) => Promise<CuboCrudQueryOptions>
22
+ afterCreate?: (result: T, req: CuboCrudRequest, opts?: CuboCrudMethodOptions) => Promise<T>
23
+
24
+ beforeUpdate?: (req: CuboCrudRequest, opts?: CuboCrudMethodOptions) => Promise<CuboCrudQueryOptions>
25
+ afterUpdate?: (result: T, req: CuboCrudRequest, opts?: CuboCrudMethodOptions) => Promise<T>
26
+
27
+ beforeDelete?: (req: CuboCrudRequest, opts?: CuboCrudMethodOptions) => Promise<CuboCrudQueryOptions>
28
+ afterDelete?: (result: T, req: CuboCrudRequest, opts?: CuboCrudMethodOptions) => Promise<boolean>
29
+ }
@@ -0,0 +1,59 @@
1
+ import { CuboEntity, CuboEntityField } from '@cuboapp/types'
2
+ import { type Transaction } from 'sequelize'
3
+
4
+ export type CuboCrudWith = {
5
+ entity: CuboEntity | { id: undefined; alias: string; fields: CuboEntityField[] }
6
+ key: string
7
+ full_key: string
8
+ table_name: string
9
+ }
10
+
11
+ export type CuboCrudQueryDefaults = {
12
+ query?: string
13
+ sort?: string
14
+ limit?: number
15
+ page?: number
16
+ }
17
+
18
+ export type CuboCrudRequest = {
19
+ headers?: Record<string, any>
20
+ query?: Record<string, any>
21
+ params?: Record<string, any>
22
+ body?: any
23
+ }
24
+
25
+ export type CuboCrudOptions = {
26
+ user_id?: number
27
+ transaction?: Transaction
28
+ }
29
+
30
+ export type CuboCrudDto = {
31
+ entity: CuboEntity
32
+ request: CuboCrudRequest
33
+ options: CuboCrudOptions
34
+ state: any
35
+ }
36
+
37
+ export type CuboCrudFindQuery = {
38
+ selects: string[]
39
+ conditions: string[]
40
+ replacements: Record<string, any>
41
+ sorts: string[]
42
+ offset: number
43
+ limit: number
44
+
45
+ joins: string[]
46
+ withes: CuboCrudWith[]
47
+
48
+ withDeleted?: boolean
49
+ is_count: boolean
50
+ sql: string
51
+ }
52
+
53
+ export type CuboCrudGetManyResponse<T, E extends object = object> = {
54
+ rows: T[]
55
+ totals: {
56
+ count: number
57
+ }
58
+ extra?: E
59
+ }
@@ -0,0 +1,24 @@
1
+ import { type Transaction } from 'sequelize'
2
+
3
+ export type CuboCrudQueryOptions = {
4
+ selects?: string[]
5
+ conditions?: string[]
6
+ replacements?: Record<string, any>
7
+ joins?: string[]
8
+ withes?: string[]
9
+ sorts?: string[]
10
+ withDeleted?: boolean
11
+
12
+ extra?: any
13
+ }
14
+
15
+ export type CuboCrudMethodOptions<E extends object = {}> = {
16
+ transaction?: Transaction
17
+ user_id?: number
18
+ extra?: any
19
+ excludeHooks?: ('beforeGetMany' | 'beforeGetOne' | 'afterCreate' | 'afterUpdate' | 'afterDelete' | 'afterGetMany' | 'afterGetOne')[]
20
+
21
+ log?: boolean
22
+
23
+ queryOptions?: CuboCrudQueryOptions
24
+ } & E
@@ -0,0 +1,3 @@
1
+ export * from './augmentation'
2
+ export * from './basic'
3
+ export * from './db'
@@ -0,0 +1,128 @@
1
+ import { QueryTypes, Sequelize, Transaction } from 'sequelize'
2
+
3
+ export function dbPrepareUpdateQueryString(obj: Record<string, any>) {
4
+ const keys: string[] = []
5
+ const replacements: Record<string, any> = {}
6
+
7
+ for (const key in obj) {
8
+ const value = obj[key]
9
+
10
+ keys.push(`${key} = :${key}`)
11
+
12
+ let val = null
13
+
14
+ if (typeof value === 'string') {
15
+ val = !!value ? value : null
16
+ } else if (typeof value === 'number') {
17
+ val = !isNaN(value) ? value : null
18
+ } else if (typeof value === 'boolean') {
19
+ val = value
20
+ } else if (Array.isArray(value) || typeof value === 'object') {
21
+ val = value ? JSON.stringify(value) : null
22
+ }
23
+
24
+ replacements[key] = val
25
+ }
26
+
27
+ return { query: keys.join(', '), replacements }
28
+ }
29
+
30
+ export function dbPrepareInsertQueryString(obj: Record<string, any>) {
31
+ const values: string[] = []
32
+ const replacements: Record<string, any> = {}
33
+
34
+ for (const key in obj) {
35
+ const value = obj[key]
36
+
37
+ values.push(`:${key}`)
38
+
39
+ let val = null
40
+
41
+ if (typeof value === 'string') {
42
+ val = !!value ? value : null
43
+ } else if (typeof value === 'number') {
44
+ val = !isNaN(value) ? value : null
45
+ } else if (typeof value === 'boolean') {
46
+ val = value
47
+ } else if (Array.isArray(value) || typeof value === 'object') {
48
+ val = value ? JSON.stringify(value) : null
49
+ }
50
+
51
+ replacements[key] = val
52
+ }
53
+
54
+ return { keys: Object.keys(obj).join(', '), values: values.join(','), replacements }
55
+ }
56
+
57
+ export async function dbCreate(
58
+ db: Sequelize,
59
+ table: string,
60
+ arInsert: any,
61
+ opts?: { log?: boolean; transaction?: Transaction }
62
+ ): Promise<{ id: number }> {
63
+ if (Object.keys(arInsert).length > 0) {
64
+ const dialect = db.getDialect()
65
+
66
+ const { keys, values, replacements } = dbPrepareInsertQueryString(arInsert)
67
+
68
+ let sql = ''
69
+
70
+ switch (dialect) {
71
+ case 'postgres':
72
+ sql = `insert into ${table} (${keys}) values (${values}) returning id`
73
+ break
74
+ case 'mysql':
75
+ sql = `insert into ${table} (${keys}) values (${values})`
76
+ break
77
+ default:
78
+ throw ''
79
+ }
80
+
81
+ if (opts?.log) {
82
+ console.warn(`QUERY: ${sql} [${JSON.stringify(replacements)}]`)
83
+ }
84
+
85
+ return db
86
+ .query(sql, {
87
+ type: QueryTypes.INSERT,
88
+ replacements,
89
+ transaction: opts?.transaction
90
+ })
91
+ .then((res: any) => {
92
+ switch (dialect) {
93
+ case 'postgres':
94
+ return { id: +res?.[0]?.[0].id }
95
+ case 'mysql':
96
+ return { id: +res[0] }
97
+ }
98
+ })
99
+ }
100
+
101
+ throw new Error('QUERY: db create array empty')
102
+ }
103
+
104
+ export async function dbUpdate(
105
+ db: Sequelize,
106
+ table: string,
107
+ where: string,
108
+ replacements: Record<string, any>,
109
+ arUpdate: any,
110
+ opts?: { log?: boolean; transaction?: Transaction }
111
+ ) {
112
+ if (Object.keys(arUpdate).length > 0) {
113
+ const prepared = dbPrepareUpdateQueryString(arUpdate)
114
+
115
+ if (opts?.log) {
116
+ console.warn(`QUERY: update ${table} set ${prepared.query} where ${where} [${JSON.stringify(replacements)}]`)
117
+ }
118
+
119
+ await db.query(`update ${table} set ${prepared.query} where ${where}`, {
120
+ type: QueryTypes.UPDATE,
121
+ replacements: {
122
+ ...(replacements || {}),
123
+ ...(prepared.replacements || {})
124
+ },
125
+ transaction: opts?.transaction
126
+ })
127
+ }
128
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "declaration": true,
5
+ "removeComments": true,
6
+ "emitDecoratorMetadata": true,
7
+ "experimentalDecorators": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "target": "ES2021",
10
+ "sourceMap": true,
11
+ "outDir": "./dist",
12
+ "baseUrl": "./",
13
+ "incremental": true,
14
+ "skipLibCheck": true,
15
+ "paths": {
16
+ "@/*": ["src/*"]
17
+ }
18
+ },
19
+ "include": ["src/**/*"],
20
+ "exclude": ["node_modules", "dist"]
21
+ }