drizzle-multitenant 1.3.0 → 1.3.2
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { C as Config, T as TenantManager, R as RetryConfig } from './types-CGqsPe2Q.js';
|
|
2
2
|
export { b as ConnectionConfig, n as ConnectionMetrics, q as DEFAULT_CONFIG, D as DebugConfig, e as DebugContext, h as HealthCheckOptions, i as HealthCheckResult, H as Hooks, I as IsolationConfig, c as IsolationStrategy, p as LintConfig, L as LintRuleConfig, o as LintRulesConfig, M as MetricsConfig, l as MetricsResult, P as PoolEntry, j as PoolHealth, k as PoolHealthStatus, d as SchemasConfig, S as SharedDb, a as TenantDb, m as TenantPoolMetrics, g as TenantWarmupResult, W as WarmupOptions, f as WarmupResult } from './types-CGqsPe2Q.js';
|
|
3
3
|
export { B as BaseTenantContext, a as TenantContext, T as TenantContextData, c as createTenantContext } from './context-BBLPNjmk.js';
|
|
4
|
-
export { A as AppliedMigration, C as CreateTenantOptions, D as DropTenantOptions, d as MigrateOptions, i as MigrationErrorHandler, b as MigrationFile, g as MigrationHooks, h as MigrationProgressCallback, e as MigrationResults, M as Migrator, a as MigratorConfig, S as SeedFunction, j as SeedOptions, l as SeedResults, m as SharedSeedFunction, n as SharedSeedResult, T as TenantMigrationResult, f as TenantMigrationStatus, k as TenantSeedResult, c as createMigrator } from './migrator-
|
|
4
|
+
export { A as AppliedMigration, C as CreateTenantOptions, D as DropTenantOptions, d as MigrateOptions, i as MigrationErrorHandler, b as MigrationFile, g as MigrationHooks, h as MigrationProgressCallback, e as MigrationResults, M as Migrator, a as MigratorConfig, S as SeedFunction, j as SeedOptions, l as SeedResults, m as SharedSeedFunction, n as SharedSeedResult, T as TenantMigrationResult, f as TenantMigrationStatus, k as TenantSeedResult, c as createMigrator } from './migrator-C7FtsZ0H.js';
|
|
5
5
|
export { ColumnSelection, CrossSchemaContext, CrossSchemaQueryBuilder, CrossSchemaRawOptions, InferSelectResult, InferSelectedColumns, JoinCondition, JoinDefinition, JoinType, LookupResult, SchemaSource, SharedLookupConfig, TableReference, WithSharedConfig, WithSharedOptions, WithSharedQueryBuilder, buildCrossSchemaSelect, createCrossSchemaQuery, crossSchemaRaw, withShared, withSharedLookup } from './cross-schema/index.js';
|
|
6
6
|
import 'pg';
|
|
7
7
|
import 'drizzle-orm/node-postgres';
|
package/dist/index.js
CHANGED
|
@@ -151,4 +151,4 @@ import {Pool}from'pg';import {drizzle}from'drizzle-orm/node-postgres';import {LR
|
|
|
151
151
|
AND tc.constraint_type = 'FOREIGN KEY'
|
|
152
152
|
AND tc.table_name != ccu.table_name`,[e]),a=new Map,r=new Set(t);for(let l of t)a.set(l,new Set);for(let l of n.rows)r.has(l.table_name)&&r.has(l.foreign_table_name)&&a.get(l.table_name).add(l.foreign_table_name);let s=[],i=new Map,o=[];for(let l of t)i.set(l,0);for(let[l,u]of a)for(let h of u)i.set(h,(i.get(h)??0)+1);for(let[l,u]of i)u===0&&o.push(l);for(;o.length>0;){let l=o.shift();s.push(l);for(let[u,h]of a)if(h.has(l)){h.delete(l);let d=(i.get(u)??0)-1;i.set(u,d),d===0&&o.push(u);}}let m=t.filter(l=>!s.includes(l));return [...s,...m]}async function ce(c,e,t,n,a,r){let s=0,i=await ze(c,e,n);await c.query("SET session_replication_role = replica");try{for(let o=0;o<i.length;o++){let m=i[o];r?.("copying_data",{table:m,progress:o+1,total:i.length});let l=await je(c,e,t,m,a);s+=l;}}finally{await c.query("SET session_replication_role = DEFAULT");}return s}var Be="__drizzle_migrations",H=class{constructor(e,t){this.deps=t;this.migrationsTable=e.migrationsTable??Be;}migrationsTable;async cloneTenant(e,t,n={}){let a=Date.now(),{includeData:r=false,anonymize:s,excludeTables:i=[],onProgress:o}=n,m=this.deps.schemaNameTemplate(e),l=this.deps.schemaNameTemplate(t),u=[this.migrationsTable,...i],h=null,d=null;try{if(o?.("starting"),!await this.deps.schemaExists(e))return this.createErrorResult(e,t,l,`Source tenant "${e}" does not exist`,a);if(await this.deps.schemaExists(t))return this.createErrorResult(e,t,l,`Target tenant "${t}" already exists`,a);o?.("introspecting"),h=await this.deps.createPool(m);let y=await ie(h,m,u);if(y.length===0)return o?.("creating_schema"),await this.deps.createSchema(t),o?.("completed"),{sourceTenant:e,targetTenant:t,targetSchema:l,success:!0,tables:[],durationMs:Date.now()-a};let b=await Promise.all(y.map(M=>oe(h,m,l,M)));await h.end(),h=null,o?.("creating_schema"),await this.deps.createSchema(t),d=await this.deps.createRootPool(),o?.("creating_tables");for(let M of b)await d.query(`SET search_path TO "${l}"; ${M.createDdl}`);o?.("creating_constraints");for(let M of b)for(let D of M.constraintDdls.filter(C=>!C.includes("FOREIGN KEY")))try{await d.query(`SET search_path TO "${l}"; ${D}`);}catch{}o?.("creating_indexes");for(let M of b)for(let D of M.indexDdls)try{await d.query(D);}catch{}let S=0;r&&(o?.("copying_data"),S=await ce(d,m,l,y,s?.enabled?s.rules:void 0,o));for(let M of b)for(let D of M.constraintDdls.filter(C=>C.includes("FOREIGN KEY")))try{await d.query(D);}catch{}o?.("completed");let N={sourceTenant:e,targetTenant:t,targetSchema:l,success:!0,tables:y,durationMs:Date.now()-a};return r&&(N.rowsCopied=S),N}catch(g){return n.onError?.(g),o?.("failed"),this.createErrorResult(e,t,l,g.message,a)}finally{h&&await h.end().catch(()=>{}),d&&await d.end().catch(()=>{});}}createErrorResult(e,t,n,a,r){return {sourceTenant:e,targetTenant:t,targetSchema:n,success:false,error:a,tables:[],durationMs:Date.now()-r}}};var We="public",q=class{constructor(e,t){this.config=e;this.deps=t;this.schemaName=e.schemaName??We;}schemaName;async migrate(e={}){let t=Date.now(),n=[],a=await this.deps.createPool();try{e.onProgress?.("starting"),await this.config.hooks?.beforeMigration?.();let r=await this.deps.getOrDetectFormat(a,this.schemaName);await this.deps.ensureMigrationsTable(a,this.schemaName,r);let s=await this.deps.loadMigrations(),i=await this.getAppliedMigrations(a,r),o=new Set(i.map(l=>l.identifier)),m=s.filter(l=>!this.isMigrationApplied(l,o,r));if(e.dryRun)return {schemaName:this.schemaName,success:!0,appliedMigrations:m.map(l=>l.name),durationMs:Date.now()-t,format:r.format};for(let l of m){let u=Date.now();e.onProgress?.("migrating",l.name),await this.applyMigration(a,l,r),await this.config.hooks?.afterMigration?.(l.name,Date.now()-u),n.push(l.name);}return e.onProgress?.("completed"),{schemaName:this.schemaName,success:!0,appliedMigrations:n,durationMs:Date.now()-t,format:r.format}}catch(r){return e.onProgress?.("failed"),{schemaName:this.schemaName,success:false,appliedMigrations:n,error:r.message,durationMs:Date.now()-t}}finally{await a.end();}}async markAsApplied(e={}){let t=Date.now(),n=[],a=await this.deps.createPool();try{e.onProgress?.("starting");let r=await this.deps.getOrDetectFormat(a,this.schemaName);await this.deps.ensureMigrationsTable(a,this.schemaName,r);let s=await this.deps.loadMigrations(),i=await this.getAppliedMigrations(a,r),o=new Set(i.map(l=>l.identifier)),m=s.filter(l=>!this.isMigrationApplied(l,o,r));for(let l of m)e.onProgress?.("migrating",l.name),await this.recordMigration(a,l,r),n.push(l.name);return e.onProgress?.("completed"),{schemaName:this.schemaName,success:!0,appliedMigrations:n,durationMs:Date.now()-t,format:r.format}}catch(r){return e.onProgress?.("failed"),{schemaName:this.schemaName,success:false,appliedMigrations:n,error:r.message,durationMs:Date.now()-t}}finally{await a.end();}}async getStatus(){let e=await this.deps.createPool();try{let t=await this.deps.loadMigrations();if(!await this.deps.migrationsTableExists(e,this.schemaName))return {schemaName:this.schemaName,appliedCount:0,pendingCount:t.length,pendingMigrations:t.map(o=>o.name),status:t.length>0?"behind":"ok",format:null};let a=await this.deps.getOrDetectFormat(e,this.schemaName),r=await this.getAppliedMigrations(e,a),s=new Set(r.map(o=>o.identifier)),i=t.filter(o=>!this.isMigrationApplied(o,s,a));return {schemaName:this.schemaName,appliedCount:r.length,pendingCount:i.length,pendingMigrations:i.map(o=>o.name),status:i.length>0?"behind":"ok",format:a.format}}catch(t){return {schemaName:this.schemaName,appliedCount:0,pendingCount:0,pendingMigrations:[],status:"error",error:t.message,format:null}}finally{await e.end();}}async getAppliedMigrations(e,t){let n=t.columns.identifier,a=t.columns.timestamp;return (await e.query(`SELECT id, "${n}" as identifier, "${a}" as applied_at
|
|
153
153
|
FROM "${this.schemaName}"."${t.tableName}"
|
|
154
|
-
ORDER BY id`)).rows.map(s=>{let i=t.columns.timestampType==="bigint"?new Date(Number(s.applied_at)):new Date(s.applied_at);return {identifier:s.identifier,...t.columns.identifier==="name"?{name:s.identifier}:{hash:s.identifier},appliedAt:i}})}isMigrationApplied(e,t,n){return n.columns.identifier==="name"?t.has(e.name):t.has(e.hash)||t.has(e.name)}async applyMigration(e,t,n){let a=await e.connect();try{await a.query("BEGIN"),await a.query(t.sql);let{identifier:r,timestamp:s,timestampType:i}=n.columns,o=r==="name"?t.name:t.hash,m=i==="bigint"?Date.now():new Date;await a.query(`INSERT INTO "${this.schemaName}"."${n.tableName}" ("${r}", "${s}") VALUES ($1, $2)`,[o,m]),await a.query("COMMIT");}catch(r){throw await a.query("ROLLBACK"),r}finally{a.release();}}async recordMigration(e,t,n){let{identifier:a,timestamp:r,timestampType:s}=n.columns,i=a==="name"?t.name:t.hash,o=s==="bigint"?Date.now():new Date;await e.query(`INSERT INTO "${this.schemaName}"."${n.tableName}" ("${a}", "${r}") VALUES ($1, $2)`,[i,o]);}};var Ue="__drizzle_migrations",ge="__drizzle_shared_migrations",j=class{constructor(e,t){this.migratorConfig=t;if(this.migrationsTable=t.migrationsTable??Ue,this.schemaManager=new O(e,this.migrationsTable),this.driftDetector=new $(e,this.schemaManager,{migrationsTable:this.migrationsTable,tenantDiscovery:t.tenantDiscovery}),this.seeder=new A({tenantDiscovery:t.tenantDiscovery},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,tenantSchema:e.schemas.tenant}),this.syncManager=new F({tenantDiscovery:t.tenantDiscovery,migrationsFolder:t.migrationsFolder,migrationsTable:this.migrationsTable},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectFormat.bind(this),loadMigrations:this.loadMigrations.bind(this)}),this.migrationExecutor=new L({hooks:t.hooks},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectFormat.bind(this),loadMigrations:this.loadMigrations.bind(this)}),this.batchExecutor=new I({tenantDiscovery:t.tenantDiscovery},this.migrationExecutor,this.loadMigrations.bind(this)),this.cloner=new H({migrationsTable:this.migrationsTable},{createPool:this.schemaManager.createPool.bind(this.schemaManager),createRootPool:this.schemaManager.createRootPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,schemaExists:this.schemaManager.schemaExists.bind(this.schemaManager),createSchema:this.schemaManager.createSchema.bind(this.schemaManager)}),t.sharedMigrationsFolder&&existsSync(t.sharedMigrationsFolder)){let n=t.sharedMigrationsTable??ge,a=t.sharedHooks,r={schemaName:"public",migrationsTable:n};(a?.beforeMigration||a?.afterApply)&&(r.hooks={},a.beforeMigration&&(r.hooks.beforeMigration=a.beforeMigration),a.afterApply&&(r.hooks.afterMigration=a.afterApply)),this.sharedMigrationExecutor=new q(r,{createPool:this.schemaManager.createRootPool.bind(this.schemaManager),migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectSharedFormat.bind(this),loadMigrations:this.loadSharedMigrations.bind(this)});}else this.sharedMigrationExecutor=null;e.schemas.shared?this.sharedSeeder=new v({schemaName:"public"},{createPool:this.schemaManager.createRootPool.bind(this.schemaManager),sharedSchema:e.schemas.shared}):this.sharedSeeder=null;}migrationsTable;schemaManager;driftDetector;seeder;syncManager;migrationExecutor;batchExecutor;cloner;sharedMigrationExecutor;sharedSeeder;async migrateAll(e={}){return this.batchExecutor.migrateAll(e)}async migrateTenant(e,t,n={}){return this.migrationExecutor.migrateTenant(e,t,n)}async migrateTenants(e,t={}){return this.batchExecutor.migrateTenants(e,t)}async getStatus(){return this.batchExecutor.getStatus()}async getTenantStatus(e,t){return this.migrationExecutor.getTenantStatus(e,t)}async createTenant(e,t={}){let{migrate:n=true}=t;await this.schemaManager.createSchema(e),n&&await this.migrateTenant(e);}async dropTenant(e,t={}){await this.schemaManager.dropSchema(e,t);}async tenantExists(e){return this.schemaManager.schemaExists(e)}async cloneTenant(e,t,n={}){return this.cloner.cloneTenant(e,t,n)}async markAsApplied(e,t={}){return this.migrationExecutor.markAsApplied(e,t)}async markAllAsApplied(e={}){return this.batchExecutor.markAllAsApplied(e)}async getSyncStatus(){return this.syncManager.getSyncStatus()}async getTenantSyncStatus(e,t){return this.syncManager.getTenantSyncStatus(e,t)}async markMissing(e){return this.syncManager.markMissing(e)}async markAllMissing(e={}){return this.syncManager.markAllMissing(e)}async cleanOrphans(e){return this.syncManager.cleanOrphans(e)}async cleanAllOrphans(e={}){return this.syncManager.cleanAllOrphans(e)}async seedTenant(e,t){return this.seeder.seedTenant(e,t)}async seedAll(e,t={}){return this.seeder.seedAll(e,t)}async seedTenants(e,t,n={}){return this.seeder.seedTenants(e,t,n)}hasSharedSeeding(){return this.sharedSeeder!==null}async seedShared(e){return this.sharedSeeder?this.sharedSeeder.seed(e):{schemaName:"public",success:false,error:"Shared schema not configured. Set schemas.shared in tenant config.",durationMs:0}}async seedAllWithShared(e,t,n={}){let a=await this.seedShared(e),r=await this.seedAll(t,n);return {shared:a,tenants:r}}async loadMigrations(){let e=await readdir(this.migratorConfig.migrationsFolder),t=[];for(let n of e){if(!n.endsWith(".sql"))continue;let a=join(this.migratorConfig.migrationsFolder,n),r=await readFile(a,"utf-8"),s=n.match(/^(\d+)_/),i=s?.[1]?parseInt(s[1],10):0,o=createHash("sha256").update(r).digest("hex");t.push({name:basename(n,".sql"),path:a,sql:r,timestamp:i,hash:o});}return t.sort((n,a)=>n.timestamp-a.timestamp)}async getOrDetectFormat(e,t){let n=this.migratorConfig.tableFormat??"auto";if(n!=="auto")return _(n,this.migrationsTable);let a=await Y(e,t,this.migrationsTable);if(a)return a;let r=this.migratorConfig.defaultFormat??"name";return _(r,this.migrationsTable)}async loadSharedMigrations(){if(!this.migratorConfig.sharedMigrationsFolder)return [];let e=await readdir(this.migratorConfig.sharedMigrationsFolder),t=[];for(let n of e){if(!n.endsWith(".sql"))continue;let a=join(this.migratorConfig.sharedMigrationsFolder,n),r=await readFile(a,"utf-8"),s=n.match(/^(\d+)_/),i=s?.[1]?parseInt(s[1],10):0,o=createHash("sha256").update(r).digest("hex");t.push({name:basename(n,".sql"),path:a,sql:r,timestamp:i,hash:o});}return t.sort((n,a)=>n.timestamp-a.timestamp)}async getOrDetectSharedFormat(e,t){let n=this.migratorConfig.sharedMigrationsTable??ge,a=this.migratorConfig.tableFormat??"auto";if(a!=="auto")return _(a,n);let r=await Y(e,t,n);if(r)return r;let s=this.migratorConfig.defaultFormat??"name";return _(s,n)}hasSharedMigrations(){return this.sharedMigrationExecutor!==null}async migrateShared(e={}){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.migrate(e):{schemaName:"public",success:false,appliedMigrations:[],error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",durationMs:0}}async getSharedStatus(){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.getStatus():{schemaName:"public",appliedCount:0,pendingCount:0,pendingMigrations:[],status:"error",error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",format:null}}async markSharedAsApplied(e={}){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.markAsApplied(e):{schemaName:"public",success:false,appliedMigrations:[],error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",durationMs:0}}async migrateAllWithShared(e={}){let{sharedOptions:t,...n}=e,a=await this.migrateShared(t??{}),r=await this.migrateAll(n);return {shared:a,tenants:r}}async getSchemaDrift(e={}){return this.driftDetector.detectDrift(e)}async getTenantSchemaDrift(e,t,n={}){return this.driftDetector.compareTenant(e,t,n)}async introspectTenantSchema(e,t={}){return this.driftDetector.introspectSchema(e,t)}};function Qe(c,e){return new j(c,e)}var z=class{constructor(e){this.context=e;}fromTable=null;joins=[];selectFields={};whereCondition=null;orderByFields=[];limitValue=null;offsetValue=null;from(e,t){let n=this.getSchemaName(e);return this.fromTable={table:t,source:e,schemaName:n},this}innerJoin(e,t,n){return this.addJoin(e,t,n,"inner")}leftJoin(e,t,n){return this.addJoin(e,t,n,"left")}rightJoin(e,t,n){return this.addJoin(e,t,n,"right")}fullJoin(e,t,n){return this.addJoin(e,t,n,"full")}select(e){return this.selectFields=e,this}where(e){return this.whereCondition=e,this}orderBy(...e){return this.orderByFields=e,this}limit(e){return this.limitValue=e,this}offset(e){return this.offsetValue=e,this}async execute(){if(!this.fromTable)throw new Error("[drizzle-multitenant] No table specified. Use .from() first.");let e=this.buildSql();return (await this.context.tenantDb.execute(e)).rows}buildSql(){if(!this.fromTable)throw new Error("[drizzle-multitenant] No table specified");let e=[],t=Object.entries(this.selectFields).map(([a,r])=>{let s=r.name;return sql`${sql.raw(`"${s}"`)} as ${sql.raw(`"${a}"`)}`});t.length===0?e.push(sql`SELECT *`):e.push(sql`SELECT ${sql.join(t,sql`, `)}`);let n=this.getFullTableName(this.fromTable.schemaName,this.fromTable.table);e.push(sql` FROM ${sql.raw(n)}`);for(let a of this.joins){let r=this.getFullTableName(a.schemaName,a.table),s=this.getJoinKeyword(a.type);e.push(sql` ${sql.raw(s)} ${sql.raw(r)} ON ${a.condition}`);}return this.whereCondition&&e.push(sql` WHERE ${this.whereCondition}`),this.orderByFields.length>0&&e.push(sql` ORDER BY ${sql.join(this.orderByFields,sql`, `)}`),this.limitValue!==null&&e.push(sql` LIMIT ${sql.raw(this.limitValue.toString())}`),this.offsetValue!==null&&e.push(sql` OFFSET ${sql.raw(this.offsetValue.toString())}`),sql.join(e,sql``)}addJoin(e,t,n,a){let r=this.getSchemaName(e);return this.joins.push({table:t,source:e,schemaName:r,condition:n,type:a}),this}getSchemaName(e){return e==="tenant"?this.context.tenantSchema??"tenant":this.context.sharedSchema??"public"}getFullTableName(e,t){let n=getTableName(t);return `"${e}"."${n}"`}getJoinKeyword(e){switch(e){case "inner":return "INNER JOIN";case "left":return "LEFT JOIN";case "right":return "RIGHT JOIN";case "full":return "FULL OUTER JOIN"}}};function Ye(c){return new z(c)}async function Ve(c){let{tenantDb:e,tenantTable:t,sharedTable:n,foreignKey:a,sharedKey:r="id",sharedFields:s,where:i}=c,o=getTableName(t),m=getTableName(n),u=[`SELECT t.*, ${s.map(g=>`s."${String(g)}"`).join(", ")}`,`FROM "${o}" t`,`LEFT JOIN "public"."${m}" s ON t."${String(a)}" = s."${String(r)}"`];i&&u.push("WHERE");let h=sql.raw(u.join(" "));return (await e.execute(h)).rows}async function Ke(c,e){let{tenantSchema:t,sharedSchema:n,sql:a}=e,r=a.replace(/\$tenant\./g,`"${t}".`).replace(/\$shared\./g,`"${n}".`),s=sql.raw(r);return (await c.execute(s)).rows}function Ge(c,e,t){return {columns:Object.entries(c).map(([r,s])=>`"${s.name}" as "${r}"`),getSchema:()=>e}}function Xe(c){let e=new Set;for(let t of Object.values(c))t&&typeof t=="object"&&"_"in t&&t._?.brand==="Table"&&e.add(t);return e}function pe(c,e){return e.has(c)}var B=class{constructor(e,t,n,a="public"){this.tenantDb=e;this.sharedTables=t;this.tenantSchemaName=n;this.sharedSchemaName=a;}fromTable=null;joins=[];selectFields={};whereCondition=null;orderByFields=[];limitValue=null;offsetValue=null;from(e){let t=pe(e,this.sharedTables);return this.fromTable={table:e,isShared:t,schemaName:t?this.sharedSchemaName:this.tenantSchemaName},this}leftJoin(e,t){return this.addJoin(e,t,"left")}innerJoin(e,t){return this.addJoin(e,t,"inner")}rightJoin(e,t){return this.addJoin(e,t,"right")}fullJoin(e,t){return this.addJoin(e,t,"full")}select(e){return this.selectFields=e,this}where(e){return this.whereCondition=e,this}orderBy(...e){return this.orderByFields=e,this}limit(e){return this.limitValue=e,this}offset(e){return this.offsetValue=e,this}async execute(){if(!this.fromTable)throw new Error("[drizzle-multitenant] No table specified. Use .from() first.");let e=this.buildSql();return (await this.tenantDb.execute(e)).rows}addJoin(e,t,n){let a=pe(e,this.sharedTables);return this.joins.push({table:e,isShared:a,schemaName:a?this.sharedSchemaName:this.tenantSchemaName,condition:t,type:n}),this}buildSql(){if(!this.fromTable)throw new Error("[drizzle-multitenant] No table specified");let e=[],t=Object.entries(this.selectFields).map(([r,s])=>{let i=s.name,o=this.getTableAliasForColumn(s);return o?sql`${sql.raw(`"${o}"."${i}"`)} as ${sql.raw(`"${r}"`)}`:sql`${sql.raw(`"${i}"`)} as ${sql.raw(`"${r}"`)}`});t.length===0?e.push(sql`SELECT *`):e.push(sql`SELECT ${sql.join(t,sql`, `)}`);let n=getTableName(this.fromTable.table),a=`"${this.fromTable.schemaName}"."${n}"`;e.push(sql` FROM ${sql.raw(a)} "${sql.raw(n)}"`);for(let r of this.joins){let s=getTableName(r.table),i=`"${r.schemaName}"."${s}"`,o=this.getJoinKeyword(r.type);e.push(sql` ${sql.raw(o)} ${sql.raw(i)} "${sql.raw(s)}" ON ${r.condition}`);}return this.whereCondition&&e.push(sql` WHERE ${this.whereCondition}`),this.orderByFields.length>0&&e.push(sql` ORDER BY ${sql.join(this.orderByFields,sql`, `)}`),this.limitValue!==null&&e.push(sql` LIMIT ${sql.raw(this.limitValue.toString())}`),this.offsetValue!==null&&e.push(sql` OFFSET ${sql.raw(this.offsetValue.toString())}`),sql.join(e,sql``)}getTableAliasForColumn(e){let t=e.table;return t?getTableName(t):null}getJoinKeyword(e){switch(e){case "inner":return "INNER JOIN";case "left":return "LEFT JOIN";case "right":return "RIGHT JOIN";case "full":return "FULL OUTER JOIN"}}};function Ze(c,e,t,n){let a=Xe(t.shared);return new B(c,a,n?.tenantSchema??"tenant",n?.sharedSchema??"public")}function fe(c){let e=c.message.toLowerCase();return !!(e.includes("econnrefused")||e.includes("econnreset")||e.includes("etimedout")||e.includes("enotfound")||e.includes("connection refused")||e.includes("connection reset")||e.includes("connection terminated")||e.includes("connection timed out")||e.includes("timeout expired")||e.includes("socket hang up")||e.includes("too many connections")||e.includes("sorry, too many clients")||e.includes("the database system is starting up")||e.includes("the database system is shutting down")||e.includes("server closed the connection unexpectedly")||e.includes("could not connect to server")||e.includes("ssl connection")||e.includes("ssl handshake"))}function ye(c,e){let t=e.initialDelayMs*Math.pow(e.backoffMultiplier,c),n=Math.min(t,e.maxDelayMs);if(e.jitter){let a=1+Math.random()*.25;return Math.floor(n*a)}return Math.floor(n)}function et(c){return new Promise(e=>setTimeout(e,c))}async function Te(c,e){let t={maxAttempts:e?.maxAttempts??T.retry.maxAttempts,initialDelayMs:e?.initialDelayMs??T.retry.initialDelayMs,maxDelayMs:e?.maxDelayMs??T.retry.maxDelayMs,backoffMultiplier:e?.backoffMultiplier??T.retry.backoffMultiplier,jitter:e?.jitter??T.retry.jitter,isRetryable:e?.isRetryable??fe,onRetry:e?.onRetry},n=Date.now(),a=null;for(let r=0;r<t.maxAttempts;r++)try{return {result:await c(),attempts:r+1,totalTimeMs:Date.now()-n}}catch(s){if(a=s,r>=t.maxAttempts-1||!t.isRetryable(a))throw a;let o=ye(r,t);t.onRetry?.(r+1,a,o),await et(o);}throw a??new Error("Retry failed with no error")}function tt(c){return e=>Te(e,c)}export{z as CrossSchemaQueryBuilder,T as DEFAULT_CONFIG,j as Migrator,B as WithSharedQueryBuilder,Ge as buildCrossSchemaSelect,ye as calculateDelay,Ye as createCrossSchemaQuery,Qe as createMigrator,tt as createRetrier,De as createTenantContext,Re as createTenantManager,Ke as crossSchemaRaw,Se as defineConfig,fe as isRetryableError,Te as withRetry,Ze as withShared,Ve as withSharedLookup};
|
|
154
|
+
ORDER BY id`)).rows.map(s=>{let i=t.columns.timestampType==="bigint"?new Date(Number(s.applied_at)):new Date(s.applied_at);return {identifier:s.identifier,...t.columns.identifier==="name"?{name:s.identifier}:{hash:s.identifier},appliedAt:i}})}isMigrationApplied(e,t,n){return n.columns.identifier==="name"?t.has(e.name):t.has(e.hash)||t.has(e.name)}async applyMigration(e,t,n){let a=await e.connect();try{await a.query("BEGIN"),await a.query(t.sql);let{identifier:r,timestamp:s,timestampType:i}=n.columns,o=r==="name"?t.name:t.hash,m=i==="bigint"?Date.now():new Date;await a.query(`INSERT INTO "${this.schemaName}"."${n.tableName}" ("${r}", "${s}") VALUES ($1, $2)`,[o,m]),await a.query("COMMIT");}catch(r){throw await a.query("ROLLBACK"),r}finally{a.release();}}async recordMigration(e,t,n){let{identifier:a,timestamp:r,timestampType:s}=n.columns,i=a==="name"?t.name:t.hash,o=s==="bigint"?Date.now():new Date;await e.query(`INSERT INTO "${this.schemaName}"."${n.tableName}" ("${a}", "${r}") VALUES ($1, $2)`,[i,o]);}};var Ue="__drizzle_migrations",ge="__drizzle_shared_migrations",j=class{constructor(e,t){this.migratorConfig=t;if(this.migrationsTable=t.migrationsTable??Ue,this.schemaManager=new O(e,this.migrationsTable),this.driftDetector=new $(e,this.schemaManager,{migrationsTable:this.migrationsTable,tenantDiscovery:t.tenantDiscovery}),this.seeder=new A({tenantDiscovery:t.tenantDiscovery},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,tenantSchema:e.schemas.tenant}),this.syncManager=new F({tenantDiscovery:t.tenantDiscovery,migrationsFolder:t.migrationsFolder,migrationsTable:this.migrationsTable},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectFormat.bind(this),loadMigrations:this.loadMigrations.bind(this)}),this.migrationExecutor=new L({hooks:t.hooks},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectFormat.bind(this),loadMigrations:this.loadMigrations.bind(this)}),this.batchExecutor=new I({tenantDiscovery:t.tenantDiscovery},this.migrationExecutor,this.loadMigrations.bind(this)),this.cloner=new H({migrationsTable:this.migrationsTable},{createPool:this.schemaManager.createPool.bind(this.schemaManager),createRootPool:this.schemaManager.createRootPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,schemaExists:this.schemaManager.schemaExists.bind(this.schemaManager),createSchema:this.schemaManager.createSchema.bind(this.schemaManager)}),t.sharedMigrationsFolder&&existsSync(t.sharedMigrationsFolder)){let n=t.sharedMigrationsTable??ge,a=t.sharedHooks,r={schemaName:"public",migrationsTable:n};(a?.beforeMigration||a?.afterApply)&&(r.hooks={},a.beforeMigration&&(r.hooks.beforeMigration=a.beforeMigration),a.afterApply&&(r.hooks.afterMigration=a.afterApply)),this.sharedMigrationExecutor=new q(r,{createPool:this.schemaManager.createRootPool.bind(this.schemaManager),migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectSharedFormat.bind(this),loadMigrations:this.loadSharedMigrations.bind(this)});}else this.sharedMigrationExecutor=null;e.schemas.shared?this.sharedSeeder=new v({schemaName:"public"},{createPool:this.schemaManager.createRootPool.bind(this.schemaManager),sharedSchema:e.schemas.shared}):this.sharedSeeder=null;}migrationsTable;schemaManager;driftDetector;seeder;syncManager;migrationExecutor;batchExecutor;cloner;sharedMigrationExecutor;sharedSeeder;async migrateAll(e={}){return this.batchExecutor.migrateAll(e)}async migrateTenant(e,t,n={}){return this.migrationExecutor.migrateTenant(e,t,n)}async migrateTenants(e,t={}){return this.batchExecutor.migrateTenants(e,t)}async getStatus(){return this.batchExecutor.getStatus()}async getTenantStatus(e,t){return this.migrationExecutor.getTenantStatus(e,t)}async createTenant(e,t={}){let{migrate:n=true}=t;await this.schemaManager.createSchema(e),n&&await this.migrateTenant(e);}async dropTenant(e,t={}){await this.schemaManager.dropSchema(e,t);}async tenantExists(e){return this.schemaManager.schemaExists(e)}async cloneTenant(e,t,n={}){return this.cloner.cloneTenant(e,t,n)}async markAsApplied(e,t={}){return this.migrationExecutor.markAsApplied(e,t)}async markAllAsApplied(e={}){return this.batchExecutor.markAllAsApplied(e)}async getSyncStatus(){return this.syncManager.getSyncStatus()}async getTenantSyncStatus(e,t){return this.syncManager.getTenantSyncStatus(e,t)}async markMissing(e){return this.syncManager.markMissing(e)}async markAllMissing(e={}){return this.syncManager.markAllMissing(e)}async cleanOrphans(e){return this.syncManager.cleanOrphans(e)}async cleanAllOrphans(e={}){return this.syncManager.cleanAllOrphans(e)}async seedTenant(e,t){return this.seeder.seedTenant(e,t)}async seedAll(e,t={}){return this.seeder.seedAll(e,t)}async seedTenants(e,t,n={}){return this.seeder.seedTenants(e,t,n)}hasSharedSeeding(){return this.sharedSeeder!==null}async seedShared(e){return this.sharedSeeder?this.sharedSeeder.seed(e):{schemaName:"public",success:false,error:"Shared schema not configured. Set schemas.shared in tenant config.",durationMs:0}}async seedAllWithShared(e,t,n={}){let a=await this.seedShared(e),r=await this.seedAll(t,n);return {shared:a,tenants:r}}async loadMigrations(){let e=await readdir(this.migratorConfig.migrationsFolder),t=[];for(let n of e){if(!n.endsWith(".sql"))continue;let a=join(this.migratorConfig.migrationsFolder,n),r=await readFile(a,"utf-8"),s=n.match(/^(\d+)_/),i=s?.[1]?parseInt(s[1],10):0,o=createHash("sha256").update(r).digest("hex");t.push({name:basename(n,".sql"),path:a,sql:r,timestamp:i,hash:o});}return t.sort((n,a)=>n.timestamp-a.timestamp)}async getOrDetectFormat(e,t){let n=this.migratorConfig.tableFormat??"auto";if(n!=="auto")return _(n,this.migrationsTable);let a=await Y(e,t,this.migrationsTable);if(a)return a;let r=this.migratorConfig.defaultFormat??"name";return _(r,this.migrationsTable)}async loadSharedMigrations(){if(!this.migratorConfig.sharedMigrationsFolder)return [];let e=await readdir(this.migratorConfig.sharedMigrationsFolder),t=[];for(let n of e){if(!n.endsWith(".sql"))continue;let a=join(this.migratorConfig.sharedMigrationsFolder,n),r=await readFile(a,"utf-8"),s=n.match(/^(\d+)_/),i=s?.[1]?parseInt(s[1],10):0,o=createHash("sha256").update(r).digest("hex");t.push({name:basename(n,".sql"),path:a,sql:r,timestamp:i,hash:o});}return t.sort((n,a)=>n.timestamp-a.timestamp)}async getOrDetectSharedFormat(e,t){let n=this.migratorConfig.sharedMigrationsTable??ge,a=this.migratorConfig.sharedTableFormat??this.migratorConfig.tableFormat??"auto";if(a!=="auto")return _(a,n);let r=await Y(e,t,n);if(r)return r;let s=this.migratorConfig.sharedDefaultFormat??this.migratorConfig.defaultFormat??"name";return _(s,n)}hasSharedMigrations(){return this.sharedMigrationExecutor!==null}async migrateShared(e={}){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.migrate(e):{schemaName:"public",success:false,appliedMigrations:[],error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",durationMs:0}}async getSharedStatus(){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.getStatus():{schemaName:"public",appliedCount:0,pendingCount:0,pendingMigrations:[],status:"error",error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",format:null}}async markSharedAsApplied(e={}){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.markAsApplied(e):{schemaName:"public",success:false,appliedMigrations:[],error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",durationMs:0}}async migrateAllWithShared(e={}){let{sharedOptions:t,...n}=e,a=await this.migrateShared(t??{}),r=await this.migrateAll(n);return {shared:a,tenants:r}}async getSchemaDrift(e={}){return this.driftDetector.detectDrift(e)}async getTenantSchemaDrift(e,t,n={}){return this.driftDetector.compareTenant(e,t,n)}async introspectTenantSchema(e,t={}){return this.driftDetector.introspectSchema(e,t)}};function Qe(c,e){return new j(c,e)}var z=class{constructor(e){this.context=e;}fromTable=null;joins=[];selectFields={};whereCondition=null;orderByFields=[];limitValue=null;offsetValue=null;from(e,t){let n=this.getSchemaName(e);return this.fromTable={table:t,source:e,schemaName:n},this}innerJoin(e,t,n){return this.addJoin(e,t,n,"inner")}leftJoin(e,t,n){return this.addJoin(e,t,n,"left")}rightJoin(e,t,n){return this.addJoin(e,t,n,"right")}fullJoin(e,t,n){return this.addJoin(e,t,n,"full")}select(e){return this.selectFields=e,this}where(e){return this.whereCondition=e,this}orderBy(...e){return this.orderByFields=e,this}limit(e){return this.limitValue=e,this}offset(e){return this.offsetValue=e,this}async execute(){if(!this.fromTable)throw new Error("[drizzle-multitenant] No table specified. Use .from() first.");let e=this.buildSql();return (await this.context.tenantDb.execute(e)).rows}buildSql(){if(!this.fromTable)throw new Error("[drizzle-multitenant] No table specified");let e=[],t=Object.entries(this.selectFields).map(([a,r])=>{let s=r.name;return sql`${sql.raw(`"${s}"`)} as ${sql.raw(`"${a}"`)}`});t.length===0?e.push(sql`SELECT *`):e.push(sql`SELECT ${sql.join(t,sql`, `)}`);let n=this.getFullTableName(this.fromTable.schemaName,this.fromTable.table);e.push(sql` FROM ${sql.raw(n)}`);for(let a of this.joins){let r=this.getFullTableName(a.schemaName,a.table),s=this.getJoinKeyword(a.type);e.push(sql` ${sql.raw(s)} ${sql.raw(r)} ON ${a.condition}`);}return this.whereCondition&&e.push(sql` WHERE ${this.whereCondition}`),this.orderByFields.length>0&&e.push(sql` ORDER BY ${sql.join(this.orderByFields,sql`, `)}`),this.limitValue!==null&&e.push(sql` LIMIT ${sql.raw(this.limitValue.toString())}`),this.offsetValue!==null&&e.push(sql` OFFSET ${sql.raw(this.offsetValue.toString())}`),sql.join(e,sql``)}addJoin(e,t,n,a){let r=this.getSchemaName(e);return this.joins.push({table:t,source:e,schemaName:r,condition:n,type:a}),this}getSchemaName(e){return e==="tenant"?this.context.tenantSchema??"tenant":this.context.sharedSchema??"public"}getFullTableName(e,t){let n=getTableName(t);return `"${e}"."${n}"`}getJoinKeyword(e){switch(e){case "inner":return "INNER JOIN";case "left":return "LEFT JOIN";case "right":return "RIGHT JOIN";case "full":return "FULL OUTER JOIN"}}};function Ye(c){return new z(c)}async function Ve(c){let{tenantDb:e,tenantTable:t,sharedTable:n,foreignKey:a,sharedKey:r="id",sharedFields:s,where:i}=c,o=getTableName(t),m=getTableName(n),u=[`SELECT t.*, ${s.map(g=>`s."${String(g)}"`).join(", ")}`,`FROM "${o}" t`,`LEFT JOIN "public"."${m}" s ON t."${String(a)}" = s."${String(r)}"`];i&&u.push("WHERE");let h=sql.raw(u.join(" "));return (await e.execute(h)).rows}async function Ke(c,e){let{tenantSchema:t,sharedSchema:n,sql:a}=e,r=a.replace(/\$tenant\./g,`"${t}".`).replace(/\$shared\./g,`"${n}".`),s=sql.raw(r);return (await c.execute(s)).rows}function Ge(c,e,t){return {columns:Object.entries(c).map(([r,s])=>`"${s.name}" as "${r}"`),getSchema:()=>e}}function Xe(c){let e=new Set;for(let t of Object.values(c))t&&typeof t=="object"&&"_"in t&&t._?.brand==="Table"&&e.add(t);return e}function pe(c,e){return e.has(c)}var B=class{constructor(e,t,n,a="public"){this.tenantDb=e;this.sharedTables=t;this.tenantSchemaName=n;this.sharedSchemaName=a;}fromTable=null;joins=[];selectFields={};whereCondition=null;orderByFields=[];limitValue=null;offsetValue=null;from(e){let t=pe(e,this.sharedTables);return this.fromTable={table:e,isShared:t,schemaName:t?this.sharedSchemaName:this.tenantSchemaName},this}leftJoin(e,t){return this.addJoin(e,t,"left")}innerJoin(e,t){return this.addJoin(e,t,"inner")}rightJoin(e,t){return this.addJoin(e,t,"right")}fullJoin(e,t){return this.addJoin(e,t,"full")}select(e){return this.selectFields=e,this}where(e){return this.whereCondition=e,this}orderBy(...e){return this.orderByFields=e,this}limit(e){return this.limitValue=e,this}offset(e){return this.offsetValue=e,this}async execute(){if(!this.fromTable)throw new Error("[drizzle-multitenant] No table specified. Use .from() first.");let e=this.buildSql();return (await this.tenantDb.execute(e)).rows}addJoin(e,t,n){let a=pe(e,this.sharedTables);return this.joins.push({table:e,isShared:a,schemaName:a?this.sharedSchemaName:this.tenantSchemaName,condition:t,type:n}),this}buildSql(){if(!this.fromTable)throw new Error("[drizzle-multitenant] No table specified");let e=[],t=Object.entries(this.selectFields).map(([r,s])=>{let i=s.name,o=this.getTableAliasForColumn(s);return o?sql`${sql.raw(`"${o}"."${i}"`)} as ${sql.raw(`"${r}"`)}`:sql`${sql.raw(`"${i}"`)} as ${sql.raw(`"${r}"`)}`});t.length===0?e.push(sql`SELECT *`):e.push(sql`SELECT ${sql.join(t,sql`, `)}`);let n=getTableName(this.fromTable.table),a=`"${this.fromTable.schemaName}"."${n}"`;e.push(sql` FROM ${sql.raw(a)} "${sql.raw(n)}"`);for(let r of this.joins){let s=getTableName(r.table),i=`"${r.schemaName}"."${s}"`,o=this.getJoinKeyword(r.type);e.push(sql` ${sql.raw(o)} ${sql.raw(i)} "${sql.raw(s)}" ON ${r.condition}`);}return this.whereCondition&&e.push(sql` WHERE ${this.whereCondition}`),this.orderByFields.length>0&&e.push(sql` ORDER BY ${sql.join(this.orderByFields,sql`, `)}`),this.limitValue!==null&&e.push(sql` LIMIT ${sql.raw(this.limitValue.toString())}`),this.offsetValue!==null&&e.push(sql` OFFSET ${sql.raw(this.offsetValue.toString())}`),sql.join(e,sql``)}getTableAliasForColumn(e){let t=e.table;return t?getTableName(t):null}getJoinKeyword(e){switch(e){case "inner":return "INNER JOIN";case "left":return "LEFT JOIN";case "right":return "RIGHT JOIN";case "full":return "FULL OUTER JOIN"}}};function Ze(c,e,t,n){let a=Xe(t.shared);return new B(c,a,n?.tenantSchema??"tenant",n?.sharedSchema??"public")}function fe(c){let e=c.message.toLowerCase();return !!(e.includes("econnrefused")||e.includes("econnreset")||e.includes("etimedout")||e.includes("enotfound")||e.includes("connection refused")||e.includes("connection reset")||e.includes("connection terminated")||e.includes("connection timed out")||e.includes("timeout expired")||e.includes("socket hang up")||e.includes("too many connections")||e.includes("sorry, too many clients")||e.includes("the database system is starting up")||e.includes("the database system is shutting down")||e.includes("server closed the connection unexpectedly")||e.includes("could not connect to server")||e.includes("ssl connection")||e.includes("ssl handshake"))}function ye(c,e){let t=e.initialDelayMs*Math.pow(e.backoffMultiplier,c),n=Math.min(t,e.maxDelayMs);if(e.jitter){let a=1+Math.random()*.25;return Math.floor(n*a)}return Math.floor(n)}function et(c){return new Promise(e=>setTimeout(e,c))}async function Te(c,e){let t={maxAttempts:e?.maxAttempts??T.retry.maxAttempts,initialDelayMs:e?.initialDelayMs??T.retry.initialDelayMs,maxDelayMs:e?.maxDelayMs??T.retry.maxDelayMs,backoffMultiplier:e?.backoffMultiplier??T.retry.backoffMultiplier,jitter:e?.jitter??T.retry.jitter,isRetryable:e?.isRetryable??fe,onRetry:e?.onRetry},n=Date.now(),a=null;for(let r=0;r<t.maxAttempts;r++)try{return {result:await c(),attempts:r+1,totalTimeMs:Date.now()-n}}catch(s){if(a=s,r>=t.maxAttempts-1||!t.isRetryable(a))throw a;let o=ye(r,t);t.onRetry?.(r+1,a,o),await et(o);}throw a??new Error("Retry failed with no error")}function tt(c){return e=>Te(e,c)}export{z as CrossSchemaQueryBuilder,T as DEFAULT_CONFIG,j as Migrator,B as WithSharedQueryBuilder,Ge as buildCrossSchemaSelect,ye as calculateDelay,Ye as createCrossSchemaQuery,Qe as createMigrator,tt as createRetrier,De as createTenantContext,Re as createTenantManager,Ke as crossSchemaRaw,Se as defineConfig,fe as isRetryableError,Te as withRetry,Ze as withShared,Ve as withSharedLookup};
|
package/dist/migrator/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { o as DetectedFormat, S as SeedFunction, k as TenantSeedResult, j as SeedOptions, l as SeedResults, p as SyncStatus, b as MigrationFile, q as TenantSyncStatus, r as TenantSyncResult, s as SyncOptions, t as SyncResults, d as MigrateOptions, e as MigrationResults, g as MigrationHooks, h as MigrationProgressCallback, i as MigrationErrorHandler, T as TenantMigrationResult, f as TenantMigrationStatus, u as ClonerConfig, v as ClonerDependencies, w as CloneTenantOptions, x as CloneTenantResult, y as SharedMigrateOptions, z as SharedMigrationResult, B as SharedMigrationStatus } from '../migrator-
|
|
2
|
-
export { _ as AnonymizeOptions, $ as AnonymizeRules, a0 as AnonymizeValue, A as AppliedMigration, Y as CloneProgressCallback, Z as CloneProgressStatus, P as ColumnDrift, J as ColumnInfo, R as ConstraintDrift, L as ConstraintInfo, C as CreateTenantOptions, G as DEFAULT_FORMAT, H as DRIZZLE_KIT_FORMAT, D as DropTenantOptions, Q as IndexDrift, K as IndexInfo, M as Migrator, a as MigratorConfig, X as SchemaDriftOptions, W as SchemaDriftStatus, a2 as SharedMigrationHooks, a1 as SharedMigratorConfig, m as SharedSeedFunction, n as SharedSeedResult, U as TableDrift, I as TableFormat, N as TableSchema, O as TenantSchema, V as TenantSchemaDrift, c as createMigrator, E as detectTableFormat, F as getFormatConfig } from '../migrator-
|
|
1
|
+
import { o as DetectedFormat, S as SeedFunction, k as TenantSeedResult, j as SeedOptions, l as SeedResults, p as SyncStatus, b as MigrationFile, q as TenantSyncStatus, r as TenantSyncResult, s as SyncOptions, t as SyncResults, d as MigrateOptions, e as MigrationResults, g as MigrationHooks, h as MigrationProgressCallback, i as MigrationErrorHandler, T as TenantMigrationResult, f as TenantMigrationStatus, u as ClonerConfig, v as ClonerDependencies, w as CloneTenantOptions, x as CloneTenantResult, y as SharedMigrateOptions, z as SharedMigrationResult, B as SharedMigrationStatus } from '../migrator-C7FtsZ0H.js';
|
|
2
|
+
export { _ as AnonymizeOptions, $ as AnonymizeRules, a0 as AnonymizeValue, A as AppliedMigration, Y as CloneProgressCallback, Z as CloneProgressStatus, P as ColumnDrift, J as ColumnInfo, R as ConstraintDrift, L as ConstraintInfo, C as CreateTenantOptions, G as DEFAULT_FORMAT, H as DRIZZLE_KIT_FORMAT, D as DropTenantOptions, Q as IndexDrift, K as IndexInfo, M as Migrator, a as MigratorConfig, X as SchemaDriftOptions, W as SchemaDriftStatus, a2 as SharedMigrationHooks, a1 as SharedMigratorConfig, m as SharedSeedFunction, n as SharedSeedResult, U as TableDrift, I as TableFormat, N as TableSchema, O as TenantSchema, V as TenantSchemaDrift, c as createMigrator, E as detectTableFormat, F as getFormatConfig } from '../migrator-C7FtsZ0H.js';
|
|
3
3
|
import * as pg from 'pg';
|
|
4
4
|
import { Pool } from 'pg';
|
|
5
5
|
import { C as Config } from '../types-CGqsPe2Q.js';
|
package/dist/migrator/index.js
CHANGED
|
@@ -151,4 +151,4 @@ import {readdir,readFile}from'fs/promises';import {join,basename}from'path';impo
|
|
|
151
151
|
AND tc.constraint_type = 'FOREIGN KEY'
|
|
152
152
|
AND tc.table_name != ccu.table_name`,[e]),r=new Map,t=new Set(n);for(let c of n)r.set(c,new Set);for(let c of a.rows)t.has(c.table_name)&&t.has(c.foreign_table_name)&&r.get(c.table_name).add(c.foreign_table_name);let i=[],s=new Map,o=[];for(let c of n)s.set(c,0);for(let[c,u]of r)for(let g of u)s.set(g,(s.get(g)??0)+1);for(let[c,u]of s)u===0&&o.push(c);for(;o.length>0;){let c=o.shift();i.push(c);for(let[u,g]of r)if(g.has(c)){g.delete(c);let p=(s.get(u)??0)-1;s.set(u,p),p===0&&o.push(u);}}let l=n.filter(c=>!i.includes(c));return [...i,...l]}async function K(m,e,n,a,r,t){let i=0,s=await be(m,e,a);await m.query("SET session_replication_role = replica");try{for(let o=0;o<s.length;o++){let l=s[o];t?.("copying_data",{table:l,progress:o+1,total:s.length});let c=await Ee(m,e,n,l,r);i+=c;}}finally{await m.query("SET session_replication_role = DEFAULT");}return i}var we="__drizzle_migrations",_=class{constructor(e,n){this.deps=n;this.migrationsTable=e.migrationsTable??we;}migrationsTable;async cloneTenant(e,n,a={}){let r=Date.now(),{includeData:t=false,anonymize:i,excludeTables:s=[],onProgress:o}=a,l=this.deps.schemaNameTemplate(e),c=this.deps.schemaNameTemplate(n),u=[this.migrationsTable,...s],g=null,p=null;try{if(o?.("starting"),!await this.deps.schemaExists(e))return this.createErrorResult(e,n,c,`Source tenant "${e}" does not exist`,r);if(await this.deps.schemaExists(n))return this.createErrorResult(e,n,c,`Target tenant "${n}" already exists`,r);o?.("introspecting"),g=await this.deps.createPool(l);let d=await Y(g,l,u);if(d.length===0)return o?.("creating_schema"),await this.deps.createSchema(n),o?.("completed"),{sourceTenant:e,targetTenant:n,targetSchema:c,success:!0,tables:[],durationMs:Date.now()-r};let f=await Promise.all(d.map(S=>W(g,l,c,S)));await g.end(),g=null,o?.("creating_schema"),await this.deps.createSchema(n),p=await this.deps.createRootPool(),o?.("creating_tables");for(let S of f)await p.query(`SET search_path TO "${c}"; ${S.createDdl}`);o?.("creating_constraints");for(let S of f)for(let C of S.constraintDdls.filter(b=>!b.includes("FOREIGN KEY")))try{await p.query(`SET search_path TO "${c}"; ${C}`);}catch{}o?.("creating_indexes");for(let S of f)for(let C of S.indexDdls)try{await p.query(C);}catch{}let P=0;t&&(o?.("copying_data"),P=await K(p,l,c,d,i?.enabled?i.rules:void 0,o));for(let S of f)for(let C of S.constraintDdls.filter(b=>b.includes("FOREIGN KEY")))try{await p.query(C);}catch{}o?.("completed");let $={sourceTenant:e,targetTenant:n,targetSchema:c,success:!0,tables:d,durationMs:Date.now()-r};return t&&($.rowsCopied=P),$}catch(h){return a.onError?.(h),o?.("failed"),this.createErrorResult(e,n,c,h.message,r)}finally{g&&await g.end().catch(()=>{}),p&&await p.end().catch(()=>{});}}createErrorResult(e,n,a,r,t){return {sourceTenant:e,targetTenant:n,targetSchema:a,success:false,error:r,tables:[],durationMs:Date.now()-t}}};function V(m,e){return new _(m,e)}var De="public",E=class{constructor(e,n){this.config=e;this.deps=n;this.schemaName=e.schemaName??De;}schemaName;async migrate(e={}){let n=Date.now(),a=[],r=await this.deps.createPool();try{e.onProgress?.("starting"),await this.config.hooks?.beforeMigration?.();let t=await this.deps.getOrDetectFormat(r,this.schemaName);await this.deps.ensureMigrationsTable(r,this.schemaName,t);let i=await this.deps.loadMigrations(),s=await this.getAppliedMigrations(r,t),o=new Set(s.map(c=>c.identifier)),l=i.filter(c=>!this.isMigrationApplied(c,o,t));if(e.dryRun)return {schemaName:this.schemaName,success:!0,appliedMigrations:l.map(c=>c.name),durationMs:Date.now()-n,format:t.format};for(let c of l){let u=Date.now();e.onProgress?.("migrating",c.name),await this.applyMigration(r,c,t),await this.config.hooks?.afterMigration?.(c.name,Date.now()-u),a.push(c.name);}return e.onProgress?.("completed"),{schemaName:this.schemaName,success:!0,appliedMigrations:a,durationMs:Date.now()-n,format:t.format}}catch(t){return e.onProgress?.("failed"),{schemaName:this.schemaName,success:false,appliedMigrations:a,error:t.message,durationMs:Date.now()-n}}finally{await r.end();}}async markAsApplied(e={}){let n=Date.now(),a=[],r=await this.deps.createPool();try{e.onProgress?.("starting");let t=await this.deps.getOrDetectFormat(r,this.schemaName);await this.deps.ensureMigrationsTable(r,this.schemaName,t);let i=await this.deps.loadMigrations(),s=await this.getAppliedMigrations(r,t),o=new Set(s.map(c=>c.identifier)),l=i.filter(c=>!this.isMigrationApplied(c,o,t));for(let c of l)e.onProgress?.("migrating",c.name),await this.recordMigration(r,c,t),a.push(c.name);return e.onProgress?.("completed"),{schemaName:this.schemaName,success:!0,appliedMigrations:a,durationMs:Date.now()-n,format:t.format}}catch(t){return e.onProgress?.("failed"),{schemaName:this.schemaName,success:false,appliedMigrations:a,error:t.message,durationMs:Date.now()-n}}finally{await r.end();}}async getStatus(){let e=await this.deps.createPool();try{let n=await this.deps.loadMigrations();if(!await this.deps.migrationsTableExists(e,this.schemaName))return {schemaName:this.schemaName,appliedCount:0,pendingCount:n.length,pendingMigrations:n.map(o=>o.name),status:n.length>0?"behind":"ok",format:null};let r=await this.deps.getOrDetectFormat(e,this.schemaName),t=await this.getAppliedMigrations(e,r),i=new Set(t.map(o=>o.identifier)),s=n.filter(o=>!this.isMigrationApplied(o,i,r));return {schemaName:this.schemaName,appliedCount:t.length,pendingCount:s.length,pendingMigrations:s.map(o=>o.name),status:s.length>0?"behind":"ok",format:r.format}}catch(n){return {schemaName:this.schemaName,appliedCount:0,pendingCount:0,pendingMigrations:[],status:"error",error:n.message,format:null}}finally{await e.end();}}async getAppliedMigrations(e,n){let a=n.columns.identifier,r=n.columns.timestamp;return (await e.query(`SELECT id, "${a}" as identifier, "${r}" as applied_at
|
|
153
153
|
FROM "${this.schemaName}"."${n.tableName}"
|
|
154
|
-
ORDER BY id`)).rows.map(i=>{let s=n.columns.timestampType==="bigint"?new Date(Number(i.applied_at)):new Date(i.applied_at);return {identifier:i.identifier,...n.columns.identifier==="name"?{name:i.identifier}:{hash:i.identifier},appliedAt:s}})}isMigrationApplied(e,n,a){return a.columns.identifier==="name"?n.has(e.name):n.has(e.hash)||n.has(e.name)}async applyMigration(e,n,a){let r=await e.connect();try{await r.query("BEGIN"),await r.query(n.sql);let{identifier:t,timestamp:i,timestampType:s}=a.columns,o=t==="name"?n.name:n.hash,l=s==="bigint"?Date.now():new Date;await r.query(`INSERT INTO "${this.schemaName}"."${a.tableName}" ("${t}", "${i}") VALUES ($1, $2)`,[o,l]),await r.query("COMMIT");}catch(t){throw await r.query("ROLLBACK"),t}finally{r.release();}}async recordMigration(e,n,a){let{identifier:r,timestamp:t,timestampType:i}=a.columns,s=r==="name"?n.name:n.hash,o=i==="bigint"?Date.now():new Date;await e.query(`INSERT INTO "${this.schemaName}"."${a.tableName}" ("${r}", "${t}") VALUES ($1, $2)`,[s,o]);}};function G(m,e){return new E(m,e)}var xe="__drizzle_migrations",te="__drizzle_shared_migrations",F=class{constructor(e,n){this.migratorConfig=n;if(this.migrationsTable=n.migrationsTable??xe,this.schemaManager=new D(e,this.migrationsTable),this.driftDetector=new O(e,this.schemaManager,{migrationsTable:this.migrationsTable,tenantDiscovery:n.tenantDiscovery}),this.seeder=new R({tenantDiscovery:n.tenantDiscovery},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,tenantSchema:e.schemas.tenant}),this.syncManager=new x({tenantDiscovery:n.tenantDiscovery,migrationsFolder:n.migrationsFolder,migrationsTable:this.migrationsTable},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectFormat.bind(this),loadMigrations:this.loadMigrations.bind(this)}),this.migrationExecutor=new T({hooks:n.hooks},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectFormat.bind(this),loadMigrations:this.loadMigrations.bind(this)}),this.batchExecutor=new M({tenantDiscovery:n.tenantDiscovery},this.migrationExecutor,this.loadMigrations.bind(this)),this.cloner=new _({migrationsTable:this.migrationsTable},{createPool:this.schemaManager.createPool.bind(this.schemaManager),createRootPool:this.schemaManager.createRootPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,schemaExists:this.schemaManager.schemaExists.bind(this.schemaManager),createSchema:this.schemaManager.createSchema.bind(this.schemaManager)}),n.sharedMigrationsFolder&&existsSync(n.sharedMigrationsFolder)){let a=n.sharedMigrationsTable??te,r=n.sharedHooks,t={schemaName:"public",migrationsTable:a};(r?.beforeMigration||r?.afterApply)&&(t.hooks={},r.beforeMigration&&(t.hooks.beforeMigration=r.beforeMigration),r.afterApply&&(t.hooks.afterMigration=r.afterApply)),this.sharedMigrationExecutor=new E(t,{createPool:this.schemaManager.createRootPool.bind(this.schemaManager),migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectSharedFormat.bind(this),loadMigrations:this.loadSharedMigrations.bind(this)});}else this.sharedMigrationExecutor=null;e.schemas.shared?this.sharedSeeder=new A({schemaName:"public"},{createPool:this.schemaManager.createRootPool.bind(this.schemaManager),sharedSchema:e.schemas.shared}):this.sharedSeeder=null;}migrationsTable;schemaManager;driftDetector;seeder;syncManager;migrationExecutor;batchExecutor;cloner;sharedMigrationExecutor;sharedSeeder;async migrateAll(e={}){return this.batchExecutor.migrateAll(e)}async migrateTenant(e,n,a={}){return this.migrationExecutor.migrateTenant(e,n,a)}async migrateTenants(e,n={}){return this.batchExecutor.migrateTenants(e,n)}async getStatus(){return this.batchExecutor.getStatus()}async getTenantStatus(e,n){return this.migrationExecutor.getTenantStatus(e,n)}async createTenant(e,n={}){let{migrate:a=true}=n;await this.schemaManager.createSchema(e),a&&await this.migrateTenant(e);}async dropTenant(e,n={}){await this.schemaManager.dropSchema(e,n);}async tenantExists(e){return this.schemaManager.schemaExists(e)}async cloneTenant(e,n,a={}){return this.cloner.cloneTenant(e,n,a)}async markAsApplied(e,n={}){return this.migrationExecutor.markAsApplied(e,n)}async markAllAsApplied(e={}){return this.batchExecutor.markAllAsApplied(e)}async getSyncStatus(){return this.syncManager.getSyncStatus()}async getTenantSyncStatus(e,n){return this.syncManager.getTenantSyncStatus(e,n)}async markMissing(e){return this.syncManager.markMissing(e)}async markAllMissing(e={}){return this.syncManager.markAllMissing(e)}async cleanOrphans(e){return this.syncManager.cleanOrphans(e)}async cleanAllOrphans(e={}){return this.syncManager.cleanAllOrphans(e)}async seedTenant(e,n){return this.seeder.seedTenant(e,n)}async seedAll(e,n={}){return this.seeder.seedAll(e,n)}async seedTenants(e,n,a={}){return this.seeder.seedTenants(e,n,a)}hasSharedSeeding(){return this.sharedSeeder!==null}async seedShared(e){return this.sharedSeeder?this.sharedSeeder.seed(e):{schemaName:"public",success:false,error:"Shared schema not configured. Set schemas.shared in tenant config.",durationMs:0}}async seedAllWithShared(e,n,a={}){let r=await this.seedShared(e),t=await this.seedAll(n,a);return {shared:r,tenants:t}}async loadMigrations(){let e=await readdir(this.migratorConfig.migrationsFolder),n=[];for(let a of e){if(!a.endsWith(".sql"))continue;let r=join(this.migratorConfig.migrationsFolder,a),t=await readFile(r,"utf-8"),i=a.match(/^(\d+)_/),s=i?.[1]?parseInt(i[1],10):0,o=createHash("sha256").update(t).digest("hex");n.push({name:basename(a,".sql"),path:r,sql:t,timestamp:s,hash:o});}return n.sort((a,r)=>a.timestamp-r.timestamp)}async getOrDetectFormat(e,n){let a=this.migratorConfig.tableFormat??"auto";if(a!=="auto")return w(a,this.migrationsTable);let r=await N(e,n,this.migrationsTable);if(r)return r;let t=this.migratorConfig.defaultFormat??"name";return w(t,this.migrationsTable)}async loadSharedMigrations(){if(!this.migratorConfig.sharedMigrationsFolder)return [];let e=await readdir(this.migratorConfig.sharedMigrationsFolder),n=[];for(let a of e){if(!a.endsWith(".sql"))continue;let r=join(this.migratorConfig.sharedMigrationsFolder,a),t=await readFile(r,"utf-8"),i=a.match(/^(\d+)_/),s=i?.[1]?parseInt(i[1],10):0,o=createHash("sha256").update(t).digest("hex");n.push({name:basename(a,".sql"),path:r,sql:t,timestamp:s,hash:o});}return n.sort((a,r)=>a.timestamp-r.timestamp)}async getOrDetectSharedFormat(e,n){let a=this.migratorConfig.sharedMigrationsTable??te,r=this.migratorConfig.tableFormat??"auto";if(r!=="auto")return w(r,a);let t=await N(e,n,a);if(t)return t;let i=this.migratorConfig.defaultFormat??"name";return w(i,a)}hasSharedMigrations(){return this.sharedMigrationExecutor!==null}async migrateShared(e={}){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.migrate(e):{schemaName:"public",success:false,appliedMigrations:[],error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",durationMs:0}}async getSharedStatus(){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.getStatus():{schemaName:"public",appliedCount:0,pendingCount:0,pendingMigrations:[],status:"error",error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",format:null}}async markSharedAsApplied(e={}){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.markAsApplied(e):{schemaName:"public",success:false,appliedMigrations:[],error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",durationMs:0}}async migrateAllWithShared(e={}){let{sharedOptions:n,...a}=e,r=await this.migrateShared(n??{}),t=await this.migrateAll(a);return {shared:r,tenants:t}}async getSchemaDrift(e={}){return this.driftDetector.detectDrift(e)}async getTenantSchemaDrift(e,n,a={}){return this.driftDetector.compareTenant(e,n,a)}async introspectTenantSchema(e,n={}){return this.driftDetector.introspectSchema(e,n)}};function Ce(m,e){return new F(m,e)}export{M as BatchExecutor,_ as Cloner,ne as DEFAULT_FORMAT,ae as DRIZZLE_KIT_FORMAT,T as MigrationExecutor,F as Migrator,D as SchemaManager,R as Seeder,E as SharedMigrationExecutor,x as SyncManager,H as createBatchExecutor,V as createCloner,U as createMigrationExecutor,Ce as createMigrator,ie as createSchemaManager,ce as createSeeder,G as createSharedMigrationExecutor,ue as createSyncManager,N as detectTableFormat,w as getFormatConfig};
|
|
154
|
+
ORDER BY id`)).rows.map(i=>{let s=n.columns.timestampType==="bigint"?new Date(Number(i.applied_at)):new Date(i.applied_at);return {identifier:i.identifier,...n.columns.identifier==="name"?{name:i.identifier}:{hash:i.identifier},appliedAt:s}})}isMigrationApplied(e,n,a){return a.columns.identifier==="name"?n.has(e.name):n.has(e.hash)||n.has(e.name)}async applyMigration(e,n,a){let r=await e.connect();try{await r.query("BEGIN"),await r.query(n.sql);let{identifier:t,timestamp:i,timestampType:s}=a.columns,o=t==="name"?n.name:n.hash,l=s==="bigint"?Date.now():new Date;await r.query(`INSERT INTO "${this.schemaName}"."${a.tableName}" ("${t}", "${i}") VALUES ($1, $2)`,[o,l]),await r.query("COMMIT");}catch(t){throw await r.query("ROLLBACK"),t}finally{r.release();}}async recordMigration(e,n,a){let{identifier:r,timestamp:t,timestampType:i}=a.columns,s=r==="name"?n.name:n.hash,o=i==="bigint"?Date.now():new Date;await e.query(`INSERT INTO "${this.schemaName}"."${a.tableName}" ("${r}", "${t}") VALUES ($1, $2)`,[s,o]);}};function G(m,e){return new E(m,e)}var xe="__drizzle_migrations",te="__drizzle_shared_migrations",F=class{constructor(e,n){this.migratorConfig=n;if(this.migrationsTable=n.migrationsTable??xe,this.schemaManager=new D(e,this.migrationsTable),this.driftDetector=new O(e,this.schemaManager,{migrationsTable:this.migrationsTable,tenantDiscovery:n.tenantDiscovery}),this.seeder=new R({tenantDiscovery:n.tenantDiscovery},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,tenantSchema:e.schemas.tenant}),this.syncManager=new x({tenantDiscovery:n.tenantDiscovery,migrationsFolder:n.migrationsFolder,migrationsTable:this.migrationsTable},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectFormat.bind(this),loadMigrations:this.loadMigrations.bind(this)}),this.migrationExecutor=new T({hooks:n.hooks},{createPool:this.schemaManager.createPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectFormat.bind(this),loadMigrations:this.loadMigrations.bind(this)}),this.batchExecutor=new M({tenantDiscovery:n.tenantDiscovery},this.migrationExecutor,this.loadMigrations.bind(this)),this.cloner=new _({migrationsTable:this.migrationsTable},{createPool:this.schemaManager.createPool.bind(this.schemaManager),createRootPool:this.schemaManager.createRootPool.bind(this.schemaManager),schemaNameTemplate:e.isolation.schemaNameTemplate,schemaExists:this.schemaManager.schemaExists.bind(this.schemaManager),createSchema:this.schemaManager.createSchema.bind(this.schemaManager)}),n.sharedMigrationsFolder&&existsSync(n.sharedMigrationsFolder)){let a=n.sharedMigrationsTable??te,r=n.sharedHooks,t={schemaName:"public",migrationsTable:a};(r?.beforeMigration||r?.afterApply)&&(t.hooks={},r.beforeMigration&&(t.hooks.beforeMigration=r.beforeMigration),r.afterApply&&(t.hooks.afterMigration=r.afterApply)),this.sharedMigrationExecutor=new E(t,{createPool:this.schemaManager.createRootPool.bind(this.schemaManager),migrationsTableExists:this.schemaManager.migrationsTableExists.bind(this.schemaManager),ensureMigrationsTable:this.schemaManager.ensureMigrationsTable.bind(this.schemaManager),getOrDetectFormat:this.getOrDetectSharedFormat.bind(this),loadMigrations:this.loadSharedMigrations.bind(this)});}else this.sharedMigrationExecutor=null;e.schemas.shared?this.sharedSeeder=new A({schemaName:"public"},{createPool:this.schemaManager.createRootPool.bind(this.schemaManager),sharedSchema:e.schemas.shared}):this.sharedSeeder=null;}migrationsTable;schemaManager;driftDetector;seeder;syncManager;migrationExecutor;batchExecutor;cloner;sharedMigrationExecutor;sharedSeeder;async migrateAll(e={}){return this.batchExecutor.migrateAll(e)}async migrateTenant(e,n,a={}){return this.migrationExecutor.migrateTenant(e,n,a)}async migrateTenants(e,n={}){return this.batchExecutor.migrateTenants(e,n)}async getStatus(){return this.batchExecutor.getStatus()}async getTenantStatus(e,n){return this.migrationExecutor.getTenantStatus(e,n)}async createTenant(e,n={}){let{migrate:a=true}=n;await this.schemaManager.createSchema(e),a&&await this.migrateTenant(e);}async dropTenant(e,n={}){await this.schemaManager.dropSchema(e,n);}async tenantExists(e){return this.schemaManager.schemaExists(e)}async cloneTenant(e,n,a={}){return this.cloner.cloneTenant(e,n,a)}async markAsApplied(e,n={}){return this.migrationExecutor.markAsApplied(e,n)}async markAllAsApplied(e={}){return this.batchExecutor.markAllAsApplied(e)}async getSyncStatus(){return this.syncManager.getSyncStatus()}async getTenantSyncStatus(e,n){return this.syncManager.getTenantSyncStatus(e,n)}async markMissing(e){return this.syncManager.markMissing(e)}async markAllMissing(e={}){return this.syncManager.markAllMissing(e)}async cleanOrphans(e){return this.syncManager.cleanOrphans(e)}async cleanAllOrphans(e={}){return this.syncManager.cleanAllOrphans(e)}async seedTenant(e,n){return this.seeder.seedTenant(e,n)}async seedAll(e,n={}){return this.seeder.seedAll(e,n)}async seedTenants(e,n,a={}){return this.seeder.seedTenants(e,n,a)}hasSharedSeeding(){return this.sharedSeeder!==null}async seedShared(e){return this.sharedSeeder?this.sharedSeeder.seed(e):{schemaName:"public",success:false,error:"Shared schema not configured. Set schemas.shared in tenant config.",durationMs:0}}async seedAllWithShared(e,n,a={}){let r=await this.seedShared(e),t=await this.seedAll(n,a);return {shared:r,tenants:t}}async loadMigrations(){let e=await readdir(this.migratorConfig.migrationsFolder),n=[];for(let a of e){if(!a.endsWith(".sql"))continue;let r=join(this.migratorConfig.migrationsFolder,a),t=await readFile(r,"utf-8"),i=a.match(/^(\d+)_/),s=i?.[1]?parseInt(i[1],10):0,o=createHash("sha256").update(t).digest("hex");n.push({name:basename(a,".sql"),path:r,sql:t,timestamp:s,hash:o});}return n.sort((a,r)=>a.timestamp-r.timestamp)}async getOrDetectFormat(e,n){let a=this.migratorConfig.tableFormat??"auto";if(a!=="auto")return w(a,this.migrationsTable);let r=await N(e,n,this.migrationsTable);if(r)return r;let t=this.migratorConfig.defaultFormat??"name";return w(t,this.migrationsTable)}async loadSharedMigrations(){if(!this.migratorConfig.sharedMigrationsFolder)return [];let e=await readdir(this.migratorConfig.sharedMigrationsFolder),n=[];for(let a of e){if(!a.endsWith(".sql"))continue;let r=join(this.migratorConfig.sharedMigrationsFolder,a),t=await readFile(r,"utf-8"),i=a.match(/^(\d+)_/),s=i?.[1]?parseInt(i[1],10):0,o=createHash("sha256").update(t).digest("hex");n.push({name:basename(a,".sql"),path:r,sql:t,timestamp:s,hash:o});}return n.sort((a,r)=>a.timestamp-r.timestamp)}async getOrDetectSharedFormat(e,n){let a=this.migratorConfig.sharedMigrationsTable??te,r=this.migratorConfig.sharedTableFormat??this.migratorConfig.tableFormat??"auto";if(r!=="auto")return w(r,a);let t=await N(e,n,a);if(t)return t;let i=this.migratorConfig.sharedDefaultFormat??this.migratorConfig.defaultFormat??"name";return w(i,a)}hasSharedMigrations(){return this.sharedMigrationExecutor!==null}async migrateShared(e={}){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.migrate(e):{schemaName:"public",success:false,appliedMigrations:[],error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",durationMs:0}}async getSharedStatus(){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.getStatus():{schemaName:"public",appliedCount:0,pendingCount:0,pendingMigrations:[],status:"error",error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",format:null}}async markSharedAsApplied(e={}){return this.sharedMigrationExecutor?this.sharedMigrationExecutor.markAsApplied(e):{schemaName:"public",success:false,appliedMigrations:[],error:"Shared migrations not configured. Set sharedMigrationsFolder in migrator config.",durationMs:0}}async migrateAllWithShared(e={}){let{sharedOptions:n,...a}=e,r=await this.migrateShared(n??{}),t=await this.migrateAll(a);return {shared:r,tenants:t}}async getSchemaDrift(e={}){return this.driftDetector.detectDrift(e)}async getTenantSchemaDrift(e,n,a={}){return this.driftDetector.compareTenant(e,n,a)}async introspectTenantSchema(e,n={}){return this.driftDetector.introspectSchema(e,n)}};function Ce(m,e){return new F(m,e)}export{M as BatchExecutor,_ as Cloner,ne as DEFAULT_FORMAT,ae as DRIZZLE_KIT_FORMAT,T as MigrationExecutor,F as Migrator,D as SchemaManager,R as Seeder,E as SharedMigrationExecutor,x as SyncManager,H as createBatchExecutor,V as createCloner,U as createMigrationExecutor,Ce as createMigrator,ie as createSchemaManager,ce as createSeeder,G as createSharedMigrationExecutor,ue as createSyncManager,N as detectTableFormat,w as getFormatConfig};
|
|
@@ -319,6 +319,21 @@ interface MigratorConfig {
|
|
|
319
319
|
* Hooks for shared schema migrations
|
|
320
320
|
*/
|
|
321
321
|
sharedHooks?: SharedMigrationHooks;
|
|
322
|
+
/**
|
|
323
|
+
* Table format for tracking shared schema migrations
|
|
324
|
+
* Independent from tenant tableFormat, allowing different formats per schema type
|
|
325
|
+
* - "auto": Auto-detect existing format, use sharedDefaultFormat for new tables
|
|
326
|
+
* - "name": Use filename (drizzle-multitenant native)
|
|
327
|
+
* - "hash": Use SHA-256 hash
|
|
328
|
+
* - "drizzle-kit": Exact drizzle-kit format (hash + bigint timestamp)
|
|
329
|
+
* @default "auto"
|
|
330
|
+
*/
|
|
331
|
+
sharedTableFormat?: 'auto' | TableFormat;
|
|
332
|
+
/**
|
|
333
|
+
* When using "auto" for sharedTableFormat and no table exists, which format to create
|
|
334
|
+
* @default "name"
|
|
335
|
+
*/
|
|
336
|
+
sharedDefaultFormat?: TableFormat;
|
|
322
337
|
}
|
|
323
338
|
/**
|
|
324
339
|
* Migrate options
|
|
@@ -963,6 +978,9 @@ declare class Migrator<TTenantSchema extends Record<string, unknown>, TSharedSch
|
|
|
963
978
|
private loadSharedMigrations;
|
|
964
979
|
/**
|
|
965
980
|
* Get or detect the format for the shared schema
|
|
981
|
+
*
|
|
982
|
+
* Uses sharedTableFormat/sharedDefaultFormat if configured,
|
|
983
|
+
* otherwise falls back to tableFormat/defaultFormat for backwards compatibility.
|
|
966
984
|
*/
|
|
967
985
|
private getOrDetectSharedFormat;
|
|
968
986
|
/**
|
package/package.json
CHANGED