@stacksjs/actions 0.61.24 → 0.62.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.
@@ -1,10 +1,10 @@
1
1
  import { log } from '@stacksjs/logging'
2
+ import { getModelName, getTableName } from '@stacksjs/orm'
2
3
  import { path } from '@stacksjs/path'
3
4
  import { fs, glob } from '@stacksjs/storage'
4
- import { camelCase, pascalCase } from '@stacksjs/strings'
5
- import type { Model, RelationConfig } from '@stacksjs/types'
6
- import { isString, isBoolean } from '@stacksjs/validation'
7
- import { getModelName, getTableName} from '@stacksjs/orm'
5
+ import { camelCase, pascalCase, plural, singular } from '@stacksjs/strings'
6
+ import type { Attributes, Model, RelationConfig } from '@stacksjs/types'
7
+ import { isString } from '@stacksjs/validation'
8
8
  export interface FieldArrayElement {
9
9
  entity: string
10
10
  charValue?: string | null
@@ -41,7 +41,7 @@ async function generateApiRoutes(modelFiles: string[]) {
41
41
  if (middlewares.length) {
42
42
  for (let i = 0; i < middlewares.length; i++) {
43
43
  middlewareString += `'${middlewares[i]}'`
44
-
44
+
45
45
  if (i < middlewares.length - 1) {
46
46
  middlewareString += ','
47
47
  }
@@ -103,13 +103,33 @@ async function writeModelNames() {
103
103
  }
104
104
  }
105
105
 
106
- async function writeModelRequests() {
106
+ async function writeModelRequest() {
107
107
  const modelFiles = glob.sync(path.userModelsPath('*.ts'))
108
108
 
109
+ const requestD = Bun.file(path.frameworkPath('types/requests.d.ts'))
110
+ let importTypes = ``
111
+ let importTypesString = ``
112
+ let typeString = `import { Request } from '../core/router/src/request'\n\n`
113
+
114
+ typeString += `interface ValidationType {
115
+ rule: VineType;
116
+ message: { [key: string]: string };
117
+ }\n\n`
118
+
119
+ typeString += `interface ValidationField {
120
+ [key: string]: string | ValidationType;
121
+ validation: ValidationType;
122
+ }\n\n`
123
+
124
+ typeString += `interface CustomAttributes {
125
+ [key: string]: ValidationField
126
+ }\n\n`
127
+
109
128
  for (let i = 0; i < modelFiles.length; i++) {
129
+ let fieldStringType = ``
110
130
  let fieldString = ``
111
131
  let fieldStringInt = ``
112
- let fileString = `import { Request } from '@stacksjs/router'\nimport { validateField } from '@stacksjs/validation'\nimport type { RequestInstance } from '@stacksjs/types'\n\n`
132
+ 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`
113
133
 
114
134
  const modeFileElement = modelFiles[i] as string
115
135
 
@@ -117,35 +137,103 @@ async function writeModelRequests() {
117
137
  const modelName = getModelName(model, modeFileElement)
118
138
 
119
139
  const attributes = await extractFields(model, modeFileElement)
120
-
140
+
141
+ fieldString += ` id?: number\n`
142
+ fieldStringInt += `public id = 1\n`
143
+ fieldStringType += `'id' |`
144
+ let keyCounter = 0
145
+ let keyCounterForeign = 0
146
+
147
+ const otherModelRelations = await fetchOtherModelRelations(model, modelName)
148
+
121
149
  for (const attribute of attributes) {
122
150
  let defaultValue: any = `''`
123
- const entity = attribute.fieldArray?.entity === 'enum' ? 'string' : attribute.fieldArray?.entity
151
+ const entity = attribute.fieldArray?.entity === 'enum' ? 'string[]' : attribute.fieldArray?.entity
124
152
 
125
- if (attribute.fieldArray?.entity === 'boolean')
126
- defaultValue = false
153
+ if (attribute.fieldArray?.entity === 'boolean') defaultValue = false
127
154
 
128
- if (attribute.fieldArray?.entity === 'number')
129
- defaultValue = 0
155
+ if (attribute.fieldArray?.entity === 'number') defaultValue = 0
130
156
 
131
157
  fieldString += ` ${attribute.field}: ${entity}\n `
132
158
 
159
+ fieldStringType += `'${attribute.field}'`
160
+ if (keyCounter < attributes.length - 1) fieldStringType += ' |'
161
+
133
162
  fieldStringInt += `public ${attribute.field} = ${defaultValue}\n`
134
- }
163
+
164
+ keyCounter++
165
+ }
166
+
167
+ for (const otherModel of otherModelRelations) {
168
+ fieldString += ` ${otherModel.foreignKey}: number\n `
169
+
170
+ if (keyCounter >= attributes.length - 1) fieldStringType += ' |'
171
+
172
+ fieldStringType += `'${otherModel.foreignKey}'`
173
+
174
+ // if (keyCounterForeign < otherModelRelations.length - 1)
175
+ // fieldStringType += ' |'
176
+
177
+ fieldStringInt += `public ${otherModel.foreignKey} = 0\n`
178
+
179
+ keyCounterForeign++
180
+ }
181
+
182
+ fieldStringInt += `public created_at = ''
183
+ public updated_at = ''
184
+ public deleted_at = ''
185
+ `
186
+
187
+ fieldString += `created_at?: string
188
+ updated_at?: string
189
+ deleted_at?: string`
135
190
 
136
191
  const modelLowerCase = camelCase(modelName)
137
192
 
138
193
  const requestFile = Bun.file(path.projectStoragePath(`framework/requests/${modelName}Request.ts`))
139
194
 
140
- fileString += `export interface ${modelName}RequestType extends RequestInstance{
141
- validate(): void
195
+ importTypes = `${modelName}RequestType`
196
+ importTypesString += `${importTypes}`
197
+
198
+ if (i < modelFiles.length - 1) importTypesString += ` | `
199
+
200
+ fileString += `import type { ${importTypes} } from '../types/requests'\n\n`
201
+
202
+ fileString += `interface ValidationType {
203
+ rule: VineType;
204
+ message: { [key: string]: string };
205
+ }\n\n`
206
+
207
+ fileString += `interface ValidationField {
208
+ [key: string]: string | ValidationType;
209
+ validation: ValidationType;
210
+ }\n\n`
211
+
212
+ fileString += `interface CustomAttributes {
213
+ [key: string]: ValidationField
214
+ }`
215
+
216
+ const types = `export interface ${modelName}RequestType extends Request {
217
+ validate(attributes?: CustomAttributes): void
218
+ get(key: ${fieldStringType}): string | number | undefined;
142
219
  ${fieldString}
143
220
  }\n\n`
144
-
145
- fileString += `export class ${modelName}Request extends Request implements ${modelName}RequestType {
221
+
222
+ typeString += `interface RequestData${modelName} {
223
+ ${fieldString}
224
+ }\n`
225
+
226
+ typeString += types
227
+
228
+ fileString += `export class ${modelName}Request extends Request implements ${modelName}RequestType {
146
229
  ${fieldStringInt}
147
- public validate(): void {
148
- validateField('${modelName}', this.all())
230
+ public async validate(attributes?: CustomAttributes): Promise<void> {
231
+ if (attributes === undefined || attributes === null) {
232
+ await validateField('${modelName}', this.all())
233
+ } else {
234
+ await customValidate(attributes, this.all())
235
+ }
236
+
149
237
  }
150
238
  }
151
239
 
@@ -156,6 +244,12 @@ async function writeModelRequests() {
156
244
 
157
245
  writer.write(fileString)
158
246
  }
247
+
248
+ typeString += `export type ModelRequest = ${importTypesString}`
249
+
250
+ const requestWrite = requestD.writer()
251
+
252
+ requestWrite.write(typeString)
159
253
  }
160
254
 
161
255
  async function writeOrmActions(apiRoute: string, modelName: String): Promise<void> {
@@ -166,8 +260,7 @@ async function writeOrmActions(apiRoute: string, modelName: String): Promise<voi
166
260
 
167
261
  let handleString = ``
168
262
 
169
-
170
- actionString += ` import type { ${modelName}RequestType } from '../../requests/${modelName}Request'\n\n`
263
+ actionString += ` import type { ${modelName}RequestType } from '../../types/requests'\n\n`
171
264
 
172
265
  if (apiRoute === 'index') {
173
266
  handleString += `async handle(request: ${modelName}RequestType) {
@@ -203,6 +296,7 @@ async function writeOrmActions(apiRoute: string, modelName: String): Promise<voi
203
296
 
204
297
  if (apiRoute === 'store') {
205
298
  handleString += `async handle(request: ${modelName}RequestType) {
299
+ await request.validate()
206
300
  const model = await ${modelName}.create(request.all())
207
301
 
208
302
  return model
@@ -213,6 +307,8 @@ async function writeOrmActions(apiRoute: string, modelName: String): Promise<voi
213
307
 
214
308
  if (apiRoute === 'update') {
215
309
  handleString += `async handle(request: ${modelName}RequestType) {
310
+ await request.validate()
311
+
216
312
  const id = request.getParam('id')
217
313
 
218
314
  const model = await ${modelName}.findOrFail(Number(id))
@@ -242,10 +338,10 @@ async function initiateModelGeneration(): Promise<void> {
242
338
  await deleteExistingModels()
243
339
  await deleteExistingOrmActions()
244
340
  await deleteExistingModelNameTypes()
245
- await deleteExistingModelRequests()
341
+ await deleteExistingModelRequest()
246
342
 
247
343
  await writeModelNames()
248
- await writeModelRequests()
344
+ await writeModelRequest()
249
345
 
250
346
  const modelFiles = glob.sync(path.userModelsPath('*.ts'))
251
347
 
@@ -296,7 +392,9 @@ async function getRelations(model: Model, modelName: string): Promise<RelationCo
296
392
  relationName: relationInstance.relationName || '',
297
393
  throughModel: relationInstance.through || '',
298
394
  throughForeignKey: relationInstance.throughForeignKey || '',
299
- pivotTable: relationInstance?.pivotTable || `${formattedModelName}_${modelRelation.table}`,
395
+ pivotTable:
396
+ relationInstance?.pivotTable ||
397
+ getPivotTableName(plural(formattedModelName), plural(modelRelation.table || '')),
300
398
  })
301
399
  }
302
400
  }
@@ -305,6 +403,21 @@ async function getRelations(model: Model, modelName: string): Promise<RelationCo
305
403
  return relationships
306
404
  }
307
405
 
406
+ function getPivotTableName(formattedModelName: string, modelRelationTable: string): string {
407
+ // Create an array of the model names
408
+ const models = [formattedModelName, modelRelationTable]
409
+
410
+ // Sort the array alphabetically
411
+ models.sort()
412
+
413
+ models[0] = singular(models[0] || '')
414
+
415
+ // Join the sorted array with an underscore
416
+ const pivotTableName = models.join('_')
417
+
418
+ return pivotTableName
419
+ }
420
+
308
421
  function hasRelations(obj: any, key: string): boolean {
309
422
  return key in obj
310
423
  }
@@ -338,12 +451,15 @@ async function deleteExistingModelNameTypes() {
338
451
  if (fs.existsSync(typeFile)) await Bun.$`rm ${typeFile}`
339
452
  }
340
453
 
341
- async function deleteExistingModelRequests() {
454
+ async function deleteExistingModelRequest() {
342
455
  const requestFiles = glob.sync(path.projectStoragePath(`framework/requests/*.ts`))
456
+ const requestD = path.frameworkPath('types/requests.d.ts')
343
457
 
344
458
  for (const requestFile of requestFiles) {
345
459
  if (fs.existsSync(requestFile)) await Bun.$`rm ${requestFile}`
346
460
  }
461
+
462
+ if (fs.existsSync(requestD)) await Bun.$`rm ${requestD}`
347
463
  }
348
464
 
349
465
  async function setKyselyTypes() {
@@ -369,7 +485,7 @@ async function setKyselyTypes() {
369
485
  const model = (await import(modelFile)).default as Model
370
486
  const modelName = getModelName(model, modelFile)
371
487
  const pivotTables = await getPivotTables(model, modelName)
372
-
488
+
373
489
  for (const pivotTable of pivotTables) {
374
490
  const words = pivotTable.table.split('_')
375
491
 
@@ -413,7 +529,10 @@ async function setKyselyTypes() {
413
529
 
414
530
  async function extractFields(model: Model, modelFile: string): Promise<ModelElement[]> {
415
531
  // TODO: we can improve this type
416
- const fields: Record<string, any> = model.attributes
532
+ let fields: Record<string, any> | undefined = model.attributes
533
+
534
+ if (!fields) fields = {}
535
+
417
536
  const fieldKeys = Object.keys(fields)
418
537
 
419
538
  const rules: string[] = []
@@ -504,7 +623,7 @@ function getRelationCount(relation: string): string {
504
623
 
505
624
  async function getPivotTables(
506
625
  model: Model,
507
- modelName: string
626
+ modelName: string,
508
627
  ): Promise<{ table: string; firstForeignKey?: string; secondForeignKey?: string }[]> {
509
628
  const pivotTable = []
510
629
 
@@ -515,8 +634,7 @@ async function getPivotTables(
515
634
  const modelRelation = (await import(modelRelationPath)).default as Model
516
635
  const formattedModelName = modelName.toLowerCase()
517
636
 
518
- const firstForeignKey =
519
- belongsToManyRelation.firstForeignKey || `${modelName.toLowerCase()}_${model.primaryKey}`
637
+ const firstForeignKey = belongsToManyRelation.firstForeignKey || `${modelName.toLowerCase()}_${model.primaryKey}`
520
638
  const secondForeignKey =
521
639
  belongsToManyRelation.secondForeignKey || `${modelRelation.name?.toLowerCase()}_${model.primaryKey}`
522
640
 
@@ -540,7 +658,7 @@ export async function fetchOtherModelRelations(model: Model, modelName: string):
540
658
  for (let i = 0; i < modelFiles.length; i++) {
541
659
  const modelFileElement = modelFiles[i] as string
542
660
  const modelFile = await import(modelFileElement)
543
-
661
+
544
662
  if (modelName === modelFile.default.name) continue
545
663
 
546
664
  const otherModelName = getModelName(modelFile, modelFileElement)
@@ -557,13 +675,43 @@ export async function fetchOtherModelRelations(model: Model, modelName: string):
557
675
  return modelRelations
558
676
  }
559
677
 
560
- async function generateModelString(tableName: string, modelName: string, model: Model, attributes: ModelElement[]): Promise<string> {
678
+ function getHiddenAttributes(attributes: Attributes | undefined): string[] {
679
+ if (attributes === undefined) return []
680
+
681
+ return Object.keys(attributes).filter((key) => {
682
+ if (attributes === undefined) return false
683
+
684
+ return attributes[key]?.hidden === true
685
+ })
686
+ }
687
+
688
+ function getFillableAttributes(attributes: Attributes | undefined): string[] {
689
+ if (attributes === undefined) return []
690
+
691
+ return Object.keys(attributes).filter((key) => {
692
+ if (attributes === undefined) return false
693
+
694
+ return attributes[key]?.fillable === true
695
+ })
696
+ }
697
+
698
+ async function generateModelString(
699
+ tableName: string,
700
+ modelName: string,
701
+ model: Model,
702
+ attributes: ModelElement[],
703
+ ): Promise<string> {
561
704
  const formattedTableName = pascalCase(tableName) // users -> Users
562
705
  const formattedModelName = modelName.toLowerCase() // User -> user
563
706
 
564
707
  let fieldString = ''
708
+ let constructorFields = ''
709
+ let declareFields = ''
710
+ let whereStatements = ''
711
+ let whereFunctionStatements = ''
565
712
  let relationMethods = ``
566
713
  let relationImports = ``
714
+ let twoFactorStatements = ''
567
715
 
568
716
  const relations = await getRelations(model, modelName)
569
717
 
@@ -577,7 +725,6 @@ async function generateModelString(tableName: string, modelName: string, model:
577
725
  const tableRelation = relation.table || ''
578
726
  const pivotTableRelation = relation.pivotTable
579
727
  const formattedModelRelation = modelRelation.toLowerCase()
580
- const capitalizeTableRelation = tableRelation.charAt(0).toUpperCase() + tableRelation.slice(1)
581
728
 
582
729
  const relationType = getRelationType(relation.relationship)
583
730
  const relationCount = getRelationCount(relation.relationship)
@@ -592,21 +739,20 @@ async function generateModelString(tableName: string, modelName: string, model:
592
739
 
593
740
  relationMethods += `
594
741
  async ${relationName}() {
595
- if (this.${formattedModelName}.id === undefined)
742
+ if (this.id === undefined)
596
743
  throw new Error('Relation Error!')
597
744
 
598
745
  const firstModel = await db.selectFrom('${throughTableRelation}')
599
- .where('${foreignKeyRelation}', '=', this.${formattedModelName}.id)
600
- .selectAll()
601
- .executeTakeFirst()
746
+ .where('${foreignKeyRelation}', '=', this.id)
747
+ .selectAll()
748
+ .executeTakeFirst()
602
749
 
603
750
  if (! firstModel)
604
751
  throw new Error('Model Relation Not Found!')
605
752
 
606
- const finalModel = await db.selectFrom('${tableRelation}')
607
- .where('${foreignKeyThroughRelation}', '=', firstModel.id)
608
- .selectAll()
609
- .executeTakeFirst()
753
+ const finalModel = ${modelRelation}
754
+ .where('${foreignKeyThroughRelation}', '=', firstModel.id)
755
+ .first()
610
756
 
611
757
  return new ${modelRelation}.modelInstance(finalModel)
612
758
  }\n\n`
@@ -617,11 +763,11 @@ async function generateModelString(tableName: string, modelName: string, model:
617
763
 
618
764
  relationMethods += `
619
765
  async ${relationName}() {
620
- if (this.${formattedModelName}.id === undefined)
766
+ if (this.id === undefined)
621
767
  throw new Error('Relation Error!')
622
768
 
623
769
  const results = await db.selectFrom('${tableRelation}')
624
- .where('${foreignKeyRelation}', '=', this.${formattedModelName}.id)
770
+ .where('${foreignKeyRelation}', '=', this.id)
625
771
  .selectAll()
626
772
  .execute()
627
773
 
@@ -633,18 +779,16 @@ async function generateModelString(tableName: string, modelName: string, model:
633
779
  const relationName = relation.relationName || formattedModelRelation
634
780
  relationMethods += `
635
781
  async ${relationName}() {
636
- if (this.${formattedModelName}.id === undefined)
782
+ if (this.id === undefined)
637
783
  throw new Error('Relation Error!')
638
784
 
639
- const model = await db.selectFrom('${tableRelation}')
640
- .where('${foreignKeyRelation}', '=', this.${formattedModelName}.id)
641
- .selectAll()
642
- .executeTakeFirst()
785
+ const model = ${modelRelation}
786
+ .where('${foreignKeyRelation}', '=', this.id).first()
643
787
 
644
788
  if (! model)
645
789
  throw new Error('Model Relation Not Found!')
646
790
 
647
- return new ${modelRelation}.modelInstance(model)
791
+ return model
648
792
  }\n\n`
649
793
  }
650
794
 
@@ -656,47 +800,116 @@ async function generateModelString(tableName: string, modelName: string, model:
656
800
  if (this.${foreignKeyRelation} === undefined)
657
801
  throw new Error('Relation Error!')
658
802
 
659
- const model = await db.selectFrom('${tableRelation}')
660
- .where('id', '=', ${foreignKeyRelation})
661
- .selectAll()
662
- .executeTakeFirst()
803
+ const model = await ${modelRelation}
804
+ .where('id', '=', ${foreignKeyRelation})
805
+ .first()
663
806
 
664
807
  if (! model)
665
808
  throw new Error('Model Relation Not Found!')
666
809
 
667
- return new ${modelRelation}.modelInstance(model)
810
+ return model
668
811
  }\n\n`
669
812
  }
670
813
 
671
814
  if (relationType === 'belongsType' && relationCount === 'many') {
672
815
  const pivotTable = pivotTableRelation || tableRelation
673
- const relationName = relation.relationName || formattedModelName + capitalizeTableRelation
816
+ const relationName = relation.relationName || formattedModelName + plural(pascalCase(modelRelation))
674
817
 
675
818
  relationMethods += `
676
819
  async ${relationName}() {
677
- if (this.${formattedModelName}.id === undefined)
820
+ if (this.id === undefined)
678
821
  throw new Error('Relation Error!')
679
822
 
680
823
  const results = await db.selectFrom('${pivotTable}')
681
- .where('${foreignKeyRelation}', '=', this.${formattedModelName}.id)
824
+ .where('${foreignKeyRelation}', '=', this.id)
682
825
  .selectAll()
683
826
  .execute()
827
+
828
+ const tableRelationIds = results.map(result => result.${singular(tableRelation)}_id)
684
829
 
685
- return results
830
+ const relationResults = await ${modelRelation}.whereIn('id', tableRelationIds).get()
831
+
832
+ return relationResults
686
833
  }\n\n`
687
834
  }
688
835
  }
689
836
 
690
- for (const attribute of attributes) fieldString += ` ${attribute.field}: ${attribute.fieldArray?.entity}\n `
837
+ declareFields += `public id: number | undefined \n `
838
+
839
+ constructorFields += `this.id = ${formattedModelName}?.id\n `
840
+
841
+ const useTwoFactor = model.traits?.useAuth?.useTwoFactor
842
+
843
+ if (useTwoFactor) {
844
+ declareFields += `public two_factor_secret: string | undefined \n`
845
+ constructorFields += `this.two_factor_secret = ${formattedModelName}?.two_factor_secret\n `
846
+
847
+ twoFactorStatements += `
848
+ async generateTwoFactorForModel() {
849
+ const secret = generateTwoFactorSecret()
850
+
851
+ await this.update({ 'two_factor_secret': secret })
852
+ }
853
+
854
+ verifyTwoFactorCode(code: string): boolean {
855
+ if (! this.${formattedModelName}) return false
856
+
857
+ const modelTwoFactorSecret = this.${formattedModelName}.two_factor_secret
858
+ const isValid = verifyTwoFactorCode(code, modelTwoFactorSecret)
859
+
860
+ return isValid
861
+ }
862
+ `
863
+ }
864
+
865
+ for (const attribute of attributes) {
866
+ const entity = attribute.fieldArray?.entity === 'enum' ? 'string[]' : attribute.fieldArray?.entity
867
+
868
+ fieldString += ` ${attribute.field}: ${entity}\n `
869
+
870
+ declareFields += `public ${attribute.field}: ${entity} | undefined \n `
871
+
872
+ constructorFields += `this.${attribute.field} = ${formattedModelName}?.${attribute.field}\n `
873
+
874
+ whereStatements += `static where${pascalCase(attribute.field)}(value: string | number | boolean | undefined | null): ${modelName}Model {
875
+ const instance = new this(null)
876
+
877
+ instance.query = instance.query.where('${attribute.field}', '=', value)
878
+
879
+ return instance
880
+ } \n\n`
881
+
882
+ whereFunctionStatements += `export async function where${pascalCase(attribute.field)}(value: string | number | boolean | undefined | null): Promise<${modelName}Model[]> {
883
+ const query = db.selectFrom('${tableName}').where('${attribute.field}', '=', value)
884
+
885
+ const results = await query.execute()
886
+
887
+ return results.map(modelItem => new ${modelName}Model(modelItem))
888
+ } \n\n`
889
+ }
691
890
 
692
891
  const otherModelRelations = await fetchOtherModelRelations(model, modelName)
693
892
 
694
- for (const otherModelRelation of otherModelRelations) fieldString += ` ${otherModelRelation.foreignKey}: number \n`
893
+ for (const otherModelRelation of otherModelRelations) {
894
+ fieldString += ` ${otherModelRelation.foreignKey}: number \n`
895
+
896
+ declareFields += `public ${otherModelRelation.foreignKey}: number | undefined \n `
897
+
898
+ constructorFields += `this.${otherModelRelation.foreignKey} = ${formattedModelName}?.${otherModelRelation.foreignKey}\n `
899
+ }
900
+
901
+ if (useTwoFactor) {
902
+ fieldString += `two_factor_secret: string \n`
903
+ }
904
+
905
+ const hidden = JSON.stringify(getHiddenAttributes(model.attributes))
906
+ const fillable = JSON.stringify(getFillableAttributes(model.attributes))
695
907
 
696
908
  return `import type { ColumnType, Generated, Insertable, Selectable, Updateable } from 'kysely'
697
- import type { Result } from '@stacksjs/error-handling'
698
- import { err, handleError, ok } from '@stacksjs/error-handling'
699
909
  import { db } from '@stacksjs/database'
910
+ import { sql } from '@stacksjs/database'
911
+ import { generateTwoFactorSecret } from '@stacksjs/auth'
912
+ import { verifyTwoFactorCode } from '@stacksjs/auth'
700
913
  ${relationImports}
701
914
  // import { Kysely, MysqlDialect, PostgresDialect } from 'kysely'
702
915
  // import { Pool } from 'pg'
@@ -737,18 +950,24 @@ async function generateModelString(tableName: string, modelName: string, model:
737
950
  offset?: number
738
951
  page?: number
739
952
  }
740
-
953
+
741
954
  export class ${modelName}Model {
742
- private ${formattedModelName}: Partial<${modelName}Type>
743
- private results: Partial<${modelName}Type>[]
744
- private hidden = ['password'] // TODO: this hidden functionality needs to be implemented still
745
-
746
- constructor(${formattedModelName}: Partial<${modelName}Type>) {
955
+ private ${formattedModelName}: Partial<${modelName}Type> | null
956
+ private hidden = ${hidden}
957
+ private fillable = ${fillable}
958
+ protected query: any
959
+ protected hasSelect: boolean
960
+ ${declareFields}
961
+ constructor(${formattedModelName}: Partial<${modelName}Type> | null) {
747
962
  this.${formattedModelName} = ${formattedModelName}
963
+ ${constructorFields}
964
+
965
+ this.query = db.selectFrom('${tableName}')
966
+ this.hasSelect = false
748
967
  }
749
968
 
750
- // Method to find a ${formattedModelName} by ID
751
- static async find(id: number, fields?: (keyof ${modelName}Type)[]): Promise<${modelName}Model> {
969
+ // Method to find a ${modelName} by ID
970
+ async find(id: number, fields?: (keyof ${modelName}Type)[]): Promise<${modelName}Model | undefined> {
752
971
  let query = db.selectFrom('${tableName}').where('id', '=', id)
753
972
 
754
973
  if (fields)
@@ -759,30 +978,54 @@ async function generateModelString(tableName: string, modelName: string, model:
759
978
  const model = await query.executeTakeFirst()
760
979
 
761
980
  if (!model)
762
- return null
981
+ return undefined
982
+
983
+ return this.parseResult(this)
984
+ }
763
985
 
764
- return new ${modelName}Model(model)
986
+ // Method to find a ${modelName} by ID
987
+ static async find(id: number, fields?: (keyof ${modelName}Type)[]): Promise<${modelName}Model | undefined> {
988
+ let query = db.selectFrom('${tableName}').where('id', '=', id)
989
+
990
+ const instance = new this(null)
991
+
992
+ if (fields)
993
+ query = query.select(fields)
994
+ else
995
+ query = query.selectAll()
996
+
997
+ const model = await query.executeTakeFirst()
998
+
999
+ if (!model)
1000
+ return undefined
1001
+
1002
+ return instance.parseResult(new this(model))
765
1003
  }
766
1004
 
767
1005
  static async findOrFail(id: number, fields?: (keyof ${modelName}Type)[]): Promise<${modelName}Model> {
768
1006
  let query = db.selectFrom('${tableName}').where('id', '=', id)
769
1007
 
1008
+ const instance = new this(null)
1009
+
770
1010
  if (fields)
771
1011
  query = query.select(fields)
772
1012
  else
773
1013
  query = query.selectAll()
774
1014
 
775
1015
  const model = await query.executeTakeFirst()
776
-
1016
+
777
1017
  if (!model)
778
1018
  throw(\`No model results found for \${id}\ \`)
779
1019
 
780
- return new ${modelName}Model(model)
1020
+
1021
+ return instance.parseResult(new this(model))
781
1022
  }
782
1023
 
783
1024
  static async findMany(ids: number[], fields?: (keyof ${modelName}Type)[]): Promise<${modelName}Model[]> {
784
1025
  let query = db.selectFrom('${tableName}').where('id', 'in', ids)
785
1026
 
1027
+ const instance = new this(null)
1028
+
786
1029
  if (fields)
787
1030
  query = query.select(fields)
788
1031
  else
@@ -790,11 +1033,13 @@ async function generateModelString(tableName: string, modelName: string, model:
790
1033
 
791
1034
  const model = await query.execute()
792
1035
 
793
- return model.map(modelItem => new ${modelName}Model(modelItem))
1036
+ instance.parseResult(new ${modelName}Model(modelItem))
1037
+
1038
+ return model.map(modelItem => instance.parseResult(new ${modelName}Model(modelItem)))
794
1039
  }
795
1040
 
796
- // Method to get a ${formattedModelName} by criteria
797
- static async get(criteria: Partial<${modelName}Type>, options: QueryOptions = {}): Promise<${modelName}Model[]> {
1041
+ // Method to get a ${modelName} by criteria
1042
+ static async fetch(criteria: Partial<${modelName}Type>, options: QueryOptions = {}): Promise<${modelName}Model[]> {
798
1043
  let query = db.selectFrom('${tableName}')
799
1044
 
800
1045
  // Apply sorting from options
@@ -812,8 +1057,50 @@ async function generateModelString(tableName: string, modelName: string, model:
812
1057
  return model.map(modelItem => new ${modelName}Model(modelItem))
813
1058
  }
814
1059
 
1060
+ // Method to get a ${modelName} by criteria
1061
+ static async get(): Promise<${modelName}Model[]> {
1062
+ const query = db.selectFrom('${tableName}')
1063
+
1064
+ const model = await query.selectAll().execute()
1065
+
1066
+ return model.map(modelItem => new ${modelName}Model(modelItem))
1067
+ }
1068
+
1069
+ // Method to get a ${modelName} by criteria
1070
+ async get(): Promise<${modelName}Model[]> {
1071
+ if (this.hasSelect) {
1072
+ const model = await this.query.execute()
1073
+
1074
+ return model.map((modelItem: ${modelName}Model) => new ${modelName}Model(modelItem))
1075
+ }
1076
+
1077
+ const model = await this.query.selectAll().execute()
1078
+
1079
+ return model.map((modelItem: ${modelName}Model) => new ${modelName}Model(modelItem))
1080
+ }
1081
+
1082
+ static async count(): Promise<number> {
1083
+ const instance = new this(null)
1084
+
1085
+ const results = await instance.query.selectAll().execute()
1086
+
1087
+ return results.length
1088
+ }
1089
+
1090
+ async count(): Promise<number> {
1091
+ if (this.hasSelect) {
1092
+ const results = await this.query.execute()
1093
+
1094
+ return results.length
1095
+ }
1096
+
1097
+ const results = await this.query.selectAll().execute()
1098
+
1099
+ return results.length
1100
+ }
1101
+
815
1102
  // Method to get all ${tableName}
816
- static async all(options: QueryOptions = { limit: 10, offset: 0, page: 1 }): Promise<${modelName}Response> {
1103
+ static async paginate(options: QueryOptions = { limit: 10, offset: 0, page: 1 }): Promise<${modelName}Response> {
817
1104
  const totalRecordsResult = await db.selectFrom('${tableName}')
818
1105
  .select(db.fn.count('id').as('total')) // Use 'id' or another actual column name
819
1106
  .executeTakeFirst()
@@ -844,24 +1131,34 @@ async function generateModelString(tableName: string, modelName: string, model:
844
1131
  }
845
1132
 
846
1133
  // Method to create a new ${formattedModelName}
847
- static async create(new${modelName}: New${modelName}): Promise<${modelName}Model> {
1134
+ static async create(new${modelName}: New${modelName}): Promise<${modelName}Model | undefined> {
1135
+ const instance = new this(null)
1136
+ const filteredValues = Object.keys(new${modelName})
1137
+ .filter(key => instance.fillable.includes(key))
1138
+ .reduce((obj: any, key) => {
1139
+ obj[key] = new${modelName}[key];
1140
+ return obj
1141
+ }, {})
1142
+
1143
+ if (Object.keys(filteredValues).length === 0) {
1144
+ return undefined
1145
+ }
1146
+
848
1147
  const result = await db.insertInto('${tableName}')
849
- .values(new${modelName})
1148
+ .values(filteredValues)
850
1149
  .executeTakeFirstOrThrow()
851
1150
 
852
1151
  return await find(Number(result.insertId)) as ${modelName}Model
853
1152
  }
854
1153
 
855
- // Method to remove a ${formattedModelName}
856
- static async remove(id: number): Promise<${modelName}Model> {
857
- const model = await db.deleteFrom('${tableName}')
1154
+ // Method to remove a ${modelName}
1155
+ static async remove(id: number): Promise<void> {
1156
+ await db.deleteFrom('${tableName}')
858
1157
  .where('id', '=', id)
859
- .executeTakeFirstOrThrow()
860
-
861
- return new ${modelName}Model(model)
1158
+ .execute()
862
1159
  }
863
1160
 
864
- async where(...args: (string | number)[]): Promise<${modelName}Type[]> {
1161
+ where(...args: (string | number | boolean | undefined | null)[]): ${modelName}Model {
865
1162
  let column: any
866
1163
  let operator: any
867
1164
  let value: any
@@ -875,135 +1172,131 @@ async function generateModelString(tableName: string, modelName: string, model:
875
1172
  throw new Error("Invalid number of arguments")
876
1173
  }
877
1174
 
878
- let query = db.selectFrom('${tableName}')
879
-
880
- query = query.where(column, operator, value)
1175
+ this.query = this.query.where(column, operator, value)
881
1176
 
882
- return await query.selectAll().execute()
1177
+ return this
883
1178
  }
884
1179
 
885
- async whereIs(criteria: Partial<${modelName}Type>, options: QueryOptions = {}) {
886
- let query = db.selectFrom('${tableName}')
887
-
888
- // Existing criteria checks
889
- if (criteria.id)
890
- query = query.where('id', '=', criteria.id) // Kysely is immutable, we must re-assign
891
-
892
- if (criteria.email)
893
- query = query.where('email', '=', criteria.email)
894
-
895
- if (criteria.name !== undefined) {
896
- query = query.where(
897
- 'name',
898
- criteria.name === null ? 'is' : '=',
899
- criteria.name,
900
- )
1180
+ static where(...args: (string | number | boolean | undefined | null)[]): ${modelName}Model {
1181
+ let column: any
1182
+ let operator: any
1183
+ let value: any
1184
+
1185
+ const instance = new this(null)
1186
+
1187
+ if (args.length === 2) {
1188
+ [column, value] = args
1189
+ operator = '='
1190
+ } else if (args.length === 3) {
1191
+ [column, operator, value] = args
1192
+ } else {
1193
+ throw new Error("Invalid number of arguments")
901
1194
  }
902
-
903
- if (criteria.password)
904
- query = query.where('password', '=', criteria.password)
905
-
906
- if (criteria.created_at)
907
- query = query.where('created_at', '=', criteria.created_at)
908
-
909
- if (criteria.updated_at)
910
- query = query.where('updated_at', '=', criteria.updated_at)
911
-
912
- if (criteria.deleted_at)
913
- query = query.where('deleted_at', '=', criteria.deleted_at)
914
-
915
- // Apply sorting from options
916
- if (options.sort)
917
- query = query.orderBy(options.sort.column, options.sort.order)
918
-
919
- // Apply pagination from options
920
- if (options.limit !== undefined)
921
- query = query.limit(options.limit)
922
-
923
- if (options.offset !== undefined)
924
- query = query.offset(options.offset)
925
-
926
- return await query.selectAll().execute()
1195
+
1196
+ instance.query = instance.query.where(column, operator, value)
1197
+
1198
+ return instance
927
1199
  }
928
1200
 
929
- async whereIn(column: keyof ${modelName}Type, values: any[], options: QueryOptions = {}): Promise<${modelName}Type[]> {
930
-
931
- let query = db.selectFrom('${tableName}')
932
-
933
- query = query.where(column, 'in', values)
934
-
935
- // Apply sorting from options
936
- if (options.sort)
937
- query = query.orderBy(options.sort.column, options.sort.order)
1201
+ ${whereStatements}
938
1202
 
939
- // Apply pagination from options
940
- if (options.limit !== undefined)
941
- query = query.limit(options.limit)
1203
+ static whereIn(column: keyof ${modelName}Type, values: any[]): ${modelName}Model {
1204
+ const instance = new this(null)
1205
+
1206
+ instance.query = instance.query.where(column, 'in', values)
1207
+
1208
+ return instance
1209
+ }
942
1210
 
943
- if (options.offset !== undefined)
944
- query = query.offset(options.offset)
1211
+ async first(): Promise<${modelName}Model | undefined> {
1212
+ const model = await this.query.selectAll().executeTakeFirst()
945
1213
 
946
- return await query.selectAll().execute()
1214
+ if (! model) {
1215
+ return undefined
1216
+ }
1217
+
1218
+ return new ${modelName}Model(model)
947
1219
  }
948
1220
 
949
- async first(): Promise<${modelName}Type> {
1221
+ async exists(): Promise<boolean> {
1222
+ const model = await this.query.selectAll().executeTakeFirst()
1223
+
1224
+ return model !== null || model !== undefined
1225
+ }
1226
+
1227
+ static async first(): Promise<${modelName}Type | undefined> {
950
1228
  return await db.selectFrom('${tableName}')
951
1229
  .selectAll()
952
1230
  .executeTakeFirst()
953
1231
  }
954
1232
 
955
- async last(): Promise<${modelName}Type> {
1233
+ async last(): Promise<${modelName}Type | undefined> {
956
1234
  return await db.selectFrom('${tableName}')
957
1235
  .selectAll()
958
1236
  .orderBy('id', 'desc')
959
1237
  .executeTakeFirst()
960
1238
  }
961
1239
 
962
- async orderBy(column: keyof ${modelName}Type, order: 'asc' | 'desc'): Promise<${modelName}Type[]> {
963
- return await db.selectFrom('${tableName}')
964
- .selectAll()
965
- .orderBy(column, order)
966
- .execute()
1240
+ static orderBy(column: keyof ${modelName}Type, order: 'asc' | 'desc'): ${modelName}Model {
1241
+ const instance = new this(null)
1242
+
1243
+ instance.query = instance.orderBy(column, order)
1244
+
1245
+ return instance
967
1246
  }
968
-
969
- async orderByDesc(column: keyof ${modelName}Type): Promise<${modelName}Type[]> {
970
- return await db.selectFrom('${tableName}')
971
- .selectAll()
972
- .orderBy(column, 'desc')
973
- .execute()
1247
+
1248
+ orderBy(column: keyof ${modelName}Type, order: 'asc' | 'desc'): ${modelName}Model {
1249
+ this.query = this.query.orderBy(column, order)
1250
+
1251
+ return this
974
1252
  }
975
1253
 
976
- async orderByAsc(column: keyof ${modelName}Type): Promise<${modelName}Type[]> {
977
- return await db.selectFrom('${tableName}')
978
- .selectAll()
979
- .orderBy(column, 'asc')
980
- .execute()
1254
+ static orderByDesc(column: keyof ${modelName}Type): ${modelName}Model {
1255
+ const instance = new this(null)
1256
+
1257
+ instance.query = instance.query.orderBy(column, 'desc')
1258
+
1259
+ return instance
981
1260
  }
982
-
983
- // Method to get the ${formattedModelName} instance itself
984
- self(): ${modelName}Model {
1261
+
1262
+ orderByDesc(column: keyof ${modelName}Type): ${modelName}Model {
1263
+ this.query = this.orderBy(column, 'desc')
1264
+
985
1265
  return this
986
1266
  }
987
1267
 
988
- // Method to get the ${formattedModelName} instance data
989
- get() {
990
- return this.${formattedModelName}
1268
+ static orderByAsc(column: keyof ${modelName}Type): ${modelName}Model {
1269
+ const instance = new this(null)
1270
+
1271
+ instance.query = instance.query.orderBy(column, 'desc')
1272
+
1273
+ return instance
991
1274
  }
992
1275
 
993
- // Method to update the ${formattedModelName} instance
994
- async update(${formattedModelName}: ${modelName}Update): Promise<Result<${modelName}Type, Error>> {
995
- if (this.${formattedModelName}.id === undefined)
996
- return err(handleError('${modelName} ID is undefined'))
1276
+ orderByAsc(column: keyof ${modelName}Type): ${modelName}Model {
1277
+ this.query = this.query.orderBy(column, 'desc')
997
1278
 
998
- const updatedModel = await db.updateTable('${tableName}')
999
- .set(${formattedModelName})
1000
- .where('id', '=', this.${formattedModelName}.id)
1001
- .executeTakeFirst()
1279
+ return this
1280
+ }
1002
1281
 
1003
- if (!updatedModel)
1004
- return err(handleError('${modelName} not found'))
1282
+ // Method to update the ${tableName} instance
1283
+ async update(${formattedModelName}: ${modelName}Update): Promise<${modelName}Model | null> {
1284
+ if (this.id === undefined)
1285
+ throw new Error('${modelName} ID is undefined')
1005
1286
 
1006
- return ok(updatedModel)
1287
+ const filteredValues = Object.keys(new${modelName})
1288
+ .filter(key => this.fillable.includes(key))
1289
+ .reduce((obj, key) => {
1290
+ obj[key] = new${modelName}[key];
1291
+ return obj;
1292
+ }, {});
1293
+
1294
+ await db.updateTable('${tableName}')
1295
+ .set(filteredValues)
1296
+ .where('id', '=', this.id)
1297
+ .executeTakeFirst()
1298
+
1299
+ return await this.find(Number(this.id))
1007
1300
  }
1008
1301
 
1009
1302
  // Method to save (insert or update) the ${formattedModelName} instance
@@ -1025,33 +1318,47 @@ async function generateModelString(tableName: string, modelName: string, model:
1025
1318
 
1026
1319
  // Method to delete the ${formattedModelName} instance
1027
1320
  async delete(): Promise<void> {
1028
- if (this.${formattedModelName}.id === undefined)
1321
+ if (this.id === undefined)
1029
1322
  throw new Error('${modelName} ID is undefined')
1030
-
1323
+
1031
1324
  await db.deleteFrom('${tableName}')
1032
- .where('id', '=', this.${formattedModelName}.id)
1325
+ .where('id', '=', this.id)
1033
1326
  .execute()
1034
-
1035
- this.${formattedModelName} = {}
1036
1327
  }
1037
1328
 
1038
- // Method to refresh the ${formattedModelName} instance data from the database
1039
- async refresh(): Promise<void> {
1040
- if (this.${formattedModelName}.id === undefined)
1041
- throw new Error('${modelName} ID is undefined')
1042
-
1043
- const refreshedModel = await db.selectFrom('${tableName}')
1044
- .where('id', '=', this.${formattedModelName}.id)
1045
- .selectAll()
1046
- .executeTakeFirst()
1047
-
1048
- if (!refreshedModel)
1049
- throw new Error('${modelName} not found')
1329
+ ${relationMethods}
1050
1330
 
1051
- this.${formattedModelName} = refreshedModel
1331
+ distinct(column: keyof ${modelName}Type): ${modelName}Model {
1332
+ this.query = this.query.distinctOn(column)
1333
+
1334
+ return this
1335
+ }
1336
+
1337
+ static distinct(column: keyof ${modelName}Type): ${modelName}Model {
1338
+ const instance = new this(null)
1339
+
1340
+ instance.query = instance.query.distinctOn(column)
1341
+
1342
+ return instance
1343
+ }
1344
+
1345
+ join(table: string, firstCol: string, secondCol: string): ${modelName}Model {
1346
+ this.query = this.query.innerJoin(table, firstCol, secondCol)
1347
+
1348
+ return this
1349
+ }
1350
+
1351
+ static join(table: string, firstCol: string, secondCol: string): ${modelName}Model {
1352
+ const instance = new this(null)
1353
+
1354
+ instance.query = instance.query.innerJoin(table, firstCol, secondCol)
1355
+
1356
+ return instance
1052
1357
  }
1053
1358
 
1054
- ${relationMethods}
1359
+ static async rawQuery(rawQuery: string): Promise<any> {
1360
+ return await sql\`\${rawQuery}\`\.execute(db)
1361
+ }
1055
1362
 
1056
1363
  toJSON() {
1057
1364
  const output: Partial<${modelName}Type> = { ...this.${formattedModelName} }
@@ -1065,259 +1372,59 @@ async function generateModelString(tableName: string, modelName: string, model:
1065
1372
 
1066
1373
  return output as ${modelName}
1067
1374
  }
1068
- }
1069
1375
 
1070
- const Model = ${modelName}Model
1071
-
1072
- // starting here, ORM functions
1073
- export async function find(id: number, fields?: (keyof ${modelName}Type)[]) {
1074
- let query = db.selectFrom('${tableName}').where('id', '=', id)
1075
-
1076
- if (fields)
1077
- query = query.select(fields)
1078
- else
1079
- query = query.selectAll()
1080
-
1081
- const model = await query.executeTakeFirst()
1376
+ parseResult(model: any): ${modelName}Model {
1377
+ for (const hiddenAttribute of this.hidden) {
1378
+ delete model[hiddenAttribute]
1379
+ delete model.${formattedModelName}[hiddenAttribute]
1380
+ }
1082
1381
 
1083
- if (!model)
1084
- return null
1382
+ return model
1383
+ }
1085
1384
 
1086
- return new ${modelName}Model(model)
1385
+ ${twoFactorStatements}
1087
1386
  }
1088
1387
 
1089
- export async function findOrFail(id: number, fields?: (keyof ${modelName}Type)[]) {
1388
+ async function find(id: number, fields?: (keyof ${modelName}Type)[]): Promise<${modelName}Model | null> {
1090
1389
  let query = db.selectFrom('${tableName}').where('id', '=', id)
1091
1390
 
1092
- if (fields)
1093
- query = query.select(fields)
1094
- else
1095
- query = query.selectAll()
1391
+ if (fields) query = query.select(fields)
1392
+ else query = query.selectAll()
1096
1393
 
1097
1394
  const model = await query.executeTakeFirst()
1098
1395
 
1099
- if (!model)
1100
- throw(\`No model results found for \${id}\ \`)
1396
+ if (!model) return null
1101
1397
 
1102
1398
  return new ${modelName}Model(model)
1103
1399
  }
1104
1400
 
1105
- export async function findMany(ids: number[], fields?: (keyof ${modelName}Type)[]) {
1106
- let query = db.selectFrom('${tableName}').where('id', 'in', ids)
1107
-
1108
- if (fields)
1109
- query = query.select(fields)
1110
- else
1111
- query = query.selectAll()
1112
-
1113
- const model = await query.execute()
1114
-
1115
- return model.map(modelItem => new ${modelName}Model(modelItem))
1116
- }
1117
-
1118
- export async function count(): Number {
1119
- const results = await db.selectFrom('${tableName}')
1120
- .selectAll()
1121
- .execute()
1401
+ export async function count(): Promise<number> {
1402
+ const results = await ${modelName}Model.count()
1122
1403
 
1123
- return results.length
1124
- }
1125
-
1126
- export async function get(criteria: Partial<${modelName}Type>, sort: { column: keyof ${modelName}Type, order: 'asc' | 'desc' } = { column: 'created_at', order: 'desc' }) {
1127
- let query = db.selectFrom('${tableName}')
1128
-
1129
- if (criteria.id)
1130
- query = query.where('id', '=', criteria.id) // Kysely is immutable, we must re-assign
1131
-
1132
- if (criteria.email)
1133
- query = query.where('email', '=', criteria.email)
1134
-
1135
- if (criteria.name !== undefined) {
1136
- query = query.where(
1137
- 'name',
1138
- criteria.name === null ? 'is' : '=',
1139
- criteria.name,
1140
- )
1141
- }
1142
-
1143
- if (criteria.password)
1144
- query = query.where('password', '=', criteria.password)
1145
-
1146
- if (criteria.created_at)
1147
- query = query.where('created_at', '=', criteria.created_at)
1148
-
1149
- if (criteria.updated_at)
1150
- query = query.where('updated_at', '=', criteria.updated_at)
1151
-
1152
- if (criteria.deleted_at)
1153
- query = query.where('deleted_at', '=', criteria.deleted_at)
1154
-
1155
- // Apply sorting based on the 'sort' parameter
1156
- query = query.orderBy(sort.column, sort.order)
1157
-
1158
- return await query.selectAll().execute()
1159
- }
1160
-
1161
- export async function all(limit: number = 10, offset: number = 0): Promise<${modelName}Type[]> {
1162
- return await db.selectFrom('${tableName}')
1163
- .selectAll()
1164
- .orderBy('created_at', 'desc')
1165
- .limit(limit)
1166
- .offset(offset)
1167
- .execute()
1404
+ return results
1168
1405
  }
1169
1406
 
1170
1407
  export async function create(new${modelName}: New${modelName}): Promise<${modelName}Model> {
1171
1408
  const result = await db.insertInto('${tableName}')
1172
- .values(new${modelName})
1173
- .executeTakeFirstOrThrow()
1409
+ .values(new${modelName})
1410
+ .executeTakeFirstOrThrow()
1174
1411
 
1175
- return await find(Number(result.insertId))
1412
+ return await find(Number(result.insertId)) as ${modelName}Model
1176
1413
  }
1177
1414
 
1178
- export async function first(): Promise<${modelName}Model> {
1179
- return await db.selectFrom('${tableName}')
1180
- .selectAll()
1181
- .executeTakeFirst()
1415
+ export async function rawQuery(rawQuery: string): Promise<any> {
1416
+ return await sql\`\${rawQuery}\`\.execute(db)
1182
1417
  }
1183
1418
 
1184
- export async function recent(limit: number): Promise<${modelName}Model[]> {
1185
- return await db.selectFrom('${tableName}')
1186
- .selectAll()
1187
- .limit(limit)
1188
- .execute()
1189
- }
1190
-
1191
- export async function last(limit: number): Promise<${modelName}Type> {
1192
- return await db.selectFrom('${tableName}')
1193
- .selectAll()
1194
- .orderBy('id', 'desc')
1195
- .limit(limit)
1196
- .execute()
1197
- }
1198
-
1199
- export async function update(id: number, ${formattedModelName}Update: ${modelName}Update) {
1200
- return await db.updateTable('${tableName}')
1201
- .set(${formattedModelName}Update)
1419
+ export async function remove(id: number): Promise<void> {
1420
+ await db.deleteFrom('${tableName}')
1202
1421
  .where('id', '=', id)
1203
1422
  .execute()
1204
1423
  }
1424
+
1425
+ ${whereFunctionStatements}
1205
1426
 
1206
- export async function remove(id: number) {
1207
- return await db.deleteFrom('${tableName}')
1208
- .where('id', '=', id)
1209
- .executeTakeFirst()
1210
- }
1211
-
1212
- export async function where(...args: (string | number)[]) {
1213
- let column: any
1214
- let operator: any
1215
- let value: any
1216
-
1217
- if (args.length === 2) {
1218
- [column, value] = args
1219
- operator = '='
1220
- } else if (args.length === 3) {
1221
- [column, operator, value] = args
1222
- } else {
1223
- throw new Error("Invalid number of arguments")
1224
- }
1225
-
1226
- let query = db.selectFrom('${tableName}')
1227
-
1228
- query = query.where(column, operator, value)
1229
-
1230
- return await query.selectAll().execute()
1231
- }
1232
-
1233
- export async function whereIs(
1234
- criteria: Partial<${modelName}Type>,
1235
- options: QueryOptions = {},
1236
- ) {
1237
- let query = db.selectFrom('${tableName}')
1238
-
1239
- // Apply criteria
1240
- if (criteria.id)
1241
- query = query.where('id', '=', criteria.id)
1242
-
1243
- if (criteria.email)
1244
- query = query.where('email', '=', criteria.email)
1245
-
1246
- if (criteria.name !== undefined) {
1247
- query = query.where(
1248
- 'name',
1249
- criteria.name === null ? 'is' : '=',
1250
- criteria.name,
1251
- )
1252
- }
1253
-
1254
- if (criteria.password)
1255
- query = query.where('password', '=', criteria.password)
1256
-
1257
- if (criteria.created_at)
1258
- query = query.where('created_at', '=', criteria.created_at)
1259
-
1260
- if (criteria.updated_at)
1261
- query = query.where('updated_at', '=', criteria.updated_at)
1262
-
1263
- if (criteria.deleted_at)
1264
- query = query.where('deleted_at', '=', criteria.deleted_at)
1265
-
1266
- // Apply sorting from options
1267
- if (options.sort)
1268
- query = query.orderBy(options.sort.column, options.sort.order)
1269
-
1270
- // Apply pagination from options
1271
- if (options.limit !== undefined)
1272
- query = query.limit(options.limit)
1273
-
1274
- if (options.offset !== undefined)
1275
- query = query.offset(options.offset)
1276
-
1277
- return await query.selectAll().execute()
1278
- }
1279
-
1280
- export async function whereIn(
1281
- column: keyof ${modelName}Type,
1282
- values: any[],
1283
- options: QueryOptions = {},
1284
- ) {
1285
- let query = db.selectFrom('${tableName}')
1286
-
1287
- query = query.where(column, 'in', values)
1288
-
1289
- // Apply sorting from options
1290
- if (options.sort)
1291
- query = query.orderBy(options.sort.column, options.sort.order)
1292
-
1293
- // Apply pagination from options
1294
- if (options.limit !== undefined)
1295
- query = query.limit(options.limit)
1296
-
1297
- if (options.offset !== undefined)
1298
- query = query.offset(options.offset)
1299
-
1300
- return await query.selectAll().execute()
1301
- }
1302
-
1303
- export const ${modelName} = {
1304
- find,
1305
- findOrFail,
1306
- findMany,
1307
- get,
1308
- count,
1309
- all,
1310
- create,
1311
- update,
1312
- remove,
1313
- Model,
1314
- first,
1315
- last,
1316
- recent,
1317
- where,
1318
- whereIn,
1319
- model: ${modelName}Model
1320
- }
1427
+ const ${modelName} = ${modelName}Model
1321
1428
 
1322
1429
  export default ${modelName}
1323
1430
  `