Skip to content

Commit fb3ee13

Browse files
chore: wip
1 parent abeeebf commit fb3ee13

File tree

9 files changed

+146
-191
lines changed

9 files changed

+146
-191
lines changed

bun.lockb

25.5 KB
Binary file not shown.

database/migrations/1711346999980-create-subscribers-table.ts

Lines changed: 0 additions & 11 deletions
This file was deleted.

database/migrations/1711346999981-create-users-table.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 1 addition & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,3 @@
1-
import User from '../../../../../../app/Models/User'
2-
3-
export interface ModelElement {
4-
field: string
5-
default: string | number | boolean | Date | undefined | null
6-
unique: boolean
7-
fieldArray: FieldArrayElement[]
8-
}
9-
10-
export interface FieldArrayElement {
11-
entity: string
12-
charValue?: string | null
13-
// Add other properties as needed
14-
}
15-
const rules: string[] = []
16-
17-
async function extractModelRule() {
18-
const modelFile = Bun.file('../../../../../app/Models/User.ts') // Assuming Bun is imported properly
19-
20-
const code = await modelFile.text()
21-
22-
const regex = /rule:.*$/gm
23-
24-
let match: RegExpExecArray | null
25-
match = regex.exec(code)
26-
while (match !== null) {
27-
rules.push(match[0])
28-
match = regex.exec(code)
29-
}
30-
}
31-
32-
await extractModelRule()
33-
34-
// TODO: we can improve this type
35-
const fields: Record<string, any> = User.fields
36-
const fieldKeys = Object.keys(fields)
37-
38-
const input: ModelElement[] = fieldKeys.map((field, index) => {
39-
const fieldExist = fields[field]
40-
let defaultValue = null
41-
let uniqueValue = false
42-
43-
if (fieldExist) {
44-
defaultValue = fieldExist.default || null
45-
uniqueValue = fieldExist.unique || false
46-
}
47-
48-
return {
49-
field,
50-
default: defaultValue,
51-
unique: uniqueValue,
52-
fieldArray: parseRule(rules[index] ?? ''),
53-
}
54-
})
55-
56-
function parseRule(rule: string): FieldArrayElement[] {
57-
const parts = rule.split('rule: validator.')
58-
59-
if (parts.length !== 2)
60-
return []
61-
62-
if (!parts[1])
63-
parts[1] = ''
64-
65-
const extractedString = parts[1].replace(/,/g, '')
66-
67-
if (!extractedString)
68-
return []
69-
70-
const extractedParts = extractedString.split('.')
71-
const regex = /\(([^)]+)\)/
72-
73-
return extractedParts.map((input) => {
74-
const match = regex.exec(input)
75-
const value = match ? match[1] : null
76-
const field = input.replace(regex, '').replace(/\(|\)/g, '')
77-
return { entity: field, charValue: value }
78-
})
79-
}
80-
81-
const modelEntity: ModelElement[] = input
82-
83-
// You can now use the modelEntity array with type safety.
841

852
const fieldAssociation: { [key: string]: { [key: string]: string } } = {
863
mysql: {
@@ -99,13 +16,4 @@ const fieldAssociation: { [key: string]: { [key: string]: string } } = {
9916
},
10017
}
10118

102-
const fieldEntity = [
103-
'maxLength',
104-
]
105-
106-
const excludeFieldEntity = [
107-
'minLength',
108-
'enum',
109-
]
110-
111-
export { fieldEntity, fieldAssociation, modelEntity, excludeFieldEntity }
19+
export { fieldAssociation}
Lines changed: 53 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,59 @@
1-
// import { generateMigrationFile } from '@stacksjs/database'
2-
import User from '../../../../../../app/Models/User'
3-
import { fieldAssociation, modelEntity } from './fields'
4-
5-
const file = Bun.file('user-migration.ts')
6-
const writer = file.writer()
7-
8-
const driver = 'sqlite'
9-
10-
writer.write('import { db, sql, Database } from \'@stacksjs/database\'\n')
11-
writer.write('\n')
12-
writer.write('export async function up(db: Database<any>) {\n')
13-
14-
writer.write(' await db.schema\n')
15-
writer.write(` .createTable('${User.table}')\n`)
16-
17-
writer.write(' .addColumn(\'id\', \'integer\', (col) => col.primaryKey())\n')
18-
19-
for (let modelIndex = 0; modelIndex < modelEntity.length; modelIndex++) {
20-
const modelElement = modelEntity[modelIndex]
21-
22-
if (!modelElement)
23-
continue
24-
25-
let entity = ''
26-
let characteristic = ''
27-
28-
const isNullablePresent = modelElement.fieldArray.some(item => item.entity === 'nullable')
29-
30-
if (modelElement.default)
31-
characteristic += `.defaultTo('${modelElement.default.toString()}')`
32-
33-
if (modelElement.unique)
34-
characteristic += '.unique()'
35-
36-
if (!isNullablePresent)
37-
characteristic += '.notNull()'
38-
39-
for (let fieldIndex = 0; fieldIndex < modelElement.fieldArray.length; fieldIndex++) {
40-
const fieldArrayElement = modelElement.fieldArray[fieldIndex]
41-
42-
if (!fieldArrayElement)
43-
continue
44-
45-
if (!fieldAssociation[driver])
46-
continue
47-
48-
if (fieldAssociation[driver][fieldArrayElement.entity])
49-
entity += `${fieldAssociation[driver][fieldArrayElement.entity]}`
1+
import { Attributes } from "@stacksjs/types"
2+
3+
export async function createTableMigration(modelPath: string) {
4+
5+
log.debug('createTableMigration modelPath:', modelPath)
6+
7+
const model = await import(modelPath)
8+
const tableName = model.default.table
9+
10+
const fields = model.default.attributes
11+
const useTimestamps = model.default?.traits?.useTimestamps ?? model.default?.traits?.timestampable
12+
const useSoftDeletes = model.default?.traits?.useSoftDeletes ?? model.default?.traits?.softDeletable
13+
14+
let migrationContent = `import type { Database } from '@stacksjs/database'\n`
15+
migrationContent += `import { sql } from '@stacksjs/database'\n\n`
16+
migrationContent += `export async function up(db: Database<any>) {\n`
17+
migrationContent += ` await db.schema\n`
18+
migrationContent += ` .createTable('${tableName}')\n`
19+
20+
for (const [fieldName, options] of Object.entries(fields)) {
21+
const fieldOptions = options as Attributes
22+
const columnType = mapFieldTypeToColumnType(fieldOptions.validator?.rule)
23+
migrationContent += ` .addColumn('${fieldName}', '${columnType}'`
24+
25+
// Check if there are configurations that require the lambda function
26+
if (fieldOptions.unique || (fieldOptions.validator?.rule?.required)) {
27+
migrationContent += `, col => col`
28+
if (fieldOptions.unique)
29+
migrationContent += `.unique()`
30+
if (fieldOptions.validator?.rule?.required)
31+
migrationContent += `.notNull()`
32+
migrationContent += ``
33+
}
34+
35+
migrationContent += `)\n`
36+
}
5037

51-
// fieldEntity.forEach((entityField) => {
52-
// if (fieldArrayElement.entity === entityField)
53-
// entity += `(${fieldArrayElement.charValue})`
54-
// })
38+
// Append created_at and updated_at columns if useTimestamps is true
39+
if (useTimestamps) {
40+
migrationContent += ` .addColumn('created_at', 'timestamp', col => col.notNull().defaultTo(sql.raw('CURRENT_TIMESTAMP')))\n`
41+
migrationContent += ` .addColumn('updated_at', 'timestamp')\n`
5542
}
5643

57-
writer.write(` .addColumn('${modelElement.field}', '${entity}', (col) => col${characteristic})\n`)
58-
}
44+
// Append deleted_at column if useSoftDeletes is true
45+
if (useSoftDeletes)
46+
migrationContent += ` .addColumn('deleted_at', 'timestamp')\n`
47+
48+
migrationContent += ` .execute()\n`
49+
migrationContent += `}\n`
5950

60-
writer.write(' .addColumn(\'created_at\', \'timestamp\', (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`).notNull())\n')
61-
writer.write(' .execute()\n')
62-
writer.write('}\n\n')
51+
const timestamp = new Date().getTime().toString()
52+
const migrationFileName = `${timestamp}-create-${tableName}-table.ts`
53+
const migrationFilePath = path.userMigrationsPath(migrationFileName)
6354

64-
writer.write('process.exit(0)\n')
55+
// Assuming fs.writeFileSync is available or use an equivalent method
56+
Bun.write(migrationFilePath, migrationContent)
6557

66-
await writer.end()
58+
log.success(`Created migration: ${migrationFileName}`)
59+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import process from 'node:process'
2+
import { log } from '@stacksjs/logging'
3+
import { resetDatabase, runDatabaseMigration } from '@stacksjs/database'
4+
5+
// this is run and checks whether new created or update migrations need to be generated
6+
const result = await resetDatabase()
7+
8+
if (result?.isErr()) {
9+
console.error(result.error)
10+
log.error('[stacks] generateMigrations failed', result.error)
11+
process.exit(1)
12+
}
13+
14+
process.exit(0)

storage/framework/core/buddy/src/commands/migrate.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,26 @@ export function migrate(buddy: CLI) {
3535
process.exit(ExitCode.Success)
3636
})
3737

38+
buddy
39+
.command('migrate:fresh', descriptions.migrate)
40+
.option('-d, --diff', 'Show the SQL that would be run', { default: false })
41+
.option('-p, --project', descriptions.project, { default: false })
42+
.option('--verbose', descriptions.verbose, { default: false })
43+
.action(async (options: MigrateOptions) => {
44+
log.debug('Running `buddy migrate:fresh` ...', options)
45+
46+
const perf = await intro('buddy migrate:fresh')
47+
const result = await runAction(Action.MigrateFresh, options)
48+
49+
if (result.isErr()) {
50+
await outro('While running the migrate command, there was an issue', { startTime: perf, useSeconds: true }, result.error)
51+
process.exit()
52+
}
53+
54+
await outro(`All tables dropped successfully`, { startTime: perf, useSeconds: true })
55+
process.exit(ExitCode.Success)
56+
})
57+
3858
buddy
3959
.command('migrate:dns', descriptions.migrate)
4060
.option('-p, --project', descriptions.project, { default: false })

0 commit comments

Comments
 (0)