@stacksjs/database 0.70.376 → 0.70.378
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.d.ts +5 -0
- package/dist/index.js +1 -1
- package/dist/schema-drift.d.ts +50 -0
- package/dist/schema-drift.js +1 -0
- package/package.json +11 -11
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export type {
|
|
|
10
10
|
PostgresConfig,
|
|
11
11
|
SqliteConfig,
|
|
12
12
|
} from './driver-config';
|
|
13
|
+
export type { SchemaDriftColumn, SchemaDriftReport } from './schema-drift';
|
|
13
14
|
export type { DeclaredFK, FkAuditResult, FkOrphan, FkOrphanReport, LiveFK } from './fk-audit';
|
|
14
15
|
export type { DeclaredUnique, LiveUniqueIndex, UniqueAuditResult } from './unique-audit';
|
|
15
16
|
export type {
|
|
@@ -143,6 +144,10 @@ export * from './ensure-database';
|
|
|
143
144
|
// Foreign-key audit (stacksjs/stacks#1916) — compare declared
|
|
144
145
|
// `belongsTo` relationships against live FKs.
|
|
145
146
|
export { auditForeignKeys, findFkOrphans, getDeclaredFKs, getLiveFKs } from './fk-audit';
|
|
147
|
+
// Schema drift audit — compare live column types against what the models
|
|
148
|
+
// declare. `migrate` only tracks which files have run, so a database built from
|
|
149
|
+
// a wrong migration set reports "up to date" forever while its columns differ.
|
|
150
|
+
export { auditSchemaDrift, formatSchemaDrift } from './schema-drift';
|
|
146
151
|
// Unique-index drift audit (stacksjs/stacks#1952) — compare declared
|
|
147
152
|
// `unique: true` attributes / indexes against live UNIQUE indexes.
|
|
148
153
|
export { auditUniqueIndexes, getDeclaredUniques, getLiveUniqueIndexes } from './unique-audit';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{Database,createDatabase,createMysqlDatabase,createPostgresDatabase,createSqliteDatabase}from"./database";export{detectDriver,driverDefaults,getConfigFromEnv,getConnectionString,mergeWithDefaults,validateDriverConfig}from"./driver-config";export*from"./utils";export*from"./types";export*from"./migrations";export{setQueryTracker,logQuery}from"./query-logger";export{addColumnSafely,backfillInBatches,renameColumnSafely}from"./safe-migrations";export*from"./seeder";export*from"./drivers";export*from"./custom";export*from"./auth-tables";export*from"./uuid-columns";export*from"./managed-columns";export*from"./relation-columns";export{ensureNotificationForeignKeys,migrateNotificationTables}from"./notification-tables";export{migrateRbacTables}from"./rbac-tables";export*from"./trait-tables";export*from"./datetime-columns";export*from"./dialect";export*from"./replicas";export*from"./ddl-constraints";export*from"./vschema";export*from"./sql-helpers";export*from"./defaults";export*from"./migration-dialect";export*from"./migration-path";export*from"./migration-ledger";export*from"./model-sources";export*from"./shadowed-models";export*from"./ensure-database";export{auditForeignKeys,findFkOrphans,getDeclaredFKs,getLiveFKs}from"./fk-audit";export{auditUniqueIndexes,getDeclaredUniques,getLiveUniqueIndexes}from"./unique-audit";export{__flushAfterCommitNow,__pendingAfterCommitCount,enqueueAfterCommit,isInTransaction,runInTransactionScope}from"./transaction-context";export{createQueryBuilder,setConfig}from"@stacksjs/query-builder";export{createDynamo,dynamo,EntityQueryBuilder,generateKeyPattern,parseKeyPattern,buildKey,marshall,unmarshall}from"./drivers/dynamodb";
|
|
1
|
+
export{Database,createDatabase,createMysqlDatabase,createPostgresDatabase,createSqliteDatabase}from"./database";export{detectDriver,driverDefaults,getConfigFromEnv,getConnectionString,mergeWithDefaults,validateDriverConfig}from"./driver-config";export*from"./utils";export*from"./types";export*from"./migrations";export{setQueryTracker,logQuery}from"./query-logger";export{addColumnSafely,backfillInBatches,renameColumnSafely}from"./safe-migrations";export*from"./seeder";export*from"./drivers";export*from"./custom";export*from"./auth-tables";export*from"./uuid-columns";export*from"./managed-columns";export*from"./relation-columns";export{ensureNotificationForeignKeys,migrateNotificationTables}from"./notification-tables";export{migrateRbacTables}from"./rbac-tables";export*from"./trait-tables";export*from"./datetime-columns";export*from"./dialect";export*from"./replicas";export*from"./ddl-constraints";export*from"./vschema";export*from"./sql-helpers";export*from"./defaults";export*from"./migration-dialect";export*from"./migration-path";export*from"./migration-ledger";export*from"./model-sources";export*from"./shadowed-models";export*from"./ensure-database";export{auditForeignKeys,findFkOrphans,getDeclaredFKs,getLiveFKs}from"./fk-audit";export{auditSchemaDrift,formatSchemaDrift}from"./schema-drift";export{auditUniqueIndexes,getDeclaredUniques,getLiveUniqueIndexes}from"./unique-audit";export{__flushAfterCommitNow,__pendingAfterCommitCount,enqueueAfterCommit,isInTransaction,runInTransactionScope}from"./transaction-context";export{createQueryBuilder,setConfig}from"@stacksjs/query-builder";export{createDynamo,dynamo,EntityQueryBuilder,generateKeyPattern,parseKeyPattern,buildKey,marshall,unmarshall}from"./drivers/dynamodb";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare the live schema against the application's models.
|
|
3
|
+
*
|
|
4
|
+
* Only the application's own models under `app/Models/`. The framework defaults
|
|
5
|
+
* are deliberately excluded: an application that does not use the commerce or
|
|
6
|
+
* CMS models has no tables for them, and reporting sixty absent tables would
|
|
7
|
+
* bury the one column that is actually wrong.
|
|
8
|
+
*
|
|
9
|
+
* Never throws. A drift audit that breaks `migrate` is worse than one that does
|
|
10
|
+
* not run, so an introspection failure, a missing permission or an
|
|
11
|
+
* unrecognisable model returns `skipped` and the caller carries on.
|
|
12
|
+
*/
|
|
13
|
+
export declare function auditSchemaDrift(): Promise<SchemaDriftReport>;
|
|
14
|
+
/** Re-exported so callers format one way. */
|
|
15
|
+
export declare function formatSchemaDrift(report: SchemaDriftReport): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Does the live database still look like the models?
|
|
18
|
+
*
|
|
19
|
+
* The companion to `fk-audit.ts`, and the one that catches the quieter failure.
|
|
20
|
+
* `migrate` decides what to do by asking which migration FILES have not
|
|
21
|
+
* executed. It never asks whether the database resembles the models. So a
|
|
22
|
+
* database created from an older, wrong migration set reports "nothing to
|
|
23
|
+
* migrate — your database is already up to date" on every run, forever, while
|
|
24
|
+
* its columns are wrong, and a corrected `CREATE TABLE IF NOT EXISTS` deploys
|
|
25
|
+
* as a no-op against it.
|
|
26
|
+
*
|
|
27
|
+
* Two of those reached production on one app: a JSON column left in
|
|
28
|
+
* varchar(255), which refused a large payload, and a money column left as an
|
|
29
|
+
* integer, which stored 99.5 as 100. Every layer reported success. The only
|
|
30
|
+
* symptom was a number that came back different from the one written.
|
|
31
|
+
*
|
|
32
|
+
* The comparison itself lives in bun-query-builder, which owns the schema plan
|
|
33
|
+
* and the introspection. This file's job is the part only the framework knows:
|
|
34
|
+
* where an application's models actually are.
|
|
35
|
+
*/
|
|
36
|
+
/** One column whose live type does not match what its model declares. */
|
|
37
|
+
export declare interface SchemaDriftColumn {
|
|
38
|
+
table: string
|
|
39
|
+
column: string
|
|
40
|
+
expected: string
|
|
41
|
+
actual: string
|
|
42
|
+
actualSqlType: string
|
|
43
|
+
}
|
|
44
|
+
export declare interface SchemaDriftReport {
|
|
45
|
+
missingTables: string[]
|
|
46
|
+
missingColumns: Array<{ table: string, column: string, expected: string }>
|
|
47
|
+
typeMismatches: SchemaDriftColumn[]
|
|
48
|
+
clean: boolean
|
|
49
|
+
skipped: boolean
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import fs from"node:fs";import{path}from"@stacksjs/path";async function loadModelsFrom(dir){const out=[];if(!fs.existsSync(dir))return out;for(const entry of fs.readdirSync(dir,{withFileTypes:!0})){const fullPath=path.join(dir,entry.name);if(entry.isDirectory()){out.push(...await loadModelsFrom(fullPath));continue}if(!entry.name.endsWith(".ts")||entry.name.startsWith("_")||entry.name.startsWith("index"))continue;try{const imported=(await import(fullPath)).default;if(imported?.name||imported?.table)out.push(imported)}catch{}}return out}export async function auditSchemaDrift(){const empty={missingTables:[],missingColumns:[],typeMismatches:[],clean:!0,skipped:!0};try{const models=await loadModelsFrom(path.appPath("Models"));if(models.length===0)return empty;const qb=await import("bun-query-builder");if(typeof qb.auditSchemaDrift!=="function"||typeof qb.buildMigrationPlan!=="function")return empty;const defined=qb.defineModels(Object.fromEntries(models.map((model)=>[model.name??model.table,model]))),plan=qb.buildMigrationPlan(defined,{});return{...await qb.auditSchemaDrift(plan,{}),skipped:!1}}catch{return empty}}export async function formatSchemaDrift(report){if(report.skipped||report.clean)return"";const{formatSchemaDrift:format}=await import("bun-query-builder");return typeof format==="function"?format(report):""}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/database",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.378",
|
|
6
6
|
"description": "The Stacks database integration.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -61,19 +61,19 @@
|
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@stacksjs/ts-validation": "^0.5.4",
|
|
64
|
-
"bun-query-builder": "^0.2.
|
|
64
|
+
"bun-query-builder": "^0.2.36",
|
|
65
65
|
"dynamodb-tooling": "^0.3.2"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@stacksjs/cli": "0.70.
|
|
69
|
-
"@stacksjs/config": "0.70.
|
|
70
|
-
"@stacksjs/logging": "0.70.
|
|
71
|
-
"@stacksjs/router": "0.70.
|
|
68
|
+
"@stacksjs/cli": "0.70.378",
|
|
69
|
+
"@stacksjs/config": "0.70.378",
|
|
70
|
+
"@stacksjs/logging": "0.70.378",
|
|
71
|
+
"@stacksjs/router": "0.70.378",
|
|
72
72
|
"better-dx": "^0.2.17",
|
|
73
|
-
"@stacksjs/path": "0.70.
|
|
74
|
-
"@stacksjs/query-builder": "0.70.
|
|
75
|
-
"@stacksjs/storage": "0.70.
|
|
76
|
-
"@stacksjs/strings": "0.70.
|
|
77
|
-
"@stacksjs/utils": "0.70.
|
|
73
|
+
"@stacksjs/path": "0.70.378",
|
|
74
|
+
"@stacksjs/query-builder": "0.70.378",
|
|
75
|
+
"@stacksjs/storage": "0.70.378",
|
|
76
|
+
"@stacksjs/strings": "0.70.378",
|
|
77
|
+
"@stacksjs/utils": "0.70.378"
|
|
78
78
|
}
|
|
79
79
|
}
|