@stacksjs/database 0.75.422 → 0.75.431
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/driver-config.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/row-lease.d.ts +14 -0
- package/dist/row-lease.js +1 -0
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.js +1 -1
- package/dist/transaction-options.d.ts +9 -0
- package/dist/transaction-options.js +1 -0
- package/package.json +17 -17
package/dist/driver-config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{env}from"@stacksjs/env";export const driverDefaults={sqlite:{database:"database/stacks.sqlite",prefix:""},mysql:{name:"stacks",host:"127.0.0.1",port:3306,username:"root",password:"",prefix:"",charset:"utf8mb4",collation:"utf8mb4_unicode_ci"},singlestore:{name:"stacks",host:"127.0.0.1",port:3306,username:"root",password:"",prefix:"",charset:"utf8mb4",ssl:!1},vitess:{name:"stacks",host:"127.0.0.1",port:15306,username:"root",password:"",prefix:"",ssl:!1,sharded:!0},turso:{url:"http://127.0.0.1:8080",prefix:""},postgres:{name:"stacks",host:"127.0.0.1",port:5432,username:"postgres",password:"",prefix:"",schema:"public"},browser:{}};export function getConnectionString(driver,config){switch(driver){case"sqlite":{const sqliteConfig=config;if(sqliteConfig.database===":memory:")return":memory:";return`sqlite://${sqliteConfig.database}`}case"mysql":{const mysqlConfig=config,{name,host="127.0.0.1",port=3306,username="root",password=""}=mysqlConfig;return
|
|
1
|
+
import{env}from"@stacksjs/env";export const driverDefaults={sqlite:{database:"database/stacks.sqlite",prefix:""},mysql:{name:"stacks",host:"127.0.0.1",port:3306,username:"root",password:"",prefix:"",charset:"utf8mb4",collation:"utf8mb4_unicode_ci"},singlestore:{name:"stacks",host:"127.0.0.1",port:3306,username:"root",password:"",prefix:"",charset:"utf8mb4",ssl:!1},vitess:{name:"stacks",host:"127.0.0.1",port:15306,username:"root",password:"",prefix:"",ssl:!1,sharded:!0},turso:{url:"http://127.0.0.1:8080",prefix:""},postgres:{name:"stacks",host:"127.0.0.1",port:5432,username:"postgres",password:"",prefix:"",schema:"public"},browser:{}};function networkConnectionString(scheme,host,port,username,password,database){const authority=host.includes(":")&&!host.startsWith("[")?`[${host}]`:host,url=new URL(`${scheme}://${authority}:${port}`);url.username=encodeURIComponent(username);url.password=encodeURIComponent(password);url.pathname=`/${encodeURIComponent(database)}`;return url.href}export function getConnectionString(driver,config){switch(driver){case"sqlite":{const sqliteConfig=config;if(sqliteConfig.database===":memory:")return":memory:";return`sqlite://${sqliteConfig.database}`}case"mysql":{const mysqlConfig=config,{name,host="127.0.0.1",port=3306,username="root",password=""}=mysqlConfig;return networkConnectionString("mysql",host,port,username,password,name)}case"singlestore":{const ssConfig=config,{name,host="127.0.0.1",port=3306,username="root",password=""}=ssConfig;return networkConnectionString("mysql",host,port,username,password,name)}case"vitess":{const vtConfig=config,{name,host="127.0.0.1",port=15306,username="root",password="",tabletType}=vtConfig,keyspace=tabletType?`${name}@${tabletType}`:name;return networkConnectionString("mysql",host,port,username,password,keyspace)}case"postgres":{const pgConfig=config,{name,host="127.0.0.1",port=5432,username="postgres",password=""}=pgConfig;return networkConnectionString("postgres",host,port,username,password,name)}case"turso":return config.url;default:throw Error(`Unsupported driver: ${driver}`)}}export function validateDriverConfig(driver,config){const errors=[];switch(driver){case"sqlite":{if(!config.database)errors.push("SQLite requires a database path");break}case"mysql":{if(!config.name)errors.push("MySQL requires a database name");break}case"singlestore":{if(!config.name)errors.push("SingleStore requires a database name");break}case"vitess":{if(!config.name)errors.push("Vitess requires a keyspace name");break}case"postgres":{if(!config.name)errors.push("PostgreSQL requires a database name");break}case"turso":{const tursoConfig=config;if(!tursoConfig.url)errors.push("Turso requires a database URL (TURSO_DATABASE_URL)");else if(!/^(?:libsql|https?|wss?):\/\//i.test(tursoConfig.url))errors.push("Turso URLs start with libsql://, https://, http://, ws:// or wss://");break}default:errors.push(`Unsupported driver: ${driver}`)}return{valid:errors.length===0,errors}}export function mergeWithDefaults(driver,config){return{...driverDefaults[driver],...config}}export function getConfigFromEnv(driver){switch(driver){case"sqlite":return{database:env.DB_DATABASE||"database/stacks.sqlite",prefix:env.DB_PREFIX||""};case"mysql":return{name:env.DB_DATABASE||"stacks",host:env.DB_HOST||"127.0.0.1",port:env.DB_PORT??3306,username:env.DB_USERNAME||"root",password:env.DB_PASSWORD||"",prefix:env.DB_PREFIX||""};case"singlestore":return{name:env.DB_DATABASE||"stacks",host:env.DB_HOST||"127.0.0.1",port:env.DB_PORT??3306,username:env.DB_USERNAME||"root",password:env.DB_PASSWORD||"",prefix:env.DB_PREFIX||"",ssl:env.DB_SSL==="true"||env.DB_SSL==="1"};case"vitess":return{name:env.DB_DATABASE||"stacks",host:env.DB_HOST||"127.0.0.1",port:env.DB_PORT??15306,username:env.DB_USERNAME||"root",password:env.DB_PASSWORD||"",prefix:env.DB_PREFIX||"",ssl:env.DB_SSL==="true"||env.DB_SSL==="1",sharded:!["0","false","no","off"].includes(String(env.DB_VITESS_SHARDED??"true").toLowerCase())};case"turso":return{url:env.TURSO_DATABASE_URL||"",authToken:env.TURSO_AUTH_TOKEN||void 0,prefix:env.DB_PREFIX||""};case"postgres":return{name:env.DB_DATABASE||"stacks",host:env.DB_HOST||"127.0.0.1",port:env.DB_PORT??5432,username:env.DB_USERNAME||"postgres",password:env.DB_PASSWORD||"",prefix:env.DB_PREFIX||"",schema:env.DB_SCHEMA||"public"};default:throw Error(`Unsupported driver: ${driver}`)}}export function detectDriver(){if(env.DB_CONNECTION)return env.DB_CONNECTION==="libsql"?"turso":env.DB_CONNECTION;if(env.TURSO_DATABASE_URL)return"turso";if(env.DATABASE_URL?.startsWith("postgres"))return"postgres";if(env.DATABASE_URL?.startsWith("mysql"))return"mysql";return"sqlite"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{Database,createDatabase,createMysqlDatabase,createPostgresDatabase,createSqliteDatabase,createTursoDatabase}from"./database";export{detectDriver,driverDefaults,getConfigFromEnv,getConnectionString,mergeWithDefaults,validateDriverConfig}from"./driver-config";export*from"./utils";export*from"./row-lock";export*from"./types";export*from"./migrations";export*from"./framework-renames";export{setQueryTracker,logQuery}from"./query-logger";export{addColumnSafely,backfillInBatches,renameColumnSafely}from"./safe-migrations";export{matchedRows,mutationCount}from"./affected-rows";export*from"./seeder";export*from"./drivers";export*from"./custom";export*from"./auth-tables";export*from"./utc-defaults";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"./erd";export*from"./vschema";export*from"./sql-helpers";export*from"./defaults";export*from"./migration-dialect";export*from"./migration-path";export*from"./migration-ledger";export*from"./schema-align";export*from"./hand-written-migrations";export*from"./migration-names";export{comparableIndexKey,postgresIndexStatement}from"./index-shape";export*from"./model-sources";export*from"./package-migrations";export*from"./package-models";export*from"./shadowed-models";export*from"./ensure-database";export{auditForeignKeys,classifyDeclaredFKs,findFkOrphans,fkKey,getDeclaredFKs,getLiveFKs,getLiveTables}from"./fk-audit";export{frameworkRouteAdmission}from"./framework-route-admission";export{auditSchemaDrift,formatSchemaDrift}from"./schema-drift";export{describeIgnoreRule,findIgnoredMigrations,formatIgnoredMigrations,trackIgnoredGeneratedMigrations}from"./ignored-migrations";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,createTursoDatabase}from"./database";export{detectDriver,driverDefaults,getConfigFromEnv,getConnectionString,mergeWithDefaults,validateDriverConfig}from"./driver-config";export*from"./utils";export*from"./row-lock";export*from"./types";export*from"./migrations";export*from"./framework-renames";export{setQueryTracker,logQuery}from"./query-logger";export{addColumnSafely,backfillInBatches,renameColumnSafely}from"./safe-migrations";export{matchedRows,mutationCount}from"./affected-rows";export*from"./seeder";export*from"./drivers";export*from"./custom";export*from"./auth-tables";export*from"./utc-defaults";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"./erd";export*from"./vschema";export*from"./sql-helpers";export*from"./defaults";export*from"./migration-dialect";export*from"./migration-path";export*from"./migration-ledger";export*from"./schema-align";export*from"./hand-written-migrations";export*from"./migration-names";export{comparableIndexKey,postgresIndexStatement}from"./index-shape";export*from"./model-sources";export*from"./package-migrations";export*from"./package-models";export*from"./shadowed-models";export*from"./ensure-database";export{auditForeignKeys,classifyDeclaredFKs,findFkOrphans,fkKey,getDeclaredFKs,getLiveFKs,getLiveTables}from"./fk-audit";export{frameworkRouteAdmission}from"./framework-route-admission";export{auditSchemaDrift,formatSchemaDrift}from"./schema-drift";export{describeIgnoreRule,findIgnoredMigrations,formatIgnoredMigrations,trackIgnoredGeneratedMigrations}from"./ignored-migrations";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";export*from"./row-lease";export{readCommittedTransactionOptions,sqliteWriteOptions}from"./transaction-options";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atomically lease one owner-scoped row without holding a transaction over I/O.
|
|
3
|
+
* Columns belong to the caller's model. All writes and release are fenced by
|
|
4
|
+
* the generated token, so an expired worker cannot renew or release its successor.
|
|
5
|
+
*/
|
|
6
|
+
export declare function claimRowLease(table: string, scope: Record<string, string | number>, columns: RowLeaseColumns, ttlMs: number): Promise<RowLease | null>;
|
|
7
|
+
export declare interface RowLeaseColumns { token: string, heartbeat: string }
|
|
8
|
+
export declare interface RowLease {
|
|
9
|
+
token: string
|
|
10
|
+
assertOwned: () => Promise<void>
|
|
11
|
+
commit: <T>(work: () => Promise<T>) => Promise<T>
|
|
12
|
+
renew: () => Promise<boolean>
|
|
13
|
+
release: () => Promise<void>
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{randomUUID}from"node:crypto";import{db,getDatabaseDialect}from"./utils";import{assertSqlIdentifier,lockRow}from"./row-lock";import{mutationCount}from"./affected-rows";import{readCommittedTransactionOptions}from"./transaction-options";export async function claimRowLease(table,scope,columns,ttlMs){for(const name of[table,...Object.keys(scope),columns.token,columns.heartbeat])assertSqlIdentifier(name);if(!Object.keys(scope).length||!Number.isSafeInteger(ttlMs)||ttlMs<1)throw RangeError("A row lease requires an owner scope and a positive TTL");const token=randomUUID(),scoped=(query)=>{for(const[column,value]of Object.entries(scope))query=query.where(column,"=",value);return query},quote=getDatabaseDialect()==="mysql"?"`":'"',column=(name)=>`${quote}${name}${quote}`;if(!await db.transaction(async(connection)=>{if(!await lockRow(connection,table,scope))return!1;const result=await scoped(connection.updateTable(table).set({[columns.token]:token,[columns.heartbeat]:new Date().toISOString()})).where(db.raw(`(${column(columns.token)} IS NULL OR ${column(columns.heartbeat)} IS NULL OR ${column(columns.heartbeat)} <= ?)`,[new Date(Date.now()-ttlMs).toISOString()])).execute(),count=mutationCount(result);if(count>1)throw Error("A row lease requires a unique scope");return count===1},readCommittedTransactionOptions()))return null;const owned=()=>scoped(db.selectFrom(table).select(columns.token)).where(columns.token,"=",token);return{token,async assertOwned(){if(!await owned().executeTakeFirst())throw Error("Row lease ownership was lost")},async commit(work){return db.transaction(async(connection)=>{if(!await lockRow(connection,table,{...scope,[columns.token]:token}))throw Error("Row lease ownership was lost");return work()})},async renew(){const result=await scoped(db.updateTable(table).set({[columns.heartbeat]:new Date().toISOString()})).where(columns.token,"=",token).execute();return mutationCount(result)>0||Boolean(await owned().executeTakeFirst())},async release(){await scoped(db.updateTable(table).set({[columns.token]:null,[columns.heartbeat]:null})).where(columns.token,"=",token).execute()}}}
|
package/dist/runtime.d.ts
CHANGED
package/dist/runtime.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./affected-rows";export*from"./dialect";export*from"./replicas";export*from"./sql-helpers";export*from"./transaction-context";export*from"./types";export*from"./utils";export*from"./row-lock";
|
|
1
|
+
export*from"./affected-rows";export*from"./dialect";export*from"./replicas";export*from"./sql-helpers";export*from"./transaction-context";export*from"./types";export*from"./utils";export*from"./row-lock";export*from"./row-lease";export{readCommittedTransactionOptions,sqliteWriteOptions}from"./transaction-options";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { getDatabaseDialect } from './utils';
|
|
2
|
+
/** Acquire SQLite's writer lock before reading; other providers reject sqliteMode. */
|
|
3
|
+
export declare function sqliteWriteOptions(dialect?: ReturnType<typeof getDatabaseDialect>): { sqliteMode?: 'immediate' };
|
|
4
|
+
/**
|
|
5
|
+
* Use statement snapshots for short operations whose locks serialize writers.
|
|
6
|
+
* MySQL cannot change isolation inside Bun's transaction callback; SQLite
|
|
7
|
+
* instead reserves its sole writer. Savepoints inherit the parent's isolation.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readCommittedTransactionOptions(dialect?: ReturnType<typeof getDatabaseDialect>): { isolation?: 'read committed' | 'serializable', sqliteMode?: 'immediate' };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{getDatabaseDialect}from"./utils";export function sqliteWriteOptions(dialect=getDatabaseDialect()){return dialect==="sqlite"?{sqliteMode:"immediate"}:{}}export function readCommittedTransactionOptions(dialect=getDatabaseDialect()){if(dialect==="postgres")return{isolation:"read committed"};if(dialect==="sqlite")return{isolation:"serializable",sqliteMode:"immediate"};return{isolation:void 0}}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/database",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.431",
|
|
6
6
|
"description": "The Stacks database integration.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -66,26 +66,26 @@
|
|
|
66
66
|
"prepublishOnly": "bun run build"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
-
"@stacksjs/config": "0.75.
|
|
70
|
-
"@stacksjs/env": "0.75.
|
|
71
|
-
"@stacksjs/error-handling": "0.75.
|
|
72
|
-
"@stacksjs/faker": "0.75.
|
|
73
|
-
"@stacksjs/features": "0.75.
|
|
74
|
-
"@stacksjs/logging": "0.75.
|
|
75
|
-
"@stacksjs/model-meta": "0.75.
|
|
76
|
-
"@stacksjs/path": "0.75.
|
|
77
|
-
"@stacksjs/query-builder": "0.75.
|
|
78
|
-
"@stacksjs/security": "0.75.
|
|
79
|
-
"@stacksjs/storage": "0.75.
|
|
80
|
-
"@stacksjs/strings": "0.75.
|
|
69
|
+
"@stacksjs/config": "0.75.431",
|
|
70
|
+
"@stacksjs/env": "0.75.431",
|
|
71
|
+
"@stacksjs/error-handling": "0.75.431",
|
|
72
|
+
"@stacksjs/faker": "0.75.431",
|
|
73
|
+
"@stacksjs/features": "0.75.431",
|
|
74
|
+
"@stacksjs/logging": "0.75.431",
|
|
75
|
+
"@stacksjs/model-meta": "0.75.431",
|
|
76
|
+
"@stacksjs/path": "0.75.431",
|
|
77
|
+
"@stacksjs/query-builder": "0.75.431",
|
|
78
|
+
"@stacksjs/security": "0.75.431",
|
|
79
|
+
"@stacksjs/storage": "0.75.431",
|
|
80
|
+
"@stacksjs/strings": "0.75.431",
|
|
81
81
|
"@stacksjs/ts-validation": "^0.5.6",
|
|
82
|
-
"bun-query-builder": "^0.3.
|
|
82
|
+
"bun-query-builder": "^0.3.34",
|
|
83
83
|
"dynamodb-tooling": "^0.3.6"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@stacksjs/cli": "0.75.
|
|
87
|
-
"@stacksjs/router": "0.75.
|
|
88
|
-
"@stacksjs/utils": "0.75.
|
|
86
|
+
"@stacksjs/cli": "0.75.431",
|
|
87
|
+
"@stacksjs/router": "0.75.431",
|
|
88
|
+
"@stacksjs/utils": "0.75.431",
|
|
89
89
|
"better-dx": "^0.2.24"
|
|
90
90
|
}
|
|
91
91
|
}
|