@stacksjs/database 0.59.10 → 0.61.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/index.js +59473 -0
- package/package.json +11 -6
- package/src/column.ts +6 -2
- package/src/drivers/index.ts +226 -0
- package/src/drivers/mysql.ts +276 -0
- package/src/drivers/postgres.ts +277 -0
- package/src/drivers/sqlite.ts +257 -0
- package/src/index.ts +1 -63
- package/src/migrations.ts +156 -57
- package/src/schema.ts +8 -5
- package/src/seeder.ts +167 -77
- package/src/table.ts +8 -5
- package/src/types.ts +3 -1
- package/src/utils.ts +50 -1
- package/dist/column.d.ts +0 -18
- package/dist/index.d.ts +0 -19
- package/dist/migrations.d.ts +0 -6
- package/dist/schema.d.ts +0 -4
- package/dist/table.d.ts +0 -8
- package/dist/types.d.ts +0 -1
- package/dist/utils.d.ts +0 -1
package/src/migrations.ts
CHANGED
|
@@ -1,73 +1,172 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { dim, italic, log } from '@stacksjs/cli'
|
|
2
|
+
import { database } from '@stacksjs/config'
|
|
3
|
+
import { err, ok } from '@stacksjs/error-handling'
|
|
4
|
+
import { extractFieldsFromModel } from '@stacksjs/orm'
|
|
5
|
+
import { path } from '@stacksjs/path'
|
|
6
|
+
import { fs, glob } from '@stacksjs/storage'
|
|
7
|
+
import type { Attribute, Attributes } from '@stacksjs/types'
|
|
8
|
+
import { $ } from 'bun'
|
|
9
|
+
import { FileMigrationProvider, Migrator } from 'kysely'
|
|
10
|
+
import { generateMysqlMigration, resetMysqlDatabase } from './drivers'
|
|
11
|
+
import { generatePostgresMigration, resetPostgresDatabase } from './drivers'
|
|
12
|
+
import { generateSqliteMigration, resetSqliteDatabase } from './drivers'
|
|
13
|
+
import { db } from './utils'
|
|
3
14
|
|
|
4
|
-
|
|
5
|
-
// import type { Model, SchemaOptions } from '@stacksjs/types'
|
|
6
|
-
// import { titleCase } from '@stacksjs/strings'
|
|
15
|
+
const driver = database.default || ''
|
|
7
16
|
|
|
8
|
-
|
|
17
|
+
export const migrator = new Migrator({
|
|
18
|
+
db,
|
|
9
19
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
20
|
+
provider: new FileMigrationProvider({
|
|
21
|
+
fs,
|
|
22
|
+
path,
|
|
23
|
+
// This needs to be an absolute path.
|
|
24
|
+
migrationFolder: path.userMigrationsPath(),
|
|
25
|
+
}),
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
27
|
+
migrationTableName: database.migrations,
|
|
28
|
+
migrationLockTableName: database.migrationLocks,
|
|
29
|
+
})
|
|
17
30
|
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// .map((file) => {
|
|
21
|
-
// const filePath = `${folderPath}/${file}`
|
|
31
|
+
// const migratorForeign = new Migrator({
|
|
32
|
+
// db,
|
|
22
33
|
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
34
|
+
// provider: new FileMigrationProvider({
|
|
35
|
+
// fs,
|
|
36
|
+
// path,
|
|
37
|
+
// // This needs to be an absolute path.
|
|
38
|
+
// migrationFolder: path.userMigrationsPath('foreign'),
|
|
39
|
+
// }),
|
|
40
|
+
// })
|
|
30
41
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// })
|
|
35
|
-
// })
|
|
36
|
-
// }
|
|
42
|
+
export async function runDatabaseMigration() {
|
|
43
|
+
try {
|
|
44
|
+
log.info('Migrating database...')
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
// const models = await readModelsFromFolder(projectPath('app/Models'))
|
|
46
|
+
const { error, results } = await migrator.migrateToLatest()
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
if (error) {
|
|
49
|
+
log.error(error)
|
|
50
|
+
return err(error)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (results?.length === 0) {
|
|
54
|
+
log.success('No new migrations were executed')
|
|
55
|
+
return ok('No new migrations were executed')
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (results) return ok(results)
|
|
59
|
+
|
|
60
|
+
log.success('Database migration completed with no new migrations.')
|
|
61
|
+
return ok('Database migration completed with no new migrations.')
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error('Migration failed:', error)
|
|
64
|
+
return err(error)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
43
67
|
|
|
44
68
|
export interface MigrationOptions {
|
|
45
69
|
name: string
|
|
46
70
|
up: string
|
|
47
|
-
down: string
|
|
48
71
|
}
|
|
49
72
|
|
|
50
|
-
export function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
export async function resetDatabase() {
|
|
74
|
+
if (driver === 'sqlite') return resetSqliteDatabase()
|
|
75
|
+
|
|
76
|
+
if (driver === 'mysql') return resetMysqlDatabase()
|
|
77
|
+
|
|
78
|
+
if (driver === 'postgres') return resetPostgresDatabase()
|
|
79
|
+
|
|
80
|
+
throw new Error('Unsupported database driver in resetDatabase')
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function generateMigrations() {
|
|
84
|
+
try {
|
|
85
|
+
log.info('Generating migrations...')
|
|
86
|
+
|
|
87
|
+
const modelFiles = glob.sync(path.userModelsPath('*.ts'))
|
|
88
|
+
|
|
89
|
+
for (const file of modelFiles) {
|
|
90
|
+
log.debug('Generating migration for:', file)
|
|
91
|
+
await generateMigration(file)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
log.success('Migrations generated')
|
|
95
|
+
return ok('Migrations generated')
|
|
96
|
+
} catch (error) {
|
|
97
|
+
return err(error)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function generateMigration(modelPath: string) {
|
|
102
|
+
if (driver === 'sqlite') generateSqliteMigration(modelPath)
|
|
103
|
+
|
|
104
|
+
if (driver === 'mysql') generateMysqlMigration(modelPath)
|
|
105
|
+
|
|
106
|
+
if (driver === 'postgres') generatePostgresMigration(modelPath)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function getExecutedMigrations() {
|
|
110
|
+
try {
|
|
111
|
+
// @ts-expect-error the migrations table is not typed yet
|
|
112
|
+
return await db.selectFrom('migrations').select('name').execute()
|
|
113
|
+
} catch (error) {
|
|
114
|
+
return []
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function haveModelFieldsChangedSinceLastMigration(modelPath: string) {
|
|
119
|
+
log.debug(`haveModelFieldsChangedSinceLastMigration for model: ${modelPath}`)
|
|
120
|
+
|
|
121
|
+
// const model = await import(modelPath)
|
|
122
|
+
// const tableName = model.default.table
|
|
123
|
+
// const lastMigration = await lastMigrationDate()
|
|
124
|
+
|
|
125
|
+
// now that we know the date, we need to check the git history for changes to the model file since that date
|
|
126
|
+
const cmd = ``
|
|
127
|
+
const gitHistory = await $`${cmd}`.text()
|
|
128
|
+
|
|
129
|
+
// if there are updates, then we need to check whether
|
|
130
|
+
// the updates include the any updates to the model
|
|
131
|
+
// fields that would require a migration
|
|
132
|
+
|
|
133
|
+
return !!gitHistory
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export async function lastMigration() {
|
|
137
|
+
try {
|
|
138
|
+
// @ts-expect-error the migrations table is not typed yet
|
|
139
|
+
return await db.selectFrom('migrations').selectAll().orderBy('timestamp', 'desc').limit(1).execute()
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.error('Failed to get last migration:', error)
|
|
142
|
+
return { error }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function lastMigrationDate(): Promise<string | undefined> {
|
|
147
|
+
try {
|
|
148
|
+
// @ts-expect-error the migrations table is not typed yet
|
|
149
|
+
return (await db.selectFrom('migrations').select('timestamp').orderBy('timestamp', 'desc').limit(1).execute())[0]
|
|
150
|
+
.timestamp
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.error('Failed to get last migration date:', error)
|
|
153
|
+
return undefined
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// This is a placeholder function. You need to implement the logic to
|
|
158
|
+
// read the last migration file and extract the fields that were modified.
|
|
159
|
+
export async function getLastMigrationFields(modelName: string): Promise<Attribute> {
|
|
160
|
+
const oldModelPath = path.frameworkPath(`database/models/${modelName}`)
|
|
161
|
+
const model = (await import(oldModelPath)).default as Model
|
|
162
|
+
let fields = {} as Attributes
|
|
163
|
+
|
|
164
|
+
if (typeof model.attributes === 'object') fields = model.attributes
|
|
165
|
+
else fields = JSON.parse(model.attributes) as Attributes
|
|
166
|
+
|
|
167
|
+
return fields
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export async function getCurrentMigrationFields(modelPath: string): Promise<Attribute | undefined> {
|
|
171
|
+
return extractFieldsFromModel(modelPath)
|
|
73
172
|
}
|
package/src/schema.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { log } from '@stacksjs/logging'
|
|
1
2
|
import { Table } from './table'
|
|
2
3
|
|
|
3
|
-
export
|
|
4
|
-
|
|
4
|
+
export const Schema = {
|
|
5
|
+
async createTable(tableName: string, callback: (table: Table) => void): Promise<void> {
|
|
5
6
|
const table = new Table()
|
|
7
|
+
|
|
6
8
|
callback(table)
|
|
9
|
+
|
|
7
10
|
table.execute() // Simulate the execution of the table creation
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
+
|
|
12
|
+
log.success(`Table "${tableName}" created.`)
|
|
13
|
+
},
|
|
11
14
|
}
|
package/src/seeder.ts
CHANGED
|
@@ -1,79 +1,169 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
// const queries = models.flatMap((model) => {
|
|
53
|
-
// const { seedable, fields } = model
|
|
54
|
-
|
|
55
|
-
// if (!seedable)
|
|
56
|
-
// return []
|
|
57
|
-
|
|
58
|
-
// const count = typeof seedable === 'boolean' ? 10 : seedable.count
|
|
59
|
-
|
|
60
|
-
// const records: Record<string, any>[] = []
|
|
61
|
-
// for (let i = 0; i < count; i++) {
|
|
62
|
-
// const record: Record<string, any> = {}
|
|
63
|
-
// Object.entries(fields).forEach(([name, field]) => {
|
|
64
|
-
// if (field.factory)
|
|
65
|
-
// record[name] = field.factory()
|
|
66
|
-
// })
|
|
67
|
-
// records.push(record)
|
|
68
|
-
// }
|
|
69
|
-
|
|
70
|
-
// return model
|
|
71
|
-
// // return db.insertInto('users').values(records).build(sql`RETURNING *`)
|
|
72
|
-
// })
|
|
73
|
-
|
|
74
|
-
// const { rows } = await db.transaction().execute()
|
|
75
|
-
|
|
76
|
-
// return rows
|
|
1
|
+
import { italic, log } from '@stacksjs/cli'
|
|
2
|
+
import { db } from '@stacksjs/database'
|
|
3
|
+
import { modelTableName } from '@stacksjs/orm'
|
|
4
|
+
import { path } from '@stacksjs/path'
|
|
5
|
+
import { fs, glob } from '@stacksjs/storage'
|
|
6
|
+
import { snakeCase } from '@stacksjs/strings'
|
|
7
|
+
import type { Model, RelationConfig } from '@stacksjs/types'
|
|
8
|
+
import { isString } from '@stacksjs/validation'
|
|
9
|
+
import { generateMigrations, resetDatabase, runDatabaseMigration } from './migrations'
|
|
10
|
+
|
|
11
|
+
async function seedModel(name: string, model?: Model) {
|
|
12
|
+
if (model?.traits?.useSeeder === false || model?.traits?.seedable === false) {
|
|
13
|
+
log.info(`Skipping seeding for ${italic(name)}`)
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!model) model = (await import(path.userModelsPath(name))) as Model
|
|
18
|
+
|
|
19
|
+
const tableName = await modelTableName(model)
|
|
20
|
+
const seedCount =
|
|
21
|
+
typeof model.traits?.useSeeder === 'object' && model.traits?.useSeeder?.count ? model.traits.useSeeder.count : 10
|
|
22
|
+
|
|
23
|
+
log.info(`Seeding ${seedCount} records into ${italic(tableName)}`)
|
|
24
|
+
|
|
25
|
+
const records = []
|
|
26
|
+
const otherRelations = await fetchOtherModelRelations(model)
|
|
27
|
+
|
|
28
|
+
log.debug(otherRelations)
|
|
29
|
+
|
|
30
|
+
for (let i = 0; i < seedCount; i++) {
|
|
31
|
+
const record: any = {}
|
|
32
|
+
|
|
33
|
+
for (const fieldName in model.attributes) {
|
|
34
|
+
const field = model.attributes[fieldName]
|
|
35
|
+
// Use the factory function if available, otherwise leave the field undefined
|
|
36
|
+
record[fieldName] = field?.factory ? field.factory() : undefined
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (otherRelations?.length) {
|
|
40
|
+
for (let j = 0; j < otherRelations.length; j++) {
|
|
41
|
+
const relationElement = otherRelations[j] as RelationConfig
|
|
42
|
+
|
|
43
|
+
record[relationElement?.foreignKey] = await seedModelRelation(relationElement?.relationModel as string)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
records.push(record)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// @ts-expect-error todo: we can improve this in the future
|
|
51
|
+
await db.insertInto(tableName).values(records).execute()
|
|
77
52
|
}
|
|
78
53
|
|
|
79
|
-
|
|
54
|
+
async function seedModelRelation(modelName: string): Promise<BigInt | number> {
|
|
55
|
+
const modelInstance = (await import(path.userModelsPath(modelName))).default
|
|
56
|
+
|
|
57
|
+
if (!modelInstance) return 1
|
|
58
|
+
|
|
59
|
+
const record: any = {}
|
|
60
|
+
const table = modelInstance.table
|
|
61
|
+
|
|
62
|
+
for (const fieldName in modelInstance.attributes) {
|
|
63
|
+
const field = modelInstance.attributes[fieldName]
|
|
64
|
+
// Use the factory function if available, otherwise leave the field undefined
|
|
65
|
+
record[fieldName] = field?.factory ? field.factory() : undefined
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const data = await db.insertInto(table).values(record).executeTakeFirstOrThrow()
|
|
69
|
+
|
|
70
|
+
return data.insertId || 1
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function getRelations(model: Model): Promise<RelationConfig[]> {
|
|
74
|
+
const relationsArray = ['hasOne', 'hasMany', 'belongsToMany', 'hasOneThrough']
|
|
75
|
+
const relationships = []
|
|
76
|
+
|
|
77
|
+
for (const relation of relationsArray) {
|
|
78
|
+
if (hasRelations(model, relation)) {
|
|
79
|
+
for (const relationInstance of model[relation]) {
|
|
80
|
+
let relationModel = relationInstance.model
|
|
81
|
+
|
|
82
|
+
if (isString(relationInstance)) {
|
|
83
|
+
relationModel = relationInstance
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const modelRelationPath = path.userModelsPath(`${relationModel}.ts`)
|
|
87
|
+
const modelRelation = (await import(modelRelationPath)).default
|
|
88
|
+
const formattedModelName = model.name?.toLowerCase()
|
|
89
|
+
|
|
90
|
+
relationships.push({
|
|
91
|
+
relationship: relation,
|
|
92
|
+
model: relationModel,
|
|
93
|
+
table: modelRelation.table,
|
|
94
|
+
relationModel: model.name,
|
|
95
|
+
relationTable: model.table,
|
|
96
|
+
foreignKey: relationInstance.foreignKey || `${formattedModelName}_id`,
|
|
97
|
+
relationName: relationInstance.relationName || '',
|
|
98
|
+
throughModel: relationInstance.through || '',
|
|
99
|
+
throughForeignKey: relationInstance.throughForeignKey || '',
|
|
100
|
+
pivotTable: relationInstance?.pivotTable || `${formattedModelName}_${modelRelation.table}`,
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return relationships
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function fetchOtherModelRelations(model: Model): Promise<RelationConfig[]> {
|
|
110
|
+
const modelFiles = glob.sync(path.userModelsPath('*.ts'))
|
|
111
|
+
const modelRelations = []
|
|
112
|
+
|
|
113
|
+
for (let i = 0; i < modelFiles.length; i++) {
|
|
114
|
+
const modelFileElement = modelFiles[i] as string
|
|
115
|
+
const modelFile = await import(modelFileElement)
|
|
116
|
+
|
|
117
|
+
if (model.name === modelFile.default.name) continue
|
|
118
|
+
|
|
119
|
+
const relations = await getRelations(modelFile.default)
|
|
120
|
+
|
|
121
|
+
if (!relations.length) continue
|
|
122
|
+
|
|
123
|
+
const relation = relations.find((relation) => relation.model === model.name)
|
|
124
|
+
|
|
125
|
+
if (relation) modelRelations.push(relation)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return modelRelations
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function hasRelations(obj: any, key: string): boolean {
|
|
132
|
+
return key in obj
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export async function seed() {
|
|
136
|
+
// TODO: need to check other databases too
|
|
137
|
+
const dbPath = path.userDatabasePath('stacks.sqlite')
|
|
138
|
+
|
|
139
|
+
if (!fs.existsSync(dbPath)) {
|
|
140
|
+
log.warn('No database found, configuring it...')
|
|
141
|
+
// first, ensure the database is reset
|
|
142
|
+
await resetDatabase()
|
|
143
|
+
|
|
144
|
+
// then, generate the migrations
|
|
145
|
+
await generateMigrations()
|
|
146
|
+
|
|
147
|
+
// finally, migrate the database
|
|
148
|
+
await runDatabaseMigration()
|
|
149
|
+
} else {
|
|
150
|
+
log.debug('Database configured...')
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// if a custom seeder exists, use it instead
|
|
154
|
+
const customSeederPath = path.userDatabasePath('seeder.ts')
|
|
155
|
+
if (fs.existsSync(customSeederPath)) {
|
|
156
|
+
log.info('Custom seeder found')
|
|
157
|
+
await import(customSeederPath)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// otherwise, seed all models
|
|
161
|
+
const modelsDir = path.userModelsPath()
|
|
162
|
+
const modelFiles = fs.readdirSync(modelsDir).filter((file) => file.endsWith('.ts'))
|
|
163
|
+
|
|
164
|
+
for (const file of modelFiles) {
|
|
165
|
+
const modelPath = path.join(modelsDir, file)
|
|
166
|
+
const model = await import(modelPath)
|
|
167
|
+
await seedModel(file, model.default)
|
|
168
|
+
}
|
|
169
|
+
}
|
package/src/table.ts
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
|
+
import { log } from '@stacksjs/logging'
|
|
1
2
|
import { Column } from './column'
|
|
2
3
|
|
|
3
4
|
export class Table {
|
|
4
5
|
private columns: Column[] = []
|
|
5
6
|
|
|
6
7
|
increments(name: string): Column {
|
|
7
|
-
const column = new Column(name, 'integer', {
|
|
8
|
+
const column = new Column(name, 'integer', {
|
|
9
|
+
primaryKey: true,
|
|
10
|
+
autoIncrement: true,
|
|
11
|
+
})
|
|
8
12
|
this.columns.push(column)
|
|
9
13
|
return column
|
|
10
14
|
}
|
|
11
15
|
|
|
12
|
-
string(name: string, varchar
|
|
16
|
+
string(name: string, varchar = 255): Column {
|
|
13
17
|
const column = new Column(name, `varchar(${varchar})`)
|
|
14
18
|
this.columns.push(column)
|
|
15
19
|
return column
|
|
@@ -22,8 +26,7 @@ export class Table {
|
|
|
22
26
|
|
|
23
27
|
// Method to simulate the execution of the schema definition
|
|
24
28
|
execute(): void {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// Here you would normally execute the SQL commands to create the table and columns in the database
|
|
29
|
+
log.info(`Creating table with columns: ${this.columns.map((col) => col.name).join(', ')}`)
|
|
30
|
+
// run kysely mirgration
|
|
28
31
|
}
|
|
29
32
|
}
|
package/src/types.ts
CHANGED
package/src/utils.ts
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { database } from '@stacksjs/config'
|
|
2
|
+
import { log } from '@stacksjs/logging'
|
|
3
|
+
import type { Database } from '@stacksjs/orm'
|
|
4
|
+
import { Kysely, MysqlDialect, PostgresDialect, sql } from 'kysely'
|
|
5
|
+
import { BunWorkerDialect } from 'kysely-bun-worker'
|
|
6
|
+
import { createPool } from 'mysql2'
|
|
7
|
+
import { Pool } from 'pg'
|
|
8
|
+
|
|
9
|
+
export function getDialect() {
|
|
10
|
+
const driver = database.default ?? 'sqlite'
|
|
11
|
+
|
|
12
|
+
log.debug(`Using database driver: ${driver}`)
|
|
13
|
+
|
|
14
|
+
if (driver === 'sqlite') {
|
|
15
|
+
const path = database.connections?.sqlite.database ?? 'database/stacks.sqlite'
|
|
16
|
+
return new BunWorkerDialect({
|
|
17
|
+
url: path,
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (driver === 'mysql') {
|
|
22
|
+
return new MysqlDialect({
|
|
23
|
+
pool: createPool({
|
|
24
|
+
database: database.connections?.mysql?.name ?? 'stacks',
|
|
25
|
+
host: database.connections?.mysql?.host ?? '127.0.0.1',
|
|
26
|
+
user: database.connections?.mysql?.username ?? 'root',
|
|
27
|
+
password: database.connections?.mysql?.password ?? '',
|
|
28
|
+
port: database.connections?.mysql?.port ?? 3306,
|
|
29
|
+
}),
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (driver === 'postgres') {
|
|
34
|
+
return new PostgresDialect({
|
|
35
|
+
pool: new Pool({
|
|
36
|
+
database: database.connections?.postgres?.name ?? 'stacks',
|
|
37
|
+
host: database.connections?.postgres?.host ?? '127.0.0.1',
|
|
38
|
+
user: database.connections?.postgres?.username ?? '',
|
|
39
|
+
password: database.connections?.postgres?.password ?? '',
|
|
40
|
+
port: database.connections?.postgres?.port ?? 5432,
|
|
41
|
+
}),
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
throw new Error(`Unsupported driver: ${driver}`)
|
|
46
|
+
}
|
|
2
47
|
|
|
3
48
|
export const now = sql`now()`
|
|
49
|
+
|
|
50
|
+
export const db = new Kysely<Database>({
|
|
51
|
+
dialect: getDialect(),
|
|
52
|
+
})
|
package/dist/column.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
interface Options {
|
|
2
|
-
notNull?: boolean;
|
|
3
|
-
default?: any;
|
|
4
|
-
primaryKey?: boolean;
|
|
5
|
-
autoIncrement?: boolean;
|
|
6
|
-
}
|
|
7
|
-
type ColumnType = 'integer' | 'varchar' | 'timestamp';
|
|
8
|
-
export declare class Column {
|
|
9
|
-
name: string;
|
|
10
|
-
type: ColumnType;
|
|
11
|
-
options: Options;
|
|
12
|
-
constructor(name: string, type: ColumnType, options?: Options);
|
|
13
|
-
notNullable(): this;
|
|
14
|
-
defaultTo(value: any): this;
|
|
15
|
-
primary(): this;
|
|
16
|
-
autoIncrement(): this;
|
|
17
|
-
}
|
|
18
|
-
export {};
|
package/dist/index.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Kysely } from 'kysely';
|
|
2
|
-
import type { ColumnType, Generated } from 'kysely';
|
|
3
|
-
export * from './schema';
|
|
4
|
-
export * from './migrations';
|
|
5
|
-
export * from './types';
|
|
6
|
-
export * from './utils';
|
|
7
|
-
export interface UsersTable {
|
|
8
|
-
id: Generated<number>;
|
|
9
|
-
name: string;
|
|
10
|
-
email: string;
|
|
11
|
-
password: string;
|
|
12
|
-
created_at: ColumnType<Date, string | undefined, never>;
|
|
13
|
-
deleted_at: ColumnType<Date, string | undefined, never>;
|
|
14
|
-
}
|
|
15
|
-
export interface Database {
|
|
16
|
-
users: UsersTable;
|
|
17
|
-
}
|
|
18
|
-
export declare const db: Kysely<Database>;
|
|
19
|
-
export declare const dbDialect: any;
|
package/dist/migrations.d.ts
DELETED
package/dist/schema.d.ts
DELETED
package/dist/table.d.ts
DELETED
package/dist/types.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { Kysely as Migration } from 'kysely';
|
package/dist/utils.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const now: import("kysely").RawBuilder<unknown>;
|