Skip to content

Commit aa0447d

Browse files
chore: wip
1 parent 15abefc commit aa0447d

File tree

11 files changed

+88
-61
lines changed

11 files changed

+88
-61
lines changed

app/Models/Post.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ export default {
3838
rule: schema.string(),
3939
message: '`body` must be a string',
4040
},
41-
42-
factory: () => faker.lorem.sentence({ min: 25, max: 40 }),
41+
factory: () => faker.lorem.sentence({ min: 10, max: 10 }),
4342
},
4443
},
4544
} satisfies Model

database/migrations/1715787552142-create-subscribers-table.ts renamed to database/migrations/1715865558985-create-subscribers-table.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export async function up(db: Database<any>) {
77
.addColumn('id', 'integer', col => col.primaryKey().autoIncrement())
88
.addColumn('subscribed', 'boolean')
99
.addColumn('user_id', 'integer', (col) =>
10-
col.references('users.id').onDelete('cascade').notNull()
10+
col.references('users.id').onDelete('cascade')
1111
)
1212
.addColumn('created_at', 'timestamp', col => col.notNull().defaultTo(sql.raw('CURRENT_TIMESTAMP')))
1313
.addColumn('updated_at', 'timestamp')

database/migrations/1715787552140-create-posts-table.ts renamed to database/migrations/1715865558987-create-posts-table.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export async function up(db: Database<any>) {
88
.addColumn('title', 'varchar(255)')
99
.addColumn('body', 'varchar(255)')
1010
.addColumn('user_id', 'integer', (col) =>
11-
col.references('users.id').onDelete('cascade').notNull()
11+
col.references('users.id').onDelete('cascade')
1212
)
1313
.addColumn('created_at', 'timestamp', col => col.notNull().defaultTo(sql.raw('CURRENT_TIMESTAMP')))
1414
.addColumn('updated_at', 'timestamp')

storage/framework/core/database/src/drivers/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import { db } from '@stacksjs/database'
33
import { path } from '@stacksjs/path'
44
import { fs } from '@stacksjs/storage'
55
import { isString } from '@stacksjs/validation'
6-
import type { Attributes, Model, RelationConfig } from '@stacksjs/types'
6+
import type { Attributes, Model, RelationConfig, VineType } from '@stacksjs/types'
77

88
export * from './mysql'
99
export * from './postgres'
1010
export * from './sqlite'
1111

12-
export async function getLastMigrationFields(modelName: string): Promise<Attribute> {
12+
export async function getLastMigrationFields(modelName: string): Promise<Attributes> {
1313
const oldModelPath = path.frameworkPath(`database/models/${modelName}`)
1414
const model = await import(oldModelPath)
1515
let fields = {} as Attributes
@@ -37,7 +37,7 @@ export async function getExecutedMigrations() {
3737
}
3838
}
3939

40-
export function mapFieldTypeToColumnType(rule: any): string {
40+
export function mapFieldTypeToColumnType(rule: VineType): string {
4141
// Check if the rule is for a string and has specific validations
4242
if (rule[Symbol.for('schema_name')].includes('string'))
4343
// Default column type for strings
@@ -70,7 +70,7 @@ export function mapFieldTypeToColumnType(rule: any): string {
7070
}
7171
}
7272

73-
export function prepareTextColumnType(rule) {
73+
export function prepareTextColumnType(rule: VineType) {
7474
let columnType = 'varchar(255)'
7575

7676
// Find min and max length validations
@@ -142,7 +142,7 @@ export async function getRelations(model: Model): Promise<RelationConfig[]> {
142142
return relationships
143143
}
144144

145-
export async function fetchOtherModelRelations(model: Model, modelFiles: string[]) {
145+
export async function fetchOtherModelRelations(model: Model, modelFiles: string[]): Promise<RelationConfig[]> {
146146
const modelRelations = []
147147

148148
for (let i = 0; i < modelFiles.length; i++) {
@@ -160,9 +160,9 @@ export async function fetchOtherModelRelations(model: Model, modelFiles: string[
160160

161161
if (relation)
162162
modelRelations.push(relation)
163-
164-
return modelRelations
165163
}
164+
165+
return modelRelations
166166
}
167167

168168
function hasRelations(obj: any, key: string): boolean {

storage/framework/core/database/src/drivers/mysql.ts

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { db } from '@stacksjs/database'
33
import { ok } from '@stacksjs/error-handling'
44
import { path } from '@stacksjs/path'
55
import { fs, glob } from '@stacksjs/storage'
6-
import type { Attributes, Model } from '@stacksjs/types'
6+
import type { Attribute, Attributes, Model } from '@stacksjs/types'
77
import { checkPivotMigration, fetchOtherModelRelations, getLastMigrationFields, hasTableBeenMigrated, mapFieldTypeToColumnType } from '.'
88

99
export async function resetMysqlDatabase() {
@@ -102,7 +102,7 @@ export async function generateMysqlMigration(modelPath: string) {
102102
// if the fields have not changed, we need to migrate the table
103103

104104
// we need to check if this tableName has already been migrated
105-
const hasBeenMigrated = await hasTableBeenMigrated(tableName)
105+
const hasBeenMigrated = await hasTableBeenMigrated(tableName as string)
106106

107107
log.debug(`Has ${tableName} been migrated? ${hasBeenMigrated}`)
108108

@@ -112,23 +112,25 @@ export async function generateMysqlMigration(modelPath: string) {
112112

113113
async function getPivotTables(
114114
model: Model,
115-
): Promise<{ table: string; firstForeignKey: string; secondForeignKey: string }[]> {
115+
): Promise<{ table: string; firstForeignKey: string | undefined; secondForeignKey: string | undefined }[]> {
116116
const pivotTable = []
117117

118-
if ('belongsToMany' in model) {
119-
for (const belongsToManyRelation of model.belongsToMany) {
120-
const modelRelationPath = path.userModelsPath(`${belongsToManyRelation.model}.ts`)
121-
const modelRelation = (await import(modelRelationPath)).default
122-
const formattedModelName = model.name.toLowerCase()
123-
124-
pivotTable.push({
125-
table: belongsToManyRelation?.pivotTable || `${formattedModelName}_${modelRelation.table}`,
126-
firstForeignKey: belongsToManyRelation.firstForeignKey,
127-
secondForeignKey: belongsToManyRelation.secondForeignKey,
128-
})
118+
if (model.belongsToMany && model.name) {
119+
if ('belongsToMany' in model) {
120+
for (const belongsToManyRelation of model.belongsToMany) {
121+
const modelRelationPath = path.userModelsPath(`${belongsToManyRelation.model}.ts`)
122+
const modelRelation = (await import(modelRelationPath)).default
123+
const formattedModelName = model.name.toLowerCase()
124+
125+
pivotTable.push({
126+
table: belongsToManyRelation?.pivotTable || `${formattedModelName}_${modelRelation.table}`,
127+
firstForeignKey: belongsToManyRelation.firstForeignKey,
128+
secondForeignKey: belongsToManyRelation.secondForeignKey,
129+
})
130+
}
131+
132+
return pivotTable
129133
}
130-
131-
return pivotTable
132134
}
133135

134136
return []
@@ -146,7 +148,7 @@ async function createTableMigration(modelPath: string) {
146148

147149
const otherModelRelations = await fetchOtherModelRelations(model, modelFiles)
148150

149-
const fields = model.attributes
151+
const fields = model.attributes as Attributes
150152
const useTimestamps = model?.traits?.useTimestamps ?? model?.traits?.timestampable
151153
const useSoftDeletes = model?.traits?.useSoftDeletes ?? model?.traits?.softDeletable
152154

@@ -158,7 +160,7 @@ async function createTableMigration(modelPath: string) {
158160
migrationContent += ` .addColumn('id', 'integer', col => col.primaryKey().autoIncrement())\n`
159161

160162
for (const [fieldName, options] of Object.entries(fields)) {
161-
const fieldOptions = options as Attributes
163+
const fieldOptions = options as Attribute
162164
const columnType = mapFieldTypeToColumnType(fieldOptions.validator?.rule)
163165
migrationContent += ` .addColumn('${fieldName}', '${columnType}'`
164166

@@ -176,7 +178,7 @@ async function createTableMigration(modelPath: string) {
176178
if (otherModelRelations?.length) {
177179
for (const modelRelation of otherModelRelations) {
178180
migrationContent += ` .addColumn('${modelRelation.foreignKey}', 'integer', (col) =>
179-
col.references('${modelRelation.relationTable}.id').onDelete('cascade').notNull()
181+
col.references('${modelRelation.relationTable}.id').onDelete('cascade')
180182
) \n`
181183
}
182184
}
@@ -258,7 +260,7 @@ export async function createAlterTableMigration(modelPath: string) {
258260

259261
// Add new fields
260262
for (const fieldName of fieldsToAdd) {
261-
const options = currentFields[fieldName] as Attributes
263+
const options = currentFields[fieldName] as Attribute
262264
const columnType = mapFieldTypeToColumnType(options.validator?.rule)
263265
migrationContent += ` .addColumn('${fieldName}', '${columnType}')\n`
264266
}
@@ -286,7 +288,7 @@ export async function fetchMysqlTables(): Promise<string[]> {
286288

287289
for (const modelPath of modelFiles) {
288290
const model = (await import(modelPath)).default as Model
289-
const tableName = model.table
291+
const tableName = model.table as string
290292

291293
tables.push(tableName)
292294
}

storage/framework/core/database/src/drivers/postgres.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { db } from '@stacksjs/database'
33
import { ok } from '@stacksjs/error-handling'
44
import { path } from '@stacksjs/path'
55
import { fs, glob } from '@stacksjs/storage'
6-
import type { Attributes } from '@stacksjs/types'
6+
import type { Attribute, Attributes } from '@stacksjs/types'
77
import { checkPivotMigration, fetchOtherModelRelations, getLastMigrationFields, hasTableBeenMigrated, mapFieldTypeToColumnType } from '.'
88

99
export async function resetPostgresDatabase() {
@@ -135,7 +135,7 @@ async function createTableMigration(modelPath: string) {
135135
migrationContent += ` .addColumn('id', 'serial', (col) => col.primaryKey())\n`
136136

137137
for (const [fieldName, options] of Object.entries(fields)) {
138-
const fieldOptions = options as Attributes
138+
const fieldOptions = options as Attribute
139139
const columnType = mapFieldTypeToColumnType(fieldOptions.validator?.rule)
140140
migrationContent += ` .addColumn('${fieldName}', '${columnType}'`
141141

@@ -260,7 +260,7 @@ export async function createAlterTableMigration(modelPath: string) {
260260

261261
// Add new fields
262262
for (const fieldName of fieldsToAdd) {
263-
const options = currentFields[fieldName] as Attributes
263+
const options = currentFields[fieldName] as Attribute
264264
const columnType = mapFieldTypeToColumnType(options.validator?.rule)
265265
migrationContent += ` .addColumn('${fieldName}', '${columnType}')\n`
266266
}

storage/framework/core/database/src/drivers/sqlite.ts

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { db } from '@stacksjs/database'
33
import { ok } from '@stacksjs/error-handling'
44
import { path } from '@stacksjs/path'
55
import { fs, glob } from '@stacksjs/storage'
6-
import type { Attributes, Model } from '@stacksjs/types'
6+
import type { Attribute, Attributes, Model } from '@stacksjs/types'
77
import { checkPivotMigration, fetchOtherModelRelations, getLastMigrationFields, hasTableBeenMigrated, mapFieldTypeToColumnType } from '.'
88

99
export async function resetSqliteDatabase() {
@@ -113,21 +113,22 @@ async function getPivotTables(
113113
): Promise<{ table: string; firstForeignKey: string | undefined; secondForeignKey: string | undefined }[]> {
114114
const pivotTable = []
115115

116-
if ('belongsToMany' in model) {
117-
for (const belongsToManyRelation of model.belongsToMany) {
118-
const modelRelationPath = path.userModelsPath(`${belongsToManyRelation.model}.ts`)
119-
const modelRelation = await import(modelRelationPath)
120-
121-
const formattedModelName = model.name.toLowerCase()
122-
123-
pivotTable.push({
124-
table: belongsToManyRelation?.pivotTable || `${formattedModelName}_${modelRelation.default.table}`,
125-
firstForeignKey: belongsToManyRelation.firstForeignKey,
126-
secondForeignKey: belongsToManyRelation.secondForeignKey,
127-
})
116+
if (model.belongsToMany && model.name) {
117+
if ('belongsToMany' in model) {
118+
for (const belongsToManyRelation of model.belongsToMany) {
119+
const modelRelationPath = path.userModelsPath(`${belongsToManyRelation.model}.ts`)
120+
const modelRelation = (await import(modelRelationPath)).default
121+
const formattedModelName = model.name.toLowerCase()
122+
123+
pivotTable.push({
124+
table: belongsToManyRelation?.pivotTable || `${formattedModelName}_${modelRelation.table}`,
125+
firstForeignKey: belongsToManyRelation.firstForeignKey,
126+
secondForeignKey: belongsToManyRelation.secondForeignKey,
127+
})
128+
}
129+
130+
return pivotTable
128131
}
129-
130-
return pivotTable
131132
}
132133

133134
return []
@@ -144,7 +145,7 @@ async function createTableMigration(modelPath: string): Promise<void> {
144145

145146
const otherModelRelations = await fetchOtherModelRelations(model, modelFiles)
146147

147-
const fields = model.attributes
148+
const fields = model.attributes as Attributes
148149
const useTimestamps = model?.traits?.useTimestamps ?? model?.traits?.timestampable
149150
const useSoftDeletes = model?.traits?.useSoftDeletes ?? model?.traits?.softDeletable
150151

@@ -156,7 +157,7 @@ async function createTableMigration(modelPath: string): Promise<void> {
156157
migrationContent += ` .addColumn('id', 'integer', col => col.primaryKey().autoIncrement())\n`
157158

158159
for (const [fieldName, options] of Object.entries(fields)) {
159-
const fieldOptions = options as Attributes
160+
const fieldOptions = options as Attribute
160161
const columnType = mapFieldTypeToColumnType(fieldOptions.validator?.rule)
161162
migrationContent += ` .addColumn('${fieldName}', '${columnType}'`
162163

@@ -256,7 +257,7 @@ export async function createAlterTableMigration(modelPath: string) {
256257

257258
// Add new fields
258259
for (const fieldName of fieldsToAdd) {
259-
const options = currentFields[fieldName] as Attributes
260+
const options = currentFields[fieldName] as Attribute
260261
const columnType = mapFieldTypeToColumnType(options.validator?.rule)
261262
migrationContent += ` .addColumn('${fieldName}', '${columnType}')\n`
262263
}

storage/framework/core/database/src/seeder.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ async function seedModel(name: string, model?: Model) {
3737
for (let j = 0; j < otherRelations.length; j++) {
3838
const relationElement = otherRelations[j] as RelationConfig
3939

40-
record[relationElement?.foreignKey] = 1 // TODO: make this dynamic
40+
record[relationElement?.foreignKey] = await seedModelRelation(relationElement?.relationModel as string)
4141
}
4242
}
4343

@@ -48,6 +48,31 @@ async function seedModel(name: string, model?: Model) {
4848
await db.insertInto(tableName).values(records).execute()
4949
}
5050

51+
async function seedModelRelation(modelName: string): Promise<BigInt | number> {
52+
53+
const modelInstance = (await import(path.userModelsPath(modelName))).default
54+
55+
if (! modelInstance) return 1
56+
57+
const record: any = {}
58+
59+
const table = modelInstance.table
60+
61+
for (const fieldName in modelInstance.attributes) {
62+
63+
const field = modelInstance.attributes[fieldName]
64+
65+
// Use the factory function if available, otherwise leave the field undefined
66+
record[fieldName] = field?.factory ? field.factory() : undefined
67+
}
68+
69+
const data = await db.insertInto(table)
70+
.values(record)
71+
.executeTakeFirstOrThrow()
72+
73+
return data.insertId || 1
74+
}
75+
5176
export async function getRelations(model: Model): Promise<RelationConfig[]> {
5277
const relationsArray = ['hasOne', 'hasMany', 'belongsToMany', 'hasOneThrough']
5378
const relationships = []
@@ -63,7 +88,7 @@ export async function getRelations(model: Model): Promise<RelationConfig[]> {
6388

6489
const modelRelationPath = path.userModelsPath(`${relationModel}.ts`)
6590
const modelRelation = (await import(modelRelationPath)).default
66-
const formattedModelName = model.name.toLowerCase()
91+
const formattedModelName = model.name?.toLowerCase()
6792

6893
relationships.push({
6994
relationship: relation,
@@ -84,7 +109,7 @@ export async function getRelations(model: Model): Promise<RelationConfig[]> {
84109
return relationships
85110
}
86111

87-
export async function fetchOtherModelRelations(model: Model) {
112+
export async function fetchOtherModelRelations(model: Model): Promise<RelationConfig[]> {
88113

89114
const modelFiles = glob.sync(path.userModelsPath('*.ts'))
90115

@@ -105,9 +130,9 @@ export async function fetchOtherModelRelations(model: Model) {
105130

106131
if (relation)
107132
modelRelations.push(relation)
108-
109-
return modelRelations
110133
}
134+
135+
return modelRelations
111136
}
112137

113138
function hasRelations(obj: any, key: string): boolean {

storage/framework/core/types/src/model.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export type AuthOptions = {}
66

77
export type ApiRoutes = 'index' | 'show' | 'store' | 'update' | 'destroy'
88

9+
export type VineType = VineString | VineNumber | VineBoolean | Date | Nullable<any>
910
export interface SeedOptions {
1011
count: number
1112
}
@@ -106,7 +107,7 @@ export interface Attribute {
106107
required?: boolean
107108
factory?: () => any
108109
validator?: {
109-
rule: VineString | VineNumber | VineBoolean | Date | Nullable<any>
110+
rule: VineType
110111
message: string
111112
}
112113
// validation?: String | Number | Boolean | Date

0 commit comments

Comments
 (0)