Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "arkormx",
"version": "2.11.2",
"version": "2.11.3",
"description": "Modern TypeScript-first ORM for Node.js.",
"keywords": [
"orm",
Expand Down Expand Up @@ -114,4 +114,4 @@
"pg": "^8.19.0"
},
"packageManager": "pnpm@10.0.0"
}
}
2 changes: 1 addition & 1 deletion packages/plugin-clear-router/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@arkormx/plugin-clear-router",
"version": "0.1.50",
"version": "0.1.52",
"description": "Clear Router plugin for resolving Arkormx models from route parameters.",
"publishConfig": {
"access": "public"
Expand Down
6 changes: 6 additions & 0 deletions src/cli/commands/MigrateFreshCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { CliApp } from '../CliApp'
import { Command } from '@h3ravel/musket'
import { MIGRATION_BRAND } from '../../database/Migration'
import { RuntimeModuleLoader } from '../../helpers/runtime-module-loader'
import { loadArkormConfig } from '../../helpers/runtime-config'

export class MigrateFreshCommand extends Command<CliApp> {
protected signature = `migrate:fresh
Expand All @@ -45,6 +46,11 @@ export class MigrateFreshCommand extends Command<CliApp> {

async handle() {
this.app.command = this
// Apply the project's arkormx.config (and its adapter) before resolving it:
// harnesses like the Arkstack CLI hand us a fresh CliApp that hasn't loaded
// the config, so without this the adapter is undefined and `migrate:fresh`
// silently falls back to the Prisma path instead of resetting the database.
await loadArkormConfig()

const configuredMigrationsDir =
this.app.getConfig('paths')?.migrations ?? join(process.cwd(), 'database', 'migrations')
Expand Down
4 changes: 4 additions & 0 deletions src/cli/commands/MigrateRollbackCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {

import { CliApp } from '../CliApp'
import { Command } from '@h3ravel/musket'
import { loadArkormConfig } from '../../helpers/runtime-config'
import { MIGRATION_BRAND } from '../../database/Migration'
import { RuntimeModuleLoader } from '../../helpers/runtime-module-loader'

Expand All @@ -49,6 +50,9 @@ export class MigrateRollbackCommand extends Command<CliApp> {

async handle() {
this.app.command = this
// Load the project config (and its adapter) before resolving it; harnesses
// may hand us a CliApp that hasn't applied the config yet.
await loadArkormConfig()

const configuredMigrationsDir =
this.app.getConfig('paths')?.migrations ?? join(process.cwd(), 'database', 'migrations')
Expand Down
4 changes: 4 additions & 0 deletions src/cli/commands/MigrationHistoryCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {

import { CliApp } from '../CliApp'
import { Command } from '@h3ravel/musket'
import { loadArkormConfig } from '../../helpers/runtime-config'

/**
* The MigrationHistoryCommand class manages tracked migration run history.
Expand All @@ -32,6 +33,9 @@ export class MigrationHistoryCommand extends Command<CliApp> {

async handle() {
this.app.command = this
// Load the project config (and its adapter) before resolving it; harnesses
// may hand us a CliApp that hasn't applied the config yet.
await loadArkormConfig()

const stateFilePath = resolveMigrationStateFilePath(
process.cwd(),
Expand Down
4 changes: 4 additions & 0 deletions src/cli/commands/ModelsSyncCommand.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CliApp } from '../CliApp'
import { Command } from '@h3ravel/musket'
import { loadArkormConfig } from '../../helpers/runtime-config'
import { resolve } from 'node:path'

export class ModelsSyncCommand extends Command<CliApp> {
Expand All @@ -12,6 +13,9 @@ export class ModelsSyncCommand extends Command<CliApp> {

async handle() {
this.app.command = this
// Load the project config (and its adapter) before resolving it; harnesses
// may hand us a CliApp that hasn't applied the config yet.
await loadArkormConfig()

let result

Expand Down
4 changes: 4 additions & 0 deletions src/cli/commands/SeedCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { getRegisteredPaths, getRegisteredSeeders } from '../../helpers/runtime-

import { CliApp } from '../CliApp'
import { Command } from '@h3ravel/musket'
import { loadArkormConfig } from '../../helpers/runtime-config'
import { RuntimeModuleLoader } from '../../helpers/runtime-module-loader'
import { SEEDER_BRAND, Seeder } from '../../database/Seeder'
import { join } from 'node:path'
Expand Down Expand Up @@ -36,6 +37,9 @@ export class SeedCommand extends Command<CliApp> {
*/
async handle() {
this.app.command = this
// Load the project config (and its adapter) before resolving paths/adapter;
// harnesses may hand us a CliApp that hasn't applied the config yet.
await loadArkormConfig()
const configuredSeedersDir =
this.app.getConfig('paths')?.seeders ?? join(process.cwd(), 'database', 'seeders')
const seederDirs = this.resolveSeederDirectories(configuredSeedersDir)
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export * from './database/SchemaBuilder'
export * from './database/Seeder'
export * from './database/TableBuilder'
export * from './DB'
export * from './Expression'
export * from './Exceptions/ArkormException'
export * from './Exceptions/MissingDelegateException'
export * from './Exceptions/ModelNotFoundException'
Expand All @@ -37,6 +36,7 @@ export * from './Exceptions/RelationResolutionException'
export * from './Exceptions/ScopeNotDefinedException'
export * from './Exceptions/UniqueConstraintResolutionException'
export * from './Exceptions/UnsupportedAdapterFeatureException'
export * from './Expression'
export * from './helpers/column-mappings'
export * from './helpers/generated-column'
export * from './helpers/migration-history'
Expand All @@ -47,6 +47,7 @@ export * from './helpers/runtime-compatibility'
export * from './helpers/runtime-config'
export * from './helpers/runtime-module-loader'
export * from './helpers/runtime-registry'
export * from './JoinClause'
export * from './Model'
export * from './Paginator'
export * from './PivotModel'
Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export * from './metadata'
export * from './migrations'
export * from './model'
export * from './ModelStatic'
export * from './query-builder'
export * from './relationship'
50 changes: 50 additions & 0 deletions tests/base/migrate-database.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,56 @@ describe('database-backed migration command fallback', () => {
expect(adapter.state.migrations[0]?.id).toContain('CreateUsersMigration')
})

it('migrate:fresh loads the project config to reach the adapter reset path (regression)', async () => {
const workspace = makeTempDir('arkormx-db-fresh-loadconfig-')
process.chdir(workspace)

const migrationsDir = join(workspace, 'database', 'migrations')
mkdirSync(migrationsDir, { recursive: true })

const migrationBaseImport = `${originalCwd.replace(/\\/g, '/')}/src/database/Migration.ts`
writeFileSync(
join(migrationsDir, 'CreateThings.ts'),
[
`import { Migration } from '${migrationBaseImport}'`,
'export class CreateThings extends Migration {',
" async up (schema) { schema.createTable('things', (table) => { table.id() }) }",
" async down (schema) { schema.dropTable('things') }",
'}',
'',
].join('\n'),
)

const adapter = createNoopAdapter() as DatabaseAdapter & {
resetCount: number
executed: SchemaOperation[][]
}
;(globalThis as Record<string, unknown>).__ARKORM_FRESH_TEST_ADAPTER__ = adapter

// The adapter is reachable ONLY through the project config — the command must
// load it itself. Without loadArkormConfig() the adapter is undefined and
// fresh wrongly takes the Prisma path (no schema.prisma => error, no reset).
writeFileSync(
join(workspace, 'arkormx.config.cjs'),
`module.exports = { adapter: globalThis.__ARKORM_FRESH_TEST_ADAPTER__, paths: { migrations: ${JSON.stringify(migrationsDir)} } }\n`,
)

const app = new CliApp()
const fresh = new MigrateFreshCommand(app, new Kernel(app))
;(fresh as unknown as { app: CliApp }).app = app
const io = attachCommandIo(fresh as unknown as any, {
'skip-generate': true,
'skip-migrate': true,
})

await fresh.handle()
delete (globalThis as Record<string, unknown>).__ARKORM_FRESH_TEST_ADAPTER__

expect(io.errorLines).toHaveLength(0)
expect(adapter.resetCount).toBe(1)
expect(adapter.executed[0]?.[0]).toMatchObject({ type: 'createTable', table: 'things' })
})

it('offers to create the configured database before adapter-backed fresh runs', async () => {
const workspace = makeTempDir('arkormx-db-fresh-create-database-')
process.chdir(workspace)
Expand Down
Loading