@@ -20,13 +20,68 @@ export function getTableName(model: Model, modelPath: string): string {
2020 return snakeCase ( plural ( getModelName ( model , modelPath ) ) )
2121}
2222
23- export function generateOrmModelString ( modelName : string , tableName : string ) : string {
23+ function extractHiddenFields ( model : Model ) : string [ ] {
24+ if ( ! model . attributes ) return [ ]
25+
26+ return Object . keys ( model . attributes ) . filter ( key =>
27+ model . attributes ?. [ key ] ?. hidden === true
28+ ) . map ( field => snakeCase ( field ) )
29+ }
30+
31+ function extractFillableFields ( model : Model ) : string [ ] {
32+ if ( ! model . attributes ) return [ ]
33+
34+ const fillable = Object . keys ( model . attributes ) . filter ( key =>
35+ model . attributes ?. [ key ] ?. fillable === true
36+ ) . map ( field => snakeCase ( field ) )
37+
38+ // Add trait-specific fillable fields
39+ const additionalFields : string [ ] = [ ]
40+
41+ if ( model . traits ?. useUuid ) {
42+ additionalFields . push ( 'uuid' )
43+ }
44+
45+ if ( model . traits ?. useAuth ) {
46+ const useAuth = model . traits . useAuth
47+ if ( typeof useAuth === 'object' && useAuth . usePasskey ) {
48+ additionalFields . push ( 'two_factor_secret' , 'public_key' )
49+ }
50+ }
51+
52+ return [ ...fillable , ...additionalFields ]
53+ }
54+
55+ function extractGuardedFields ( model : Model ) : string [ ] {
56+ if ( ! model . attributes ) return [ ]
57+
58+ return Object . keys ( model . attributes ) . filter ( key =>
59+ model . attributes ?. [ key ] ?. guarded === true
60+ ) . map ( field => snakeCase ( field ) )
61+ }
62+
63+ export function generateOrmModelString ( modelName : string , tableName : string , model : Model ) : string {
64+ const hidden = extractHiddenFields ( model )
65+ const fillable = extractFillableFields ( model )
66+ const guarded = extractGuardedFields ( model )
67+
68+ const hiddenArray = hidden . length > 0 ? `['${ hidden . join ( "', '" ) } ']` : '[]'
69+ const fillableArray = fillable . length > 0 ? `['${ fillable . join ( "', '" ) } ']` : '[]'
70+ const guardedArray = guarded . length > 0 ? `['${ guarded . join ( "', '" ) } ']` : '[]'
71+
2472 return `import { db2 } from '../../db'
2573
2674class ${ modelName } Model {
75+ private readonly hidden: string[] = ${ hiddenArray }
76+ private readonly fillable: string[] = ${ fillableArray }
77+ private readonly guarded: string[] = ${ guardedArray }
78+ protected attributes: Record<string, any> = {}
2779 private query: any
2880
29- constructor() {
81+ constructor(data?: Record<string, any>) {
82+ if (data) {
83+ this.attributes = { ...data }
84+ }
3085 this.query = db2.selectFrom('${ tableName } ')
3186 }
3287
@@ -37,22 +92,26 @@ class ${modelName}Model {
3792
3893 // Find by ID
3994 static async find(id: number) {
40- return await db2.selectFrom('${ tableName } ').where('id', '=', id).executeTakeFirst()
95+ const result = await db2.selectFrom('${ tableName } ').where('id', '=', id).executeTakeFirst()
96+ return result ? new ${ modelName } Model(result) : undefined
4197 }
4298
4399 // Get all records
44100 static async all() {
45- return await db2.selectFrom('${ tableName } ').execute()
101+ const results = await db2.selectFrom('${ tableName } ').execute()
102+ return results.map((result: any) => new ${ modelName } Model(result))
46103 }
47104
48105 // Get the first record
49106 async first() {
50- return await this.query.executeTakeFirst()
107+ const result = await this.query.executeTakeFirst()
108+ return result ? new ${ modelName } Model(result) : undefined
51109 }
52110
53111 // Get all records from the query
54112 async get() {
55- return await this.query.execute()
113+ const results = await this.query.execute()
114+ return results.map((result: any) => new ${ modelName } Model(result))
56115 }
57116
58117 // Chainable where clause
@@ -82,6 +141,83 @@ class ${modelName}Model {
82141 this.query = this.query.limit(count)
83142 return this
84143 }
144+
145+ // Create a new record
146+ static async create(data: Record<string, any>) {
147+ const instance = new ${ modelName } Model()
148+
149+ // Filter based on fillable and guarded
150+ const filteredData = Object.fromEntries(
151+ Object.entries(data).filter(([key]) =>
152+ !instance.guarded.includes(key) && instance.fillable.includes(key)
153+ )
154+ )
155+
156+ const result = await db2.insertInto('${ tableName } ')
157+ .values(filteredData)
158+ .execute()
159+
160+ // Fetch the created record
161+ const created = await db2.selectFrom('${ tableName } ')
162+ .where('id', '=', Number((result as any).insertId))
163+ .executeTakeFirst()
164+
165+ return created ? new ${ modelName } Model(created) : undefined
166+ }
167+
168+ // Update the current record
169+ async update(data: Record<string, any>) {
170+ if (!this.attributes.id) {
171+ throw new Error('Cannot update a model without an ID')
172+ }
173+
174+ // Filter based on fillable and guarded
175+ const filteredData = Object.fromEntries(
176+ Object.entries(data).filter(([key]) =>
177+ !this.guarded.includes(key) && this.fillable.includes(key)
178+ )
179+ )
180+
181+ await (db2 as any).updateTable('${ tableName } ')
182+ .set(filteredData)
183+ .where('id', '=', this.attributes.id)
184+ .execute()
185+
186+ // Fetch the updated record
187+ const updated = await db2.selectFrom('${ tableName } ')
188+ .where('id', '=', this.attributes.id)
189+ .executeTakeFirst()
190+
191+ if (updated) {
192+ this.attributes = { ...updated }
193+ }
194+
195+ return this
196+ }
197+
198+ // Delete the current record
199+ async delete() {
200+ if (!this.attributes.id) {
201+ throw new Error('Cannot delete a model without an ID')
202+ }
203+
204+ await (db2 as any).deleteFrom('${ tableName } ')
205+ .where('id', '=', this.attributes.id)
206+ .execute()
207+
208+ return true
209+ }
210+
211+ // Convert to JSON (excluding hidden fields)
212+ toJSON() {
213+ const json = { ...this.attributes }
214+
215+ for (const field of this.hidden) {
216+ delete json[field]
217+ }
218+
219+ return json
220+ }
85221}
86222
87223export default ${ modelName } Model
@@ -99,7 +235,7 @@ export async function generateOrmModels(): Promise<void> {
99235 const modelName = getModelName ( model , userModelFile )
100236 const tableName = getTableName ( model , userModelFile )
101237
102- const modelString = generateOrmModelString ( modelName , tableName )
238+ const modelString = generateOrmModelString ( modelName , tableName , model )
103239
104240 // Ensure the directory exists
105241 const ormModelsDir = path . storagePath ( 'framework/core/db/src/orm/Models' )
@@ -118,7 +254,7 @@ export async function generateOrmModel(modelPath: string): Promise<void> {
118254 const modelName = getModelName ( model , modelPath )
119255 const tableName = getTableName ( model , modelPath )
120256
121- const modelString = generateOrmModelString ( modelName , tableName )
257+ const modelString = generateOrmModelString ( modelName , tableName , model )
122258
123259 // Ensure the directory exists
124260 const ormModelsDir = path . storagePath ( 'framework/core/db/src/orm/Models' )
0 commit comments