@stacksjs/actions 0.62.0 → 0.63.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/dist/add.js +3 -0
- package/dist/add.js.map +10 -0
- package/dist/build/component-libs.js +3 -0
- package/dist/build/component-libs.js.map +10 -0
- package/dist/build/core.js +3 -0
- package/dist/build/core.js.map +10 -0
- package/dist/build/stacks.js +3 -0
- package/dist/build/stacks.js.map +10 -0
- package/dist/build.js +6 -4
- package/dist/build.js.map +14 -0
- package/dist/bump.js +7 -4
- package/dist/bump.js.map +10 -0
- package/dist/changelog.js +3 -0
- package/dist/changelog.js.map +10 -0
- package/dist/clean.js +3 -0
- package/dist/clean.js.map +10 -0
- package/dist/commit.js +3 -0
- package/dist/commit.js.map +10 -0
- package/dist/copy-types.js +3 -0
- package/dist/copy-types.js.map +10 -0
- package/dist/database/seed.js +3 -0
- package/dist/database/seed.js.map +10 -0
- package/dist/deploy/index.js +14 -5
- package/dist/deploy/index.js.map +10 -0
- package/dist/dev/components.js +3 -0
- package/dist/dev/components.js.map +10 -0
- package/dist/dev/docs.js +3 -0
- package/dist/dev/docs.js.map +10 -0
- package/dist/dev/index.js +4 -2
- package/dist/dev/index.js.map +11 -0
- package/dist/examples.js +3 -0
- package/dist/examples.js.map +10 -0
- package/dist/fresh.js +3 -0
- package/dist/fresh.js.map +10 -0
- package/dist/generate/component-meta.js +3 -0
- package/dist/generate/component-meta.js.map +11 -0
- package/dist/generate/ide-helpers.js +5 -2
- package/dist/generate/ide-helpers.js.map +12 -0
- package/dist/generate/index.js +6 -4
- package/dist/generate/index.js.map +13 -0
- package/dist/generate/lib-entries.js +3 -0
- package/dist/generate/lib-entries.js.map +12 -0
- package/dist/generate/vscode-custom-data.js +5 -2
- package/dist/generate/vscode-custom-data.js.map +12 -0
- package/dist/helpers/component-meta.js +3 -0
- package/dist/helpers/component-meta.js.map +10 -0
- package/dist/helpers/lib-entries.js +3 -0
- package/dist/helpers/lib-entries.js.map +11 -0
- package/dist/helpers/package-json.js +3 -0
- package/dist/helpers/package-json.js.map +11 -0
- package/dist/helpers/utils.js +4 -2
- package/dist/helpers/utils.js.map +10 -0
- package/dist/helpers/vscode-custom-data.js +5 -2
- package/dist/helpers/vscode-custom-data.js.map +11 -0
- package/dist/index.js +21 -5
- package/dist/index.js.map +18 -0
- package/dist/key-generate.js +3 -0
- package/dist/key-generate.js.map +10 -0
- package/dist/lint/fix.js +3 -0
- package/dist/lint/fix.js.map +10 -0
- package/dist/lint/index.js +3 -0
- package/dist/lint/index.js.map +10 -0
- package/dist/make.js +3 -0
- package/dist/make.js.map +10 -0
- package/dist/prepublish.js +3 -0
- package/dist/prepublish.js.map +10 -0
- package/dist/release.js +21 -5
- package/dist/release.js.map +19 -0
- package/dist/test/coverage.js +3 -0
- package/dist/test/coverage.js.map +10 -0
- package/dist/test/feature.js +3 -0
- package/dist/test/feature.js.map +10 -0
- package/dist/test/ui.js +3 -0
- package/dist/test/ui.js.map +10 -0
- package/dist/test/unit.js +3 -0
- package/dist/test/unit.js.map +10 -0
- package/dist/test.js +3 -0
- package/dist/test.js.map +10 -0
- package/dist/typecheck.js +3 -0
- package/dist/typecheck.js.map +10 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +10 -0
- package/dist/upgrade/dependencies.js +3 -0
- package/dist/upgrade/dependencies.js.map +9 -0
- package/dist/upgrade/framework.js +3 -0
- package/dist/upgrade/framework.js.map +9 -0
- package/dist/upgrade/index.js +4 -2
- package/dist/upgrade/index.js.map +11 -0
- package/dist/upgrade.js +4 -1
- package/dist/upgrade.js.map +10 -0
- package/package.json +3 -3
- package/src/action.ts +15 -1
- package/src/build/server.ts +1 -1
- package/src/bump.ts +5 -5
- package/src/cdn/invalidate-cache.ts +1 -1
- package/src/deploy/index.ts +14 -6
- package/src/files/watch.ts +8 -0
- package/src/helpers/utils.ts +2 -3
- package/src/orm/generate-model.ts +384 -144
|
@@ -2,9 +2,10 @@ import { log } from '@stacksjs/logging'
|
|
|
2
2
|
import { getModelName, getTableName } from '@stacksjs/orm'
|
|
3
3
|
import { path } from '@stacksjs/path'
|
|
4
4
|
import { fs, glob } from '@stacksjs/storage'
|
|
5
|
-
import { camelCase, pascalCase, plural, singular } from '@stacksjs/strings'
|
|
5
|
+
import { camelCase, pascalCase, plural, singular, snakeCase } from '@stacksjs/strings'
|
|
6
6
|
import type { Attributes, Model, RelationConfig } from '@stacksjs/types'
|
|
7
7
|
import { isString } from '@stacksjs/validation'
|
|
8
|
+
|
|
8
9
|
export interface FieldArrayElement {
|
|
9
10
|
entity: string
|
|
10
11
|
charValue?: string | null
|
|
@@ -22,7 +23,7 @@ await initiateModelGeneration()
|
|
|
22
23
|
await setKyselyTypes()
|
|
23
24
|
|
|
24
25
|
async function generateApiRoutes(modelFiles: string[]) {
|
|
25
|
-
const file = Bun.file(path.
|
|
26
|
+
const file = Bun.file(path.frameworkPath(`orm/routes.ts`))
|
|
26
27
|
const writer = file.writer()
|
|
27
28
|
let routeString = `import { route } from '@stacksjs/router'\n\n\n`
|
|
28
29
|
|
|
@@ -36,6 +37,8 @@ async function generateApiRoutes(modelFiles: string[]) {
|
|
|
36
37
|
if (model.traits?.useApi) {
|
|
37
38
|
const apiRoutes = model.traits?.useApi?.routes
|
|
38
39
|
const middlewares = model.traits.useApi?.middleware
|
|
40
|
+
const uri = model.traits.useApi?.uri || tableName
|
|
41
|
+
|
|
39
42
|
if (middlewares) {
|
|
40
43
|
middlewareString = `.middleware([`
|
|
41
44
|
if (middlewares.length) {
|
|
@@ -51,24 +54,37 @@ async function generateApiRoutes(modelFiles: string[]) {
|
|
|
51
54
|
middlewareString += `])`
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
if (Object.keys(model.traits.useApi.routes).length > 0) {
|
|
58
|
+
if (apiRoutes) {
|
|
59
|
+
for (const apiRoute in apiRoutes) {
|
|
60
|
+
// if (Object.prototype.hasOwnProperty.call(apiRoutes, route)) {
|
|
61
|
+
// console.log(`Route: ${route}, Path: ${apiRoutes[route]}`);
|
|
62
|
+
// }
|
|
63
|
+
|
|
64
|
+
let path: string | null = ''
|
|
65
|
+
|
|
66
|
+
await writeOrmActions(apiRoute as string, modelName)
|
|
57
67
|
|
|
58
|
-
|
|
59
|
-
routeString += `await route.get('${tableName}', 'Actions/${modelName}IndexOrmAction')${middlewareString}\n\n`
|
|
68
|
+
path = `${apiRoutes[apiRoute]}.ts`
|
|
60
69
|
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
if (!path.includes('/')) {
|
|
71
|
+
path = await lookupFile(path)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!path) {
|
|
75
|
+
throw { message: 'Action Not Found!' }
|
|
76
|
+
}
|
|
63
77
|
|
|
64
|
-
|
|
65
|
-
routeString += `await route.patch('${tableName}/{id}', 'Actions/${modelName}UpdateOrmAction')${middlewareString}\n\n`
|
|
78
|
+
if (apiRoute === 'index') routeString += `await route.get('${uri}', '${path}')\n\n`
|
|
66
79
|
|
|
67
|
-
|
|
68
|
-
routeString += `await route.get('${tableName}/{id}', 'Actions/${modelName}ShowOrmAction')${middlewareString}\n\n`
|
|
80
|
+
if (apiRoute === 'show') routeString += `await route.get('${uri}/{id}', '${path}')\n\n`
|
|
69
81
|
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
if (apiRoute === 'store') routeString += `await route.post('${uri}', '${path}')\n\n`
|
|
83
|
+
|
|
84
|
+
if (apiRoute === 'update') routeString += `await route.patch('${uri}/{id}', '${path}')\n\n`
|
|
85
|
+
|
|
86
|
+
if (apiRoute === 'destroy') routeString += `await route.delete('${uri}/{id}', '${path}')\n\n`
|
|
87
|
+
}
|
|
72
88
|
}
|
|
73
89
|
}
|
|
74
90
|
}
|
|
@@ -78,18 +94,36 @@ async function generateApiRoutes(modelFiles: string[]) {
|
|
|
78
94
|
await writer.end()
|
|
79
95
|
}
|
|
80
96
|
|
|
97
|
+
async function lookupFile(fileName: string): Promise<string | null> {
|
|
98
|
+
const ormDirectory = path.builtUserActionsPath('src')
|
|
99
|
+
const filePath = path.join(ormDirectory, fileName)
|
|
100
|
+
const pathExists = await fs.existsSync(filePath)
|
|
101
|
+
|
|
102
|
+
// Check if the directory exists
|
|
103
|
+
if (pathExists) {
|
|
104
|
+
return filePath
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const actionDirectory = path.userActionsPath()
|
|
108
|
+
const actionFilePath = path.join(actionDirectory, fileName)
|
|
109
|
+
const fileExists = await fs.existsSync(actionFilePath)
|
|
110
|
+
|
|
111
|
+
if (fileExists) {
|
|
112
|
+
return actionFilePath
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return null
|
|
116
|
+
}
|
|
117
|
+
|
|
81
118
|
async function writeModelNames() {
|
|
82
119
|
const modelFiles = glob.sync(path.userModelsPath('*.ts'))
|
|
83
|
-
|
|
84
120
|
let fileString = `export type ModelNames = `
|
|
85
121
|
|
|
86
122
|
for (let i = 0; i < modelFiles.length; i++) {
|
|
87
123
|
const modeFileElement = modelFiles[i] as string
|
|
88
|
-
|
|
89
124
|
const model = (await import(modeFileElement)).default as Model
|
|
90
125
|
const modelName = getModelName(model, modeFileElement)
|
|
91
|
-
|
|
92
|
-
const typeFile = Bun.file(path.projectStoragePath(`framework/core/types/src/model-names.ts`))
|
|
126
|
+
const typeFile = Bun.file(path.corePath(`types/src/model-names.ts`))
|
|
93
127
|
|
|
94
128
|
fileString += `'${modelName}'`
|
|
95
129
|
|
|
@@ -105,8 +139,8 @@ async function writeModelNames() {
|
|
|
105
139
|
|
|
106
140
|
async function writeModelRequest() {
|
|
107
141
|
const modelFiles = glob.sync(path.userModelsPath('*.ts'))
|
|
108
|
-
|
|
109
142
|
const requestD = Bun.file(path.frameworkPath('types/requests.d.ts'))
|
|
143
|
+
|
|
110
144
|
let importTypes = ``
|
|
111
145
|
let importTypesString = ``
|
|
112
146
|
let typeString = `import { Request } from '../core/router/src/request'\n\n`
|
|
@@ -132,10 +166,10 @@ async function writeModelRequest() {
|
|
|
132
166
|
let fileString = `import { Request } from '@stacksjs/router'\nimport type { VineType } from '@stacksjs/types'\nimport { validateField } from '@stacksjs/validation'\nimport { customValidate } from '@stacksjs/validation'\n\n`
|
|
133
167
|
|
|
134
168
|
const modeFileElement = modelFiles[i] as string
|
|
135
|
-
|
|
136
169
|
const model = (await import(modeFileElement)).default as Model
|
|
137
170
|
const modelName = getModelName(model, modeFileElement)
|
|
138
|
-
|
|
171
|
+
const useTimestamps = model?.traits?.useTimestamps ?? model?.traits?.timestampable ?? true
|
|
172
|
+
const useSoftDeletes = model?.traits?.useSoftDeletes ?? model?.traits?.softDeletable ?? false
|
|
139
173
|
const attributes = await extractFields(model, modeFileElement)
|
|
140
174
|
|
|
141
175
|
fieldString += ` id?: number\n`
|
|
@@ -147,20 +181,18 @@ async function writeModelRequest() {
|
|
|
147
181
|
const otherModelRelations = await fetchOtherModelRelations(model, modelName)
|
|
148
182
|
|
|
149
183
|
for (const attribute of attributes) {
|
|
150
|
-
let defaultValue: any = `''`
|
|
151
184
|
const entity = attribute.fieldArray?.entity === 'enum' ? 'string[]' : attribute.fieldArray?.entity
|
|
185
|
+
let defaultValue: any = `''`
|
|
152
186
|
|
|
153
187
|
if (attribute.fieldArray?.entity === 'boolean') defaultValue = false
|
|
154
|
-
|
|
155
188
|
if (attribute.fieldArray?.entity === 'number') defaultValue = 0
|
|
156
189
|
|
|
157
190
|
fieldString += ` ${attribute.field}: ${entity}\n `
|
|
158
|
-
|
|
159
191
|
fieldStringType += `'${attribute.field}'`
|
|
192
|
+
|
|
160
193
|
if (keyCounter < attributes.length - 1) fieldStringType += ' |'
|
|
161
194
|
|
|
162
195
|
fieldStringInt += `public ${attribute.field} = ${defaultValue}\n`
|
|
163
|
-
|
|
164
196
|
keyCounter++
|
|
165
197
|
}
|
|
166
198
|
|
|
@@ -175,14 +207,20 @@ async function writeModelRequest() {
|
|
|
175
207
|
// fieldStringType += ' |'
|
|
176
208
|
|
|
177
209
|
fieldStringInt += `public ${otherModel.foreignKey} = 0\n`
|
|
178
|
-
|
|
179
210
|
keyCounterForeign++
|
|
180
211
|
}
|
|
181
212
|
|
|
182
|
-
|
|
183
|
-
public
|
|
184
|
-
|
|
213
|
+
if (useTimestamps) {
|
|
214
|
+
fieldStringInt += `public created_at = ''
|
|
215
|
+
public updated_at = ''
|
|
185
216
|
`
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (useSoftDeletes) {
|
|
220
|
+
fieldStringInt += `
|
|
221
|
+
public deleted_at = ''
|
|
222
|
+
`
|
|
223
|
+
}
|
|
186
224
|
|
|
187
225
|
fieldString += `created_at?: string
|
|
188
226
|
updated_at?: string
|
|
@@ -190,7 +228,7 @@ async function writeModelRequest() {
|
|
|
190
228
|
|
|
191
229
|
const modelLowerCase = camelCase(modelName)
|
|
192
230
|
|
|
193
|
-
const requestFile = Bun.file(path.
|
|
231
|
+
const requestFile = Bun.file(path.frameworkPath(`requests/${modelName}Request.ts`))
|
|
194
232
|
|
|
195
233
|
importTypes = `${modelName}RequestType`
|
|
196
234
|
importTypesString += `${importTypes}`
|
|
@@ -233,11 +271,11 @@ async function writeModelRequest() {
|
|
|
233
271
|
} else {
|
|
234
272
|
await customValidate(attributes, this.all())
|
|
235
273
|
}
|
|
236
|
-
|
|
274
|
+
|
|
237
275
|
}
|
|
238
276
|
}
|
|
239
|
-
|
|
240
|
-
export const
|
|
277
|
+
|
|
278
|
+
export const request = new ${modelName}Request()
|
|
241
279
|
`
|
|
242
280
|
|
|
243
281
|
const writer = requestFile.writer()
|
|
@@ -274,7 +312,7 @@ async function writeOrmActions(apiRoute: string, modelName: String): Promise<voi
|
|
|
274
312
|
handleString += `async handle(request: ${modelName}RequestType) {
|
|
275
313
|
const id = await request.getParam('id')
|
|
276
314
|
|
|
277
|
-
return ${modelName}.findOrFail(Number(id))
|
|
315
|
+
return await ${modelName}.findOrFail(Number(id))
|
|
278
316
|
},`
|
|
279
317
|
|
|
280
318
|
method = 'GET'
|
|
@@ -308,7 +346,7 @@ async function writeOrmActions(apiRoute: string, modelName: String): Promise<voi
|
|
|
308
346
|
if (apiRoute === 'update') {
|
|
309
347
|
handleString += `async handle(request: ${modelName}RequestType) {
|
|
310
348
|
await request.validate()
|
|
311
|
-
|
|
349
|
+
|
|
312
350
|
const id = request.getParam('id')
|
|
313
351
|
|
|
314
352
|
const model = await ${modelName}.findOrFail(Number(id))
|
|
@@ -327,18 +365,19 @@ async function writeOrmActions(apiRoute: string, modelName: String): Promise<voi
|
|
|
327
365
|
})
|
|
328
366
|
`
|
|
329
367
|
|
|
330
|
-
const file = Bun.file(path.
|
|
368
|
+
const file = Bun.file(path.builtUserActionsPath(`src/${modelName}${formattedApiRoute}OrmAction.ts`))
|
|
331
369
|
|
|
332
370
|
const writer = file.writer()
|
|
333
371
|
|
|
334
372
|
writer.write(actionString)
|
|
335
373
|
}
|
|
336
374
|
|
|
337
|
-
async function initiateModelGeneration(): Promise<void> {
|
|
338
|
-
await deleteExistingModels()
|
|
339
|
-
await deleteExistingOrmActions()
|
|
375
|
+
async function initiateModelGeneration(modelStringFile?: string): Promise<void> {
|
|
376
|
+
await deleteExistingModels(modelStringFile)
|
|
377
|
+
await deleteExistingOrmActions(modelStringFile)
|
|
340
378
|
await deleteExistingModelNameTypes()
|
|
341
|
-
await deleteExistingModelRequest()
|
|
379
|
+
await deleteExistingModelRequest(modelStringFile)
|
|
380
|
+
await deleteExistingOrmRoute()
|
|
342
381
|
|
|
343
382
|
await writeModelNames()
|
|
344
383
|
await writeModelRequest()
|
|
@@ -348,13 +387,15 @@ async function initiateModelGeneration(): Promise<void> {
|
|
|
348
387
|
await generateApiRoutes(modelFiles)
|
|
349
388
|
|
|
350
389
|
for (const modelFile of modelFiles) {
|
|
390
|
+
if (modelStringFile && modelStringFile !== modelFile) continue
|
|
391
|
+
|
|
351
392
|
log.debug(`Processing model file: ${modelFile}`)
|
|
352
393
|
|
|
353
394
|
const model = (await import(modelFile)).default as Model
|
|
354
395
|
const tableName = await getTableName(model, modelFile)
|
|
355
396
|
const modelName = getModelName(model, modelFile)
|
|
356
397
|
|
|
357
|
-
const file = Bun.file(path.
|
|
398
|
+
const file = Bun.file(path.frameworkPath(`orm/src/models/${modelName}.ts`))
|
|
358
399
|
const fields = await extractFields(model, modelFile)
|
|
359
400
|
const classString = await generateModelString(tableName, modelName, model, fields)
|
|
360
401
|
|
|
@@ -422,44 +463,74 @@ function hasRelations(obj: any, key: string): boolean {
|
|
|
422
463
|
return key in obj
|
|
423
464
|
}
|
|
424
465
|
|
|
425
|
-
async function deleteExistingModels() {
|
|
426
|
-
const
|
|
466
|
+
async function deleteExistingModels(modelStringFile?: string) {
|
|
467
|
+
const typePath = path.frameworkPath(`orm/src/types.ts`)
|
|
468
|
+
|
|
469
|
+
if (fs.existsSync(typePath)) await Bun.$`rm ${typePath}`
|
|
470
|
+
|
|
471
|
+
if (modelStringFile) {
|
|
472
|
+
const modelPath = path.frameworkPath(`orm/src/models/${modelStringFile}.ts`)
|
|
473
|
+
|
|
474
|
+
await Bun.$`rm ${modelPath}`
|
|
475
|
+
|
|
476
|
+
return
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const modelPaths = glob.sync(path.frameworkPath(`orm/src/models/*.ts`))
|
|
427
480
|
|
|
428
481
|
for (const modelPath of modelPaths) {
|
|
429
482
|
if (fs.existsSync(modelPath)) await Bun.$`rm ${modelPath}`
|
|
430
483
|
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
async function deleteExistingOrmActions(modelStringFile?: string) {
|
|
487
|
+
const routes = path.frameworkPath(`orm/routes`)
|
|
488
|
+
if (fs.existsSync(routes)) await Bun.$`rm ${routes}`
|
|
431
489
|
|
|
432
|
-
|
|
490
|
+
if (modelStringFile) {
|
|
491
|
+
const ormPath = path.builtUserActionsPath(`src/${modelStringFile}.ts`)
|
|
433
492
|
|
|
434
|
-
|
|
435
|
-
|
|
493
|
+
if (fs.existsSync(ormPath)) await Bun.$`rm ${ormPath}`
|
|
494
|
+
|
|
495
|
+
return
|
|
496
|
+
}
|
|
436
497
|
|
|
437
|
-
|
|
438
|
-
const ormPaths = glob.sync(path.projectStoragePath(`framework/orm/Actions/*.ts`))
|
|
439
|
-
const routes = path.projectStoragePath(`framework/orm/routes`)
|
|
498
|
+
const ormPaths = glob.sync(path.builtUserActionsPath(`**/*.ts`))
|
|
440
499
|
|
|
441
500
|
for (const ormPath of ormPaths) {
|
|
442
501
|
if (fs.existsSync(ormPath)) await Bun.$`rm ${ormPath}`
|
|
443
502
|
}
|
|
444
|
-
|
|
445
|
-
if (fs.existsSync(routes)) await Bun.$`rm ${routes}`
|
|
446
503
|
}
|
|
447
504
|
|
|
448
505
|
async function deleteExistingModelNameTypes() {
|
|
449
|
-
const typeFile = path.
|
|
506
|
+
const typeFile = path.corePath(`types/src/model-names.ts`)
|
|
450
507
|
|
|
451
508
|
if (fs.existsSync(typeFile)) await Bun.$`rm ${typeFile}`
|
|
452
509
|
}
|
|
453
510
|
|
|
454
|
-
async function deleteExistingModelRequest() {
|
|
455
|
-
const requestFiles = glob.sync(path.projectStoragePath(`framework/requests/*.ts`))
|
|
511
|
+
async function deleteExistingModelRequest(modelStringFile?: string) {
|
|
456
512
|
const requestD = path.frameworkPath('types/requests.d.ts')
|
|
513
|
+
if (fs.existsSync(requestD)) await Bun.$`rm ${requestD}`
|
|
514
|
+
|
|
515
|
+
if (modelStringFile) {
|
|
516
|
+
const requestFile = path.frameworkPath(`requests/${modelStringFile}.ts`)
|
|
517
|
+
|
|
518
|
+
if (fs.existsSync(requestFile)) await Bun.$`rm ${requestFile}`
|
|
519
|
+
|
|
520
|
+
return
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const requestFiles = glob.sync(path.frameworkPath(`requests/*.ts`))
|
|
457
524
|
|
|
458
525
|
for (const requestFile of requestFiles) {
|
|
459
526
|
if (fs.existsSync(requestFile)) await Bun.$`rm ${requestFile}`
|
|
460
527
|
}
|
|
528
|
+
}
|
|
461
529
|
|
|
462
|
-
|
|
530
|
+
async function deleteExistingOrmRoute() {
|
|
531
|
+
const ormRoute = path.projectStoragePath('framework/orm/routes.ts')
|
|
532
|
+
|
|
533
|
+
if (fs.existsSync(ormRoute)) await Bun.$`rm ${ormRoute}`
|
|
463
534
|
}
|
|
464
535
|
|
|
465
536
|
async function setKyselyTypes() {
|
|
@@ -518,7 +589,7 @@ async function setKyselyTypes() {
|
|
|
518
589
|
|
|
519
590
|
text += `}`
|
|
520
591
|
|
|
521
|
-
const file = Bun.file(path.
|
|
592
|
+
const file = Bun.file(path.frameworkPath(`orm/src/types.ts`))
|
|
522
593
|
|
|
523
594
|
const writer = file.writer()
|
|
524
595
|
|
|
@@ -688,11 +759,13 @@ function getHiddenAttributes(attributes: Attributes | undefined): string[] {
|
|
|
688
759
|
function getFillableAttributes(attributes: Attributes | undefined): string[] {
|
|
689
760
|
if (attributes === undefined) return []
|
|
690
761
|
|
|
691
|
-
return Object.keys(attributes)
|
|
692
|
-
|
|
762
|
+
return Object.keys(attributes)
|
|
763
|
+
.filter((key) => {
|
|
764
|
+
if (attributes === undefined) return false
|
|
693
765
|
|
|
694
|
-
|
|
695
|
-
|
|
766
|
+
return attributes[key]?.fillable === true
|
|
767
|
+
})
|
|
768
|
+
.map((attribute) => snakeCase(attribute))
|
|
696
769
|
}
|
|
697
770
|
|
|
698
771
|
async function generateModelString(
|
|
@@ -706,12 +779,16 @@ async function generateModelString(
|
|
|
706
779
|
|
|
707
780
|
let fieldString = ''
|
|
708
781
|
let constructorFields = ''
|
|
782
|
+
let jsonFields = '{\n'
|
|
709
783
|
let declareFields = ''
|
|
710
784
|
let whereStatements = ''
|
|
711
785
|
let whereFunctionStatements = ''
|
|
712
786
|
let relationMethods = ``
|
|
713
787
|
let relationImports = ``
|
|
714
788
|
let twoFactorStatements = ''
|
|
789
|
+
let mittCreateStatement = ``
|
|
790
|
+
let mittUpdateStatement = ``
|
|
791
|
+
let mittDeleteStatement = ``
|
|
715
792
|
|
|
716
793
|
const relations = await getRelations(model, modelName)
|
|
717
794
|
|
|
@@ -719,6 +796,31 @@ async function generateModelString(
|
|
|
719
796
|
relationImports += `import ${relationInstance.model} from './${relationInstance.model}'\n\n`
|
|
720
797
|
}
|
|
721
798
|
|
|
799
|
+
const useTimestamps = model?.traits?.useTimestamps ?? model?.traits?.timestampable ?? true
|
|
800
|
+
const useSoftDeletes = model?.traits?.useSoftDeletes ?? model?.traits?.softDeletable ?? false
|
|
801
|
+
const observer = model?.traits?.observe
|
|
802
|
+
|
|
803
|
+
if (typeof observer === 'boolean') {
|
|
804
|
+
if (observer) {
|
|
805
|
+
mittCreateStatement += `dispatch('${formattedModelName}.created', model)`
|
|
806
|
+
mittUpdateStatement += `dispatch('${formattedModelName}.updated', model)`
|
|
807
|
+
mittDeleteStatement += `dispatch('${formattedModelName}.deleted', this)`
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
if (Array.isArray(observer)) {
|
|
812
|
+
// Iterate through the array and append statements based on its contents
|
|
813
|
+
if (observer.includes('create')) {
|
|
814
|
+
mittCreateStatement += `dispatch('${formattedModelName}.created', model);`
|
|
815
|
+
}
|
|
816
|
+
if (observer.includes('update')) {
|
|
817
|
+
mittUpdateStatement += `dispatch('${formattedModelName}.updated', model);`
|
|
818
|
+
}
|
|
819
|
+
if (observer.includes('delete')) {
|
|
820
|
+
mittDeleteStatement += `dispatch('${formattedModelName}.deleted', model);`
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
722
824
|
for (const relation of relations) {
|
|
723
825
|
const modelRelation = relation.model
|
|
724
826
|
const foreignKeyRelation = relation.foreignKey
|
|
@@ -733,7 +835,9 @@ async function generateModelString(
|
|
|
733
835
|
const relationName = relation.relationName || formattedModelName + modelRelation
|
|
734
836
|
const throughRelation = relation.throughModel
|
|
735
837
|
|
|
736
|
-
|
|
838
|
+
if (relation.throughModel === undefined) continue
|
|
839
|
+
|
|
840
|
+
const formattedThroughRelation = relation?.throughModel?.toLowerCase()
|
|
737
841
|
const throughTableRelation = throughRelation
|
|
738
842
|
const foreignKeyThroughRelation = relation.throughForeignKey || `${formattedThroughRelation}_id`
|
|
739
843
|
|
|
@@ -824,9 +928,12 @@ async function generateModelString(
|
|
|
824
928
|
.where('${foreignKeyRelation}', '=', this.id)
|
|
825
929
|
.selectAll()
|
|
826
930
|
.execute()
|
|
827
|
-
|
|
931
|
+
|
|
828
932
|
const tableRelationIds = results.map(result => result.${singular(tableRelation)}_id)
|
|
829
933
|
|
|
934
|
+
if (! tableRelationIds.length)
|
|
935
|
+
throw new Error('Relation Error!')
|
|
936
|
+
|
|
830
937
|
const relationResults = await ${modelRelation}.whereIn('id', tableRelationIds).get()
|
|
831
938
|
|
|
832
939
|
return relationResults
|
|
@@ -862,20 +969,22 @@ async function generateModelString(
|
|
|
862
969
|
`
|
|
863
970
|
}
|
|
864
971
|
|
|
972
|
+
jsonFields += `\nid: this.id,\n`
|
|
865
973
|
for (const attribute of attributes) {
|
|
866
974
|
const entity = attribute.fieldArray?.entity === 'enum' ? 'string[]' : attribute.fieldArray?.entity
|
|
867
975
|
|
|
868
976
|
fieldString += ` ${attribute.field}: ${entity}\n `
|
|
869
977
|
|
|
870
|
-
declareFields += `public ${attribute.field}: ${entity} | undefined \n `
|
|
978
|
+
declareFields += `public ${snakeCase(attribute.field)}: ${entity} | undefined \n `
|
|
871
979
|
|
|
872
|
-
constructorFields += `this.${attribute.field} = ${formattedModelName}?.${attribute.field}\n `
|
|
980
|
+
constructorFields += `this.${snakeCase(attribute.field)} = ${formattedModelName}?.${snakeCase(attribute.field)}\n `
|
|
981
|
+
jsonFields += `${snakeCase(attribute.field)}: this.${snakeCase(attribute.field)},\n `
|
|
873
982
|
|
|
874
983
|
whereStatements += `static where${pascalCase(attribute.field)}(value: string | number | boolean | undefined | null): ${modelName}Model {
|
|
875
984
|
const instance = new this(null)
|
|
876
985
|
|
|
877
986
|
instance.query = instance.query.where('${attribute.field}', '=', value)
|
|
878
|
-
|
|
987
|
+
|
|
879
988
|
return instance
|
|
880
989
|
} \n\n`
|
|
881
990
|
|
|
@@ -888,6 +997,39 @@ async function generateModelString(
|
|
|
888
997
|
} \n\n`
|
|
889
998
|
}
|
|
890
999
|
|
|
1000
|
+
if (useTimestamps) {
|
|
1001
|
+
declareFields += `
|
|
1002
|
+
public created_at: Date | undefined
|
|
1003
|
+
public updated_at: Date | undefined
|
|
1004
|
+
`
|
|
1005
|
+
|
|
1006
|
+
constructorFields += `
|
|
1007
|
+
this.created_at = user?.created_at\n
|
|
1008
|
+
this.updated_at = user?.updated_at\n
|
|
1009
|
+
`
|
|
1010
|
+
|
|
1011
|
+
jsonFields += `
|
|
1012
|
+
created_at: this.created_at,\n
|
|
1013
|
+
updated_at: this.updated_at,\n
|
|
1014
|
+
`
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
if (useSoftDeletes) {
|
|
1018
|
+
declareFields += `
|
|
1019
|
+
public deleted_at: Date | undefined
|
|
1020
|
+
`
|
|
1021
|
+
|
|
1022
|
+
constructorFields += `
|
|
1023
|
+
this.deleted_at = user?.deleted_at\n
|
|
1024
|
+
`
|
|
1025
|
+
|
|
1026
|
+
jsonFields += `
|
|
1027
|
+
deleted_at: this.deleted_at,\n
|
|
1028
|
+
`
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
jsonFields += '}'
|
|
1032
|
+
|
|
891
1033
|
const otherModelRelations = await fetchOtherModelRelations(model, modelName)
|
|
892
1034
|
|
|
893
1035
|
for (const otherModelRelation of otherModelRelations) {
|
|
@@ -902,12 +1044,26 @@ async function generateModelString(
|
|
|
902
1044
|
fieldString += `two_factor_secret: string \n`
|
|
903
1045
|
}
|
|
904
1046
|
|
|
1047
|
+
if (useTimestamps) {
|
|
1048
|
+
fieldString += `
|
|
1049
|
+
created_at: ColumnType<Date, string | undefined, never>\n
|
|
1050
|
+
updated_at: ColumnType<Date, string | undefined, never>
|
|
1051
|
+
`
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
if (useSoftDeletes) {
|
|
1055
|
+
fieldString += `
|
|
1056
|
+
deleted_at: ColumnType<Date, string | undefined, never>\n
|
|
1057
|
+
`
|
|
1058
|
+
}
|
|
1059
|
+
|
|
905
1060
|
const hidden = JSON.stringify(getHiddenAttributes(model.attributes))
|
|
906
1061
|
const fillable = JSON.stringify(getFillableAttributes(model.attributes))
|
|
907
1062
|
|
|
908
1063
|
return `import type { ColumnType, Generated, Insertable, Selectable, Updateable } from 'kysely'
|
|
909
1064
|
import { db } from '@stacksjs/database'
|
|
910
1065
|
import { sql } from '@stacksjs/database'
|
|
1066
|
+
import { dispatch } from '@stacksjs/events'
|
|
911
1067
|
import { generateTwoFactorSecret } from '@stacksjs/auth'
|
|
912
1068
|
import { verifyTwoFactorCode } from '@stacksjs/auth'
|
|
913
1069
|
${relationImports}
|
|
@@ -918,9 +1074,6 @@ async function generateModelString(
|
|
|
918
1074
|
export interface ${formattedTableName}Table {
|
|
919
1075
|
id: Generated<number>
|
|
920
1076
|
${fieldString}
|
|
921
|
-
created_at: ColumnType<Date, string | undefined, never>
|
|
922
|
-
updated_at: ColumnType<Date, string | undefined, never>
|
|
923
|
-
deleted_at: ColumnType<Date, string | undefined, never>
|
|
924
1077
|
}
|
|
925
1078
|
|
|
926
1079
|
interface ${modelName}Response {
|
|
@@ -950,16 +1103,15 @@ async function generateModelString(
|
|
|
950
1103
|
offset?: number
|
|
951
1104
|
page?: number
|
|
952
1105
|
}
|
|
953
|
-
|
|
1106
|
+
|
|
954
1107
|
export class ${modelName}Model {
|
|
955
|
-
private ${formattedModelName}: Partial<${modelName}Type> | null
|
|
956
1108
|
private hidden = ${hidden}
|
|
957
1109
|
private fillable = ${fillable}
|
|
1110
|
+
private softDeletes = ${useSoftDeletes}
|
|
958
1111
|
protected query: any
|
|
959
1112
|
protected hasSelect: boolean
|
|
960
1113
|
${declareFields}
|
|
961
1114
|
constructor(${formattedModelName}: Partial<${modelName}Type> | null) {
|
|
962
|
-
this.${formattedModelName} = ${formattedModelName}
|
|
963
1115
|
${constructorFields}
|
|
964
1116
|
|
|
965
1117
|
this.query = db.selectFrom('${tableName}')
|
|
@@ -979,8 +1131,8 @@ async function generateModelString(
|
|
|
979
1131
|
|
|
980
1132
|
if (!model)
|
|
981
1133
|
return undefined
|
|
982
|
-
|
|
983
|
-
return this.parseResult(
|
|
1134
|
+
|
|
1135
|
+
return this.parseResult(new ${modelName}Model(model))
|
|
984
1136
|
}
|
|
985
1137
|
|
|
986
1138
|
// Method to find a ${modelName} by ID
|
|
@@ -988,7 +1140,7 @@ async function generateModelString(
|
|
|
988
1140
|
let query = db.selectFrom('${tableName}').where('id', '=', id)
|
|
989
1141
|
|
|
990
1142
|
const instance = new this(null)
|
|
991
|
-
|
|
1143
|
+
|
|
992
1144
|
if (fields)
|
|
993
1145
|
query = query.select(fields)
|
|
994
1146
|
else
|
|
@@ -1002,18 +1154,34 @@ async function generateModelString(
|
|
|
1002
1154
|
return instance.parseResult(new this(model))
|
|
1003
1155
|
}
|
|
1004
1156
|
|
|
1005
|
-
static async
|
|
1157
|
+
static async all(): Promise<${modelName}Model[]> {
|
|
1158
|
+
let query = db.selectFrom('${tableName}').selectAll()
|
|
1159
|
+
|
|
1160
|
+
const instance = new this(null)
|
|
1161
|
+
|
|
1162
|
+
if (instance.softDeletes) {
|
|
1163
|
+
query = query.where('deleted_at', 'is', null)
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
const results = await query.execute();
|
|
1167
|
+
|
|
1168
|
+
return results.map(modelItem => instance.parseResult(new ${modelName}Model(modelItem)));
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
static async findOrFail(id: number): Promise<${modelName}Model> {
|
|
1006
1173
|
let query = db.selectFrom('${tableName}').where('id', '=', id)
|
|
1007
1174
|
|
|
1008
1175
|
const instance = new this(null)
|
|
1009
1176
|
|
|
1010
|
-
if (
|
|
1011
|
-
query = query.
|
|
1012
|
-
|
|
1013
|
-
|
|
1177
|
+
if (instance.softDeletes) {
|
|
1178
|
+
query = query.where('deleted_at', 'is', null);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
query = query.selectAll()
|
|
1014
1182
|
|
|
1015
1183
|
const model = await query.executeTakeFirst()
|
|
1016
|
-
|
|
1184
|
+
|
|
1017
1185
|
if (!model)
|
|
1018
1186
|
throw(\`No model results found for \${id}\ \`)
|
|
1019
1187
|
|
|
@@ -1021,19 +1189,18 @@ async function generateModelString(
|
|
|
1021
1189
|
return instance.parseResult(new this(model))
|
|
1022
1190
|
}
|
|
1023
1191
|
|
|
1024
|
-
static async findMany(ids: number[]
|
|
1192
|
+
static async findMany(ids: number[]): Promise<${modelName}Model[]> {
|
|
1025
1193
|
let query = db.selectFrom('${tableName}').where('id', 'in', ids)
|
|
1026
1194
|
|
|
1027
1195
|
const instance = new this(null)
|
|
1028
|
-
|
|
1029
|
-
if (fields)
|
|
1030
|
-
query = query.select(fields)
|
|
1031
|
-
else
|
|
1032
|
-
query = query.selectAll()
|
|
1033
1196
|
|
|
1034
|
-
|
|
1197
|
+
if (instance.softDeletes) {
|
|
1198
|
+
query = query.where('deleted_at', 'is', null);
|
|
1199
|
+
}
|
|
1035
1200
|
|
|
1036
|
-
|
|
1201
|
+
query = query.selectAll()
|
|
1202
|
+
|
|
1203
|
+
const model = await query.execute()
|
|
1037
1204
|
|
|
1038
1205
|
return model.map(modelItem => instance.parseResult(new ${modelName}Model(modelItem)))
|
|
1039
1206
|
}
|
|
@@ -1042,6 +1209,8 @@ async function generateModelString(
|
|
|
1042
1209
|
static async fetch(criteria: Partial<${modelName}Type>, options: QueryOptions = {}): Promise<${modelName}Model[]> {
|
|
1043
1210
|
let query = db.selectFrom('${tableName}')
|
|
1044
1211
|
|
|
1212
|
+
const instance = new this(null)
|
|
1213
|
+
|
|
1045
1214
|
// Apply sorting from options
|
|
1046
1215
|
if (options.sort)
|
|
1047
1216
|
query = query.orderBy(options.sort.column, options.sort.order)
|
|
@@ -1053,35 +1222,59 @@ async function generateModelString(
|
|
|
1053
1222
|
if (options.offset !== undefined)
|
|
1054
1223
|
query = query.offset(options.offset)
|
|
1055
1224
|
|
|
1225
|
+
if (instance.softDeletes) {
|
|
1226
|
+
query = query.where('deleted_at', 'is', null);
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1056
1229
|
const model = await query.selectAll().execute()
|
|
1057
1230
|
return model.map(modelItem => new ${modelName}Model(modelItem))
|
|
1058
1231
|
}
|
|
1059
1232
|
|
|
1060
1233
|
// Method to get a ${modelName} by criteria
|
|
1061
1234
|
static async get(): Promise<${modelName}Model[]> {
|
|
1062
|
-
|
|
1235
|
+
let query = db.selectFrom('${tableName}');
|
|
1063
1236
|
|
|
1064
|
-
const
|
|
1237
|
+
const instance = new this(null)
|
|
1065
1238
|
|
|
1066
|
-
|
|
1239
|
+
// Check if soft deletes are enabled
|
|
1240
|
+
if (instance.softDeletes) {
|
|
1241
|
+
query = query.where('deleted_at', 'is', null);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
const model = await query.selectAll().execute();
|
|
1245
|
+
|
|
1246
|
+
return model.map(modelItem => new ${modelName}Model(modelItem));
|
|
1067
1247
|
}
|
|
1068
1248
|
|
|
1069
1249
|
// Method to get a ${modelName} by criteria
|
|
1070
1250
|
async get(): Promise<${modelName}Model[]> {
|
|
1071
1251
|
if (this.hasSelect) {
|
|
1252
|
+
|
|
1253
|
+
if (this.softDeletes) {
|
|
1254
|
+
this.query = this.query.where('deleted_at', 'is', null);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1072
1257
|
const model = await this.query.execute()
|
|
1073
|
-
|
|
1258
|
+
|
|
1074
1259
|
return model.map((modelItem: ${modelName}Model) => new ${modelName}Model(modelItem))
|
|
1075
1260
|
}
|
|
1076
|
-
|
|
1261
|
+
|
|
1262
|
+
if (this.softDeletes) {
|
|
1263
|
+
this.query = this.query.where('deleted_at', 'is', null);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1077
1266
|
const model = await this.query.selectAll().execute()
|
|
1078
|
-
|
|
1267
|
+
|
|
1079
1268
|
return model.map((modelItem: ${modelName}Model) => new ${modelName}Model(modelItem))
|
|
1080
1269
|
}
|
|
1081
1270
|
|
|
1082
1271
|
static async count(): Promise<number> {
|
|
1083
1272
|
const instance = new this(null)
|
|
1084
1273
|
|
|
1274
|
+
if (instance.softDeletes) {
|
|
1275
|
+
instance.query = instance.query.where('deleted_at', 'is', null);
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1085
1278
|
const results = await instance.query.selectAll().execute()
|
|
1086
1279
|
|
|
1087
1280
|
return results.length
|
|
@@ -1089,6 +1282,11 @@ async function generateModelString(
|
|
|
1089
1282
|
|
|
1090
1283
|
async count(): Promise<number> {
|
|
1091
1284
|
if (this.hasSelect) {
|
|
1285
|
+
|
|
1286
|
+
if (this.softDeletes) {
|
|
1287
|
+
this.query = this.query.where('deleted_at', 'is', null);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1092
1290
|
const results = await this.query.execute()
|
|
1093
1291
|
|
|
1094
1292
|
return results.length
|
|
@@ -1112,7 +1310,7 @@ async function generateModelString(
|
|
|
1112
1310
|
.selectAll()
|
|
1113
1311
|
.orderBy('id', 'asc') // Assuming 'id' is used for cursor-based pagination
|
|
1114
1312
|
.limit((options.limit ?? 10) + 1) // Fetch one extra record
|
|
1115
|
-
.offset((options.page - 1) * (options.limit ?? 10))
|
|
1313
|
+
.offset(((options.page ?? 1) - 1) * (options.limit ?? 10)) // Ensure options.page is not undefined
|
|
1116
1314
|
.execute()
|
|
1117
1315
|
|
|
1118
1316
|
let nextCursor = null
|
|
@@ -1148,14 +1346,33 @@ async function generateModelString(
|
|
|
1148
1346
|
.values(filteredValues)
|
|
1149
1347
|
.executeTakeFirstOrThrow()
|
|
1150
1348
|
|
|
1151
|
-
|
|
1349
|
+
const model = await find(Number(result.insertId)) as ${modelName}Model
|
|
1350
|
+
|
|
1351
|
+
${mittCreateStatement}
|
|
1352
|
+
|
|
1353
|
+
return model
|
|
1152
1354
|
}
|
|
1153
1355
|
|
|
1154
1356
|
// Method to remove a ${modelName}
|
|
1155
1357
|
static async remove(id: number): Promise<void> {
|
|
1156
|
-
|
|
1358
|
+
const instance = new this(null)
|
|
1359
|
+
|
|
1360
|
+
const model = await instance.find(id)
|
|
1361
|
+
|
|
1362
|
+
if (instance.softDeletes) {
|
|
1363
|
+
await db.updateTable('${tableName}')
|
|
1364
|
+
.set({
|
|
1365
|
+
deleted_at: sql.raw('CURRENT_TIMESTAMP')
|
|
1366
|
+
})
|
|
1157
1367
|
.where('id', '=', id)
|
|
1158
|
-
.execute()
|
|
1368
|
+
.execute();
|
|
1369
|
+
} else {
|
|
1370
|
+
await db.deleteFrom('${tableName}')
|
|
1371
|
+
.where('id', '=', id)
|
|
1372
|
+
.execute();
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
${mittDeleteStatement}
|
|
1159
1376
|
}
|
|
1160
1377
|
|
|
1161
1378
|
where(...args: (string | number | boolean | undefined | null)[]): ${modelName}Model {
|
|
@@ -1181,9 +1398,9 @@ async function generateModelString(
|
|
|
1181
1398
|
let column: any
|
|
1182
1399
|
let operator: any
|
|
1183
1400
|
let value: any
|
|
1184
|
-
|
|
1401
|
+
|
|
1185
1402
|
const instance = new this(null)
|
|
1186
|
-
|
|
1403
|
+
|
|
1187
1404
|
if (args.length === 2) {
|
|
1188
1405
|
[column, value] = args
|
|
1189
1406
|
operator = '='
|
|
@@ -1192,9 +1409,9 @@ async function generateModelString(
|
|
|
1192
1409
|
} else {
|
|
1193
1410
|
throw new Error("Invalid number of arguments")
|
|
1194
1411
|
}
|
|
1195
|
-
|
|
1412
|
+
|
|
1196
1413
|
instance.query = instance.query.where(column, operator, value)
|
|
1197
|
-
|
|
1414
|
+
|
|
1198
1415
|
return instance
|
|
1199
1416
|
}
|
|
1200
1417
|
|
|
@@ -1202,9 +1419,9 @@ async function generateModelString(
|
|
|
1202
1419
|
|
|
1203
1420
|
static whereIn(column: keyof ${modelName}Type, values: any[]): ${modelName}Model {
|
|
1204
1421
|
const instance = new this(null)
|
|
1205
|
-
|
|
1422
|
+
|
|
1206
1423
|
instance.query = instance.query.where(column, 'in', values)
|
|
1207
|
-
|
|
1424
|
+
|
|
1208
1425
|
return instance
|
|
1209
1426
|
}
|
|
1210
1427
|
|
|
@@ -1214,16 +1431,16 @@ async function generateModelString(
|
|
|
1214
1431
|
if (! model) {
|
|
1215
1432
|
return undefined
|
|
1216
1433
|
}
|
|
1217
|
-
|
|
1218
|
-
return new ${modelName}Model(model)
|
|
1434
|
+
|
|
1435
|
+
return this.parseResult(new ${modelName}Model(model))
|
|
1219
1436
|
}
|
|
1220
1437
|
|
|
1221
1438
|
async exists(): Promise<boolean> {
|
|
1222
1439
|
const model = await this.query.selectAll().executeTakeFirst()
|
|
1223
|
-
|
|
1440
|
+
|
|
1224
1441
|
return model !== null || model !== undefined
|
|
1225
1442
|
}
|
|
1226
|
-
|
|
1443
|
+
|
|
1227
1444
|
static async first(): Promise<${modelName}Type | undefined> {
|
|
1228
1445
|
return await db.selectFrom('${tableName}')
|
|
1229
1446
|
.selectAll()
|
|
@@ -1239,29 +1456,29 @@ async function generateModelString(
|
|
|
1239
1456
|
|
|
1240
1457
|
static orderBy(column: keyof ${modelName}Type, order: 'asc' | 'desc'): ${modelName}Model {
|
|
1241
1458
|
const instance = new this(null)
|
|
1242
|
-
|
|
1459
|
+
|
|
1243
1460
|
instance.query = instance.orderBy(column, order)
|
|
1244
|
-
|
|
1461
|
+
|
|
1245
1462
|
return instance
|
|
1246
1463
|
}
|
|
1247
|
-
|
|
1464
|
+
|
|
1248
1465
|
orderBy(column: keyof ${modelName}Type, order: 'asc' | 'desc'): ${modelName}Model {
|
|
1249
1466
|
this.query = this.query.orderBy(column, order)
|
|
1250
|
-
|
|
1467
|
+
|
|
1251
1468
|
return this
|
|
1252
1469
|
}
|
|
1253
1470
|
|
|
1254
1471
|
static orderByDesc(column: keyof ${modelName}Type): ${modelName}Model {
|
|
1255
1472
|
const instance = new this(null)
|
|
1256
|
-
|
|
1473
|
+
|
|
1257
1474
|
instance.query = instance.query.orderBy(column, 'desc')
|
|
1258
|
-
|
|
1475
|
+
|
|
1259
1476
|
return instance
|
|
1260
1477
|
}
|
|
1261
|
-
|
|
1478
|
+
|
|
1262
1479
|
orderByDesc(column: keyof ${modelName}Type): ${modelName}Model {
|
|
1263
1480
|
this.query = this.orderBy(column, 'desc')
|
|
1264
|
-
|
|
1481
|
+
|
|
1265
1482
|
return this
|
|
1266
1483
|
}
|
|
1267
1484
|
|
|
@@ -1280,23 +1497,27 @@ async function generateModelString(
|
|
|
1280
1497
|
}
|
|
1281
1498
|
|
|
1282
1499
|
// Method to update the ${tableName} instance
|
|
1283
|
-
async update(${formattedModelName}: ${modelName}Update): Promise<${modelName}Model |
|
|
1500
|
+
async update(${formattedModelName}: ${modelName}Update): Promise<${modelName}Model | undefined> {
|
|
1284
1501
|
if (this.id === undefined)
|
|
1285
1502
|
throw new Error('${modelName} ID is undefined')
|
|
1286
1503
|
|
|
1287
|
-
const filteredValues = Object.keys(
|
|
1504
|
+
const filteredValues = Object.keys(${formattedModelName})
|
|
1288
1505
|
.filter(key => this.fillable.includes(key))
|
|
1289
1506
|
.reduce((obj, key) => {
|
|
1290
|
-
obj[key] =
|
|
1507
|
+
obj[key] = ${formattedModelName}[key]
|
|
1291
1508
|
return obj;
|
|
1292
1509
|
}, {});
|
|
1293
|
-
|
|
1510
|
+
|
|
1294
1511
|
await db.updateTable('${tableName}')
|
|
1295
1512
|
.set(filteredValues)
|
|
1296
1513
|
.where('id', '=', this.id)
|
|
1297
1514
|
.executeTakeFirst()
|
|
1298
|
-
|
|
1299
|
-
|
|
1515
|
+
|
|
1516
|
+
const model = this.find(Number(this.id))
|
|
1517
|
+
|
|
1518
|
+
${mittUpdateStatement}
|
|
1519
|
+
|
|
1520
|
+
return model
|
|
1300
1521
|
}
|
|
1301
1522
|
|
|
1302
1523
|
// Method to save (insert or update) the ${formattedModelName} instance
|
|
@@ -1316,43 +1537,57 @@ async function generateModelString(
|
|
|
1316
1537
|
}
|
|
1317
1538
|
}
|
|
1318
1539
|
|
|
1319
|
-
// Method to delete the ${formattedModelName} instance
|
|
1540
|
+
// Method to delete (soft delete) the ${formattedModelName} instance
|
|
1320
1541
|
async delete(): Promise<void> {
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1542
|
+
if (this.id === undefined)
|
|
1543
|
+
throw new Error('${modelName} ID is undefined');
|
|
1544
|
+
|
|
1545
|
+
// Check if soft deletes are enabled
|
|
1546
|
+
if (this.softDeletes) {
|
|
1547
|
+
// Update the deleted_at column with the current timestamp
|
|
1548
|
+
await db.updateTable('${tableName}')
|
|
1549
|
+
.set({
|
|
1550
|
+
deleted_at: sql.raw('CURRENT_TIMESTAMP')
|
|
1551
|
+
})
|
|
1552
|
+
.where('id', '=', this.id)
|
|
1553
|
+
.execute();
|
|
1554
|
+
} else {
|
|
1555
|
+
// Perform a hard delete
|
|
1556
|
+
await db.deleteFrom('${tableName}')
|
|
1557
|
+
.where('id', '=', this.id)
|
|
1558
|
+
.execute();
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
${mittDeleteStatement}
|
|
1327
1562
|
}
|
|
1328
1563
|
|
|
1329
1564
|
${relationMethods}
|
|
1330
1565
|
|
|
1331
1566
|
distinct(column: keyof ${modelName}Type): ${modelName}Model {
|
|
1332
1567
|
this.query = this.query.distinctOn(column)
|
|
1333
|
-
|
|
1568
|
+
|
|
1334
1569
|
return this
|
|
1335
1570
|
}
|
|
1336
|
-
|
|
1571
|
+
|
|
1337
1572
|
static distinct(column: keyof ${modelName}Type): ${modelName}Model {
|
|
1338
1573
|
const instance = new this(null)
|
|
1339
|
-
|
|
1574
|
+
|
|
1340
1575
|
instance.query = instance.query.distinctOn(column)
|
|
1341
|
-
|
|
1576
|
+
|
|
1342
1577
|
return instance
|
|
1343
1578
|
}
|
|
1344
|
-
|
|
1579
|
+
|
|
1345
1580
|
join(table: string, firstCol: string, secondCol: string): ${modelName}Model {
|
|
1346
1581
|
this.query = this.query.innerJoin(table, firstCol, secondCol)
|
|
1347
|
-
|
|
1582
|
+
|
|
1348
1583
|
return this
|
|
1349
1584
|
}
|
|
1350
|
-
|
|
1585
|
+
|
|
1351
1586
|
static join(table: string, firstCol: string, secondCol: string): ${modelName}Model {
|
|
1352
1587
|
const instance = new this(null)
|
|
1353
|
-
|
|
1588
|
+
|
|
1354
1589
|
instance.query = instance.query.innerJoin(table, firstCol, secondCol)
|
|
1355
|
-
|
|
1590
|
+
|
|
1356
1591
|
return instance
|
|
1357
1592
|
}
|
|
1358
1593
|
|
|
@@ -1361,7 +1596,7 @@ async function generateModelString(
|
|
|
1361
1596
|
}
|
|
1362
1597
|
|
|
1363
1598
|
toJSON() {
|
|
1364
|
-
const output: Partial<${modelName}Type> = {
|
|
1599
|
+
const output: Partial<${modelName}Type> = ${jsonFields}
|
|
1365
1600
|
|
|
1366
1601
|
this.hidden.forEach((attr) => {
|
|
1367
1602
|
if (attr in output)
|
|
@@ -1373,10 +1608,15 @@ async function generateModelString(
|
|
|
1373
1608
|
return output as ${modelName}
|
|
1374
1609
|
}
|
|
1375
1610
|
|
|
1376
|
-
parseResult(model:
|
|
1611
|
+
parseResult(model: ${modelName}Model): ${modelName}Model {
|
|
1612
|
+
delete model['query']
|
|
1613
|
+
delete model['fillable']
|
|
1614
|
+
delete model['two_factor_secret']
|
|
1615
|
+
delete model['hasSelect']
|
|
1616
|
+
delete model['softDeletes']
|
|
1617
|
+
|
|
1377
1618
|
for (const hiddenAttribute of this.hidden) {
|
|
1378
1619
|
delete model[hiddenAttribute]
|
|
1379
|
-
delete model.${formattedModelName}[hiddenAttribute]
|
|
1380
1620
|
}
|
|
1381
1621
|
|
|
1382
1622
|
return model
|
|
@@ -1385,7 +1625,7 @@ async function generateModelString(
|
|
|
1385
1625
|
${twoFactorStatements}
|
|
1386
1626
|
}
|
|
1387
1627
|
|
|
1388
|
-
async function find(id: number
|
|
1628
|
+
async function find(id: number): Promise<${modelName}Model | null> {
|
|
1389
1629
|
let query = db.selectFrom('${tableName}').where('id', '=', id)
|
|
1390
1630
|
|
|
1391
1631
|
if (fields) query = query.select(fields)
|
|
@@ -1421,7 +1661,7 @@ async function generateModelString(
|
|
|
1421
1661
|
.where('id', '=', id)
|
|
1422
1662
|
.execute()
|
|
1423
1663
|
}
|
|
1424
|
-
|
|
1664
|
+
|
|
1425
1665
|
${whereFunctionStatements}
|
|
1426
1666
|
|
|
1427
1667
|
const ${modelName} = ${modelName}Model
|