@stacksjs/database 0.65.0 → 0.67.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 +24 -27
- package/package.json +11 -13
- package/dist/index.js.map +0 -605
- package/src/column.ts +0 -36
- package/src/drivers/index.ts +0 -258
- package/src/drivers/mysql.ts +0 -389
- package/src/drivers/postgres.ts +0 -284
- package/src/drivers/sqlite.ts +0 -433
- package/src/index.ts +0 -6
- package/src/migrations.ts +0 -150
- package/src/schema.ts +0 -14
- package/src/seeder.ts +0 -166
- package/src/table.ts +0 -32
- package/src/types.ts +0 -5
- package/src/utils.ts +0 -62
package/src/seeder.ts
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import type { Model, RelationConfig } from '@stacksjs/types'
|
|
2
|
-
import { italic, log } from '@stacksjs/cli'
|
|
3
|
-
import { db } from '@stacksjs/database'
|
|
4
|
-
import { fetchOtherModelRelations, modelTableName } from '@stacksjs/orm'
|
|
5
|
-
import { path } from '@stacksjs/path'
|
|
6
|
-
|
|
7
|
-
import { makeHash } from '@stacksjs/security'
|
|
8
|
-
import { fs } from '@stacksjs/storage'
|
|
9
|
-
import { singular, snakeCase } from '@stacksjs/strings'
|
|
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)
|
|
18
|
-
model = (await import(path.userModelsPath(name))) as Model
|
|
19
|
-
|
|
20
|
-
const tableName = await modelTableName(model)
|
|
21
|
-
const seedCount
|
|
22
|
-
= typeof model.traits?.useSeeder === 'object' && model.traits?.useSeeder?.count ? model.traits.useSeeder.count : 10
|
|
23
|
-
|
|
24
|
-
log.info(`Seeding ${seedCount} records into ${italic(tableName)}`)
|
|
25
|
-
|
|
26
|
-
const records = []
|
|
27
|
-
const otherRelations = await fetchOtherModelRelations(model)
|
|
28
|
-
|
|
29
|
-
for (let i = 0; i < seedCount; i++) {
|
|
30
|
-
const record: any = {}
|
|
31
|
-
|
|
32
|
-
for (const fieldName in model.attributes) {
|
|
33
|
-
const formattedFieldName = snakeCase(fieldName)
|
|
34
|
-
const field = model.attributes[fieldName]
|
|
35
|
-
|
|
36
|
-
// Use the factory function if available, otherwise leave the field undefined
|
|
37
|
-
if (formattedFieldName === 'password')
|
|
38
|
-
record[formattedFieldName] = field?.factory ? await makeHash('Test@123', { algorithm: 'bcrypt' }) : undefined
|
|
39
|
-
else record[formattedFieldName] = field?.factory ? field.factory() : undefined
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (otherRelations?.length) {
|
|
43
|
-
for (let j = 0; j < otherRelations.length; j++) {
|
|
44
|
-
const relationElement = otherRelations[j] as RelationConfig
|
|
45
|
-
|
|
46
|
-
if (relationElement.relationship === 'belongsToMany') {
|
|
47
|
-
await seedPivotRelation(relationElement)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
record[relationElement?.foreignKey] = await seedModelRelation(relationElement?.relationModel as string)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
records.push(record)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// @ts-expect-error todo: we can improve this in the future
|
|
58
|
-
await db.insertInto(tableName).values(records).execute()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async function seedPivotRelation(relation: RelationConfig): Promise<any> {
|
|
62
|
-
const record: any = {}
|
|
63
|
-
const record2: any = {}
|
|
64
|
-
const pivotRecord: any = {}
|
|
65
|
-
|
|
66
|
-
const modelInstance = (await import(path.userModelsPath(relation?.model))).default
|
|
67
|
-
const relationModelInstance = (await import(path.userModelsPath(relation?.relationModel))).default
|
|
68
|
-
|
|
69
|
-
if (!relationModelInstance)
|
|
70
|
-
return 1
|
|
71
|
-
|
|
72
|
-
const relationModelTable = relationModelInstance.table
|
|
73
|
-
const relationTable = relation.table
|
|
74
|
-
const pivotTable = relation.pivotTable
|
|
75
|
-
const modelKey = `${singular(relationTable)}_id`
|
|
76
|
-
const foreignKey = relation.foreignKey
|
|
77
|
-
|
|
78
|
-
for (const fieldName in relationModelInstance.attributes) {
|
|
79
|
-
const formattedFieldName = snakeCase(fieldName)
|
|
80
|
-
const field = relationModelInstance.attributes[fieldName]
|
|
81
|
-
// Use the factory function if available, otherwise leave the field undefined
|
|
82
|
-
if (formattedFieldName === 'password')
|
|
83
|
-
record[formattedFieldName] = field?.factory ? await makeHash('Test@123', { algorithm: 'bcrypt' }) : undefined
|
|
84
|
-
else record[formattedFieldName] = field?.factory ? field.factory() : undefined
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
for (const fieldName in modelInstance.attributes) {
|
|
88
|
-
const formattedFieldName = snakeCase(fieldName)
|
|
89
|
-
const field = modelInstance.attributes[fieldName]
|
|
90
|
-
// Use the factory function if available, otherwise leave the field undefined
|
|
91
|
-
if (formattedFieldName === 'password')
|
|
92
|
-
record2[formattedFieldName] = field?.factory ? await makeHash('Test@123', { algorithm: 'bcrypt' }) : undefined
|
|
93
|
-
else record2[formattedFieldName] = field?.factory ? field.factory() : undefined
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const data = await db.insertInto(relationModelTable).values(record).executeTakeFirstOrThrow()
|
|
97
|
-
const data2 = await db.insertInto(relationTable).values(record2).executeTakeFirstOrThrow()
|
|
98
|
-
const relationData = data.insertId || 1
|
|
99
|
-
const modelData = data2.insertId || 1
|
|
100
|
-
|
|
101
|
-
pivotRecord[foreignKey] = relationData
|
|
102
|
-
pivotRecord[modelKey] = modelData
|
|
103
|
-
|
|
104
|
-
if (pivotTable)
|
|
105
|
-
await db.insertInto(pivotTable).values(pivotRecord).executeTakeFirstOrThrow()
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async function seedModelRelation(modelName: string): Promise<bigint | number> {
|
|
109
|
-
const modelInstance = (await import(path.userModelsPath(modelName))).default
|
|
110
|
-
|
|
111
|
-
if (!modelInstance)
|
|
112
|
-
return 1
|
|
113
|
-
|
|
114
|
-
const record: any = {}
|
|
115
|
-
const table = modelInstance.table
|
|
116
|
-
|
|
117
|
-
for (const fieldName in modelInstance.attributes) {
|
|
118
|
-
const formattedFieldName = snakeCase(fieldName)
|
|
119
|
-
const field = modelInstance.attributes[fieldName]
|
|
120
|
-
// Use the factory function if available, otherwise leave the field undefined
|
|
121
|
-
|
|
122
|
-
if (formattedFieldName === 'password')
|
|
123
|
-
record[formattedFieldName] = field?.factory ? await makeHash(field.factory(), { algorithm: 'bcrypt' }) : undefined
|
|
124
|
-
else record[formattedFieldName] = field?.factory ? field.factory() : undefined
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const data = await db.insertInto(table).values(record).executeTakeFirstOrThrow()
|
|
128
|
-
|
|
129
|
-
return data.insertId || 1
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export async function seed() {
|
|
133
|
-
// TODO: need to check other databases too
|
|
134
|
-
// const dbPath = path.userDatabasePath('stacks.sqlite')
|
|
135
|
-
|
|
136
|
-
// if (!fs.existsSync(dbPath)) {
|
|
137
|
-
// log.warn('No database found, configuring it...')
|
|
138
|
-
// // first, ensure the database is reset
|
|
139
|
-
// await resetDatabase()
|
|
140
|
-
|
|
141
|
-
// // then, generate the migrations
|
|
142
|
-
// await generateMigrations()
|
|
143
|
-
|
|
144
|
-
// // finally, migrate the database
|
|
145
|
-
// await runDatabaseMigration()
|
|
146
|
-
// } else {
|
|
147
|
-
// log.debug('Database configured...')
|
|
148
|
-
// }
|
|
149
|
-
|
|
150
|
-
// if a custom seeder exists, use it instead
|
|
151
|
-
const customSeederPath = path.userDatabasePath('seeder.ts')
|
|
152
|
-
if (fs.existsSync(customSeederPath)) {
|
|
153
|
-
log.info('Custom seeder found')
|
|
154
|
-
await import(customSeederPath)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// otherwise, seed all models
|
|
158
|
-
const modelsDir = path.userModelsPath()
|
|
159
|
-
const modelFiles = fs.readdirSync(modelsDir).filter(file => file.endsWith('.ts'))
|
|
160
|
-
|
|
161
|
-
for (const file of modelFiles) {
|
|
162
|
-
const modelPath = path.join(modelsDir, file)
|
|
163
|
-
const model = await import(modelPath)
|
|
164
|
-
await seedModel(file, model.default)
|
|
165
|
-
}
|
|
166
|
-
}
|
package/src/table.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { log } from '@stacksjs/logging'
|
|
2
|
-
import { Column } from './column'
|
|
3
|
-
|
|
4
|
-
export class Table {
|
|
5
|
-
private columns: Column[] = []
|
|
6
|
-
|
|
7
|
-
increments(name: string): Column {
|
|
8
|
-
const column = new Column(name, 'integer', {
|
|
9
|
-
primaryKey: true,
|
|
10
|
-
autoIncrement: true,
|
|
11
|
-
})
|
|
12
|
-
this.columns.push(column)
|
|
13
|
-
return column
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
string(name: string, varchar = 255): Column {
|
|
17
|
-
const column = new Column(name, `varchar(${varchar})`)
|
|
18
|
-
this.columns.push(column)
|
|
19
|
-
return column
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
timestamps(): void {
|
|
23
|
-
this.columns.push(new Column('created_at', 'timestamp'))
|
|
24
|
-
this.columns.push(new Column('updated_at', 'timestamp'))
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Method to simulate the execution of the schema definition
|
|
28
|
-
execute(): void {
|
|
29
|
-
log.info(`Creating table with columns: ${this.columns.map(col => col.name).join(', ')}`)
|
|
30
|
-
// run kysely mirgration
|
|
31
|
-
}
|
|
32
|
-
}
|
package/src/types.ts
DELETED
package/src/utils.ts
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type { Database } from '@stacksjs/orm'
|
|
2
|
-
import type { RawBuilder } from 'kysely'
|
|
3
|
-
import { app, database } from '@stacksjs/config'
|
|
4
|
-
import { log } from '@stacksjs/logging'
|
|
5
|
-
import { path } from '@stacksjs/path'
|
|
6
|
-
import { Kysely, MysqlDialect, PostgresDialect, sql } from 'kysely'
|
|
7
|
-
import { BunWorkerDialect } from 'kysely-bun-worker'
|
|
8
|
-
import { createPool } from 'mysql2'
|
|
9
|
-
import { Pool } from 'pg'
|
|
10
|
-
|
|
11
|
-
const appEnv = app.env || 'local'
|
|
12
|
-
|
|
13
|
-
export function getDialect(): MysqlDialect | PostgresDialect | BunWorkerDialect {
|
|
14
|
-
const driver = database.default ?? 'sqlite'
|
|
15
|
-
|
|
16
|
-
log.debug(`Using database driver: ${driver}`)
|
|
17
|
-
|
|
18
|
-
if (driver === 'sqlite') {
|
|
19
|
-
const defaultName = appEnv !== 'testing' ? 'database/stacks.sqlite' : 'database/stacks_testing.sqlite'
|
|
20
|
-
const sqliteDbName = database.connections?.sqlite.database ?? defaultName
|
|
21
|
-
const dbPath = path.projectPath(sqliteDbName)
|
|
22
|
-
|
|
23
|
-
return new BunWorkerDialect({
|
|
24
|
-
url: dbPath,
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (driver === 'mysql') {
|
|
29
|
-
return new MysqlDialect({
|
|
30
|
-
pool: createPool({
|
|
31
|
-
database: database.connections?.mysql?.name || 'stacks', // Use modified dbName
|
|
32
|
-
host: database.connections?.mysql?.host ?? '127.0.0.1',
|
|
33
|
-
user: database.connections?.mysql?.username ?? 'root',
|
|
34
|
-
password: database.connections?.mysql?.password ?? '',
|
|
35
|
-
port: database.connections?.mysql?.port ?? 3306,
|
|
36
|
-
}),
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (driver === 'postgres') {
|
|
41
|
-
const pgDbName = database.connections?.postgres?.name ?? 'stacks' // Default Postgres database name
|
|
42
|
-
const finalPgDbName = appEnv === 'testing' ? `${pgDbName}_testing` : pgDbName // Modify if testing
|
|
43
|
-
|
|
44
|
-
return new PostgresDialect({
|
|
45
|
-
pool: new Pool({
|
|
46
|
-
database: finalPgDbName, // Use modified pgDbName
|
|
47
|
-
host: database.connections?.postgres?.host ?? '127.0.0.1',
|
|
48
|
-
user: database.connections?.postgres?.username ?? '',
|
|
49
|
-
password: database.connections?.postgres?.password ?? '',
|
|
50
|
-
port: database.connections?.postgres?.port ?? 5432,
|
|
51
|
-
}),
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
throw new Error(`Unsupported driver: ${driver}`)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export const now: RawBuilder<any> = sql`now()`
|
|
59
|
-
|
|
60
|
-
export const db: Kysely<Database> = new Kysely<Database>({
|
|
61
|
-
dialect: getDialect(),
|
|
62
|
-
})
|