drizzle-multitenant 1.2.0 → 1.3.1

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.
@@ -1,4 +1,4 @@
1
- import { T as TenantManager, a as TenantDb, S as SharedDb } from './types-BhK96FPC.js';
1
+ import { T as TenantManager, a as TenantDb, S as SharedDb } from './types-CGqsPe2Q.js';
2
2
 
3
3
  /**
4
4
  * Base tenant context data
@@ -1,426 +1 @@
1
- import { sql, getTableName } from 'drizzle-orm';
2
-
3
- // src/cross-schema/cross-schema.ts
4
- var CrossSchemaQueryBuilder = class {
5
- constructor(context) {
6
- this.context = context;
7
- }
8
- fromTable = null;
9
- joins = [];
10
- selectFields = {};
11
- whereCondition = null;
12
- orderByFields = [];
13
- limitValue = null;
14
- offsetValue = null;
15
- /**
16
- * Set the main table to query from
17
- */
18
- from(source, table) {
19
- const schemaName = this.getSchemaName(source);
20
- this.fromTable = { table, source, schemaName };
21
- return this;
22
- }
23
- /**
24
- * Add an inner join
25
- */
26
- innerJoin(source, table, condition) {
27
- return this.addJoin(source, table, condition, "inner");
28
- }
29
- /**
30
- * Add a left join
31
- */
32
- leftJoin(source, table, condition) {
33
- return this.addJoin(source, table, condition, "left");
34
- }
35
- /**
36
- * Add a right join
37
- */
38
- rightJoin(source, table, condition) {
39
- return this.addJoin(source, table, condition, "right");
40
- }
41
- /**
42
- * Add a full outer join
43
- */
44
- fullJoin(source, table, condition) {
45
- return this.addJoin(source, table, condition, "full");
46
- }
47
- /**
48
- * Select specific fields
49
- */
50
- select(fields) {
51
- this.selectFields = fields;
52
- return this;
53
- }
54
- /**
55
- * Add a where condition
56
- */
57
- where(condition) {
58
- this.whereCondition = condition;
59
- return this;
60
- }
61
- /**
62
- * Add order by
63
- */
64
- orderBy(...fields) {
65
- this.orderByFields = fields;
66
- return this;
67
- }
68
- /**
69
- * Set limit
70
- */
71
- limit(value) {
72
- this.limitValue = value;
73
- return this;
74
- }
75
- /**
76
- * Set offset
77
- */
78
- offset(value) {
79
- this.offsetValue = value;
80
- return this;
81
- }
82
- /**
83
- * Execute the query and return typed results
84
- */
85
- async execute() {
86
- if (!this.fromTable) {
87
- throw new Error("[drizzle-multitenant] No table specified. Use .from() first.");
88
- }
89
- const sqlQuery = this.buildSql();
90
- const result = await this.context.tenantDb.execute(sqlQuery);
91
- return result.rows;
92
- }
93
- /**
94
- * Build the SQL query
95
- */
96
- buildSql() {
97
- if (!this.fromTable) {
98
- throw new Error("[drizzle-multitenant] No table specified");
99
- }
100
- const parts = [];
101
- const selectParts = Object.entries(this.selectFields).map(([alias, column]) => {
102
- const columnName = column.name;
103
- return sql`${sql.raw(`"${columnName}"`)} as ${sql.raw(`"${alias}"`)}`;
104
- });
105
- if (selectParts.length === 0) {
106
- parts.push(sql`SELECT *`);
107
- } else {
108
- parts.push(sql`SELECT ${sql.join(selectParts, sql`, `)}`);
109
- }
110
- const fromTableRef = this.getFullTableName(this.fromTable.schemaName, this.fromTable.table);
111
- parts.push(sql` FROM ${sql.raw(fromTableRef)}`);
112
- for (const join of this.joins) {
113
- const joinTableRef = this.getFullTableName(join.schemaName, join.table);
114
- const joinType = this.getJoinKeyword(join.type);
115
- parts.push(sql` ${sql.raw(joinType)} ${sql.raw(joinTableRef)} ON ${join.condition}`);
116
- }
117
- if (this.whereCondition) {
118
- parts.push(sql` WHERE ${this.whereCondition}`);
119
- }
120
- if (this.orderByFields.length > 0) {
121
- parts.push(sql` ORDER BY ${sql.join(this.orderByFields, sql`, `)}`);
122
- }
123
- if (this.limitValue !== null) {
124
- parts.push(sql` LIMIT ${sql.raw(this.limitValue.toString())}`);
125
- }
126
- if (this.offsetValue !== null) {
127
- parts.push(sql` OFFSET ${sql.raw(this.offsetValue.toString())}`);
128
- }
129
- return sql.join(parts, sql``);
130
- }
131
- /**
132
- * Add a join to the query
133
- */
134
- addJoin(source, table, condition, type) {
135
- const schemaName = this.getSchemaName(source);
136
- this.joins.push({ table, source, schemaName, condition, type });
137
- return this;
138
- }
139
- /**
140
- * Get schema name for a source
141
- */
142
- getSchemaName(source) {
143
- if (source === "tenant") {
144
- return this.context.tenantSchema ?? "tenant";
145
- }
146
- return this.context.sharedSchema ?? "public";
147
- }
148
- /**
149
- * Get fully qualified table name
150
- */
151
- getFullTableName(schemaName, table) {
152
- const tableName = getTableName(table);
153
- return `"${schemaName}"."${tableName}"`;
154
- }
155
- /**
156
- * Get SQL keyword for join type
157
- */
158
- getJoinKeyword(type) {
159
- switch (type) {
160
- case "inner":
161
- return "INNER JOIN";
162
- case "left":
163
- return "LEFT JOIN";
164
- case "right":
165
- return "RIGHT JOIN";
166
- case "full":
167
- return "FULL OUTER JOIN";
168
- }
169
- }
170
- };
171
- function createCrossSchemaQuery(context) {
172
- return new CrossSchemaQueryBuilder(context);
173
- }
174
- async function withSharedLookup(config) {
175
- const {
176
- tenantDb,
177
- tenantTable,
178
- sharedTable,
179
- foreignKey,
180
- sharedKey = "id",
181
- sharedFields,
182
- where: whereCondition
183
- } = config;
184
- const tenantTableName = getTableName(tenantTable);
185
- const sharedTableName = getTableName(sharedTable);
186
- const sharedFieldList = sharedFields.map((field) => `s."${String(field)}"`).join(", ");
187
- const queryParts = [
188
- `SELECT t.*, ${sharedFieldList}`,
189
- `FROM "${tenantTableName}" t`,
190
- `LEFT JOIN "public"."${sharedTableName}" s ON t."${String(foreignKey)}" = s."${String(sharedKey)}"`
191
- ];
192
- if (whereCondition) {
193
- queryParts.push("WHERE");
194
- }
195
- const sqlQuery = sql.raw(queryParts.join(" "));
196
- const result = await tenantDb.execute(sqlQuery);
197
- return result.rows;
198
- }
199
- async function crossSchemaRaw(db, options) {
200
- const { tenantSchema, sharedSchema, sql: rawSql } = options;
201
- const processedSql = rawSql.replace(/\$tenant\./g, `"${tenantSchema}".`).replace(/\$shared\./g, `"${sharedSchema}".`);
202
- const query = sql.raw(processedSql);
203
- const result = await db.execute(query);
204
- return result.rows;
205
- }
206
- function buildCrossSchemaSelect(fields, tenantSchema, _sharedSchema) {
207
- const columns = Object.entries(fields).map(([alias, column]) => {
208
- const columnName = column.name;
209
- return `"${columnName}" as "${alias}"`;
210
- });
211
- const getSchema = () => {
212
- return tenantSchema;
213
- };
214
- return { columns, getSchema };
215
- }
216
- function extractTablesFromSchema(schema) {
217
- const tables = /* @__PURE__ */ new Set();
218
- for (const value of Object.values(schema)) {
219
- if (value && typeof value === "object" && "_" in value) {
220
- const branded = value;
221
- if (branded._?.brand === "Table") {
222
- tables.add(value);
223
- }
224
- }
225
- }
226
- return tables;
227
- }
228
- function isSharedTable(table, sharedTables) {
229
- return sharedTables.has(table);
230
- }
231
- var WithSharedQueryBuilder = class {
232
- constructor(tenantDb, sharedTables, tenantSchemaName, sharedSchemaName = "public") {
233
- this.tenantDb = tenantDb;
234
- this.sharedTables = sharedTables;
235
- this.tenantSchemaName = tenantSchemaName;
236
- this.sharedSchemaName = sharedSchemaName;
237
- }
238
- fromTable = null;
239
- joins = [];
240
- selectFields = {};
241
- whereCondition = null;
242
- orderByFields = [];
243
- limitValue = null;
244
- offsetValue = null;
245
- /**
246
- * Set the main table to query from
247
- * Automatically detects if it's a tenant or shared table
248
- */
249
- from(table) {
250
- const isShared = isSharedTable(table, this.sharedTables);
251
- this.fromTable = {
252
- table,
253
- isShared,
254
- schemaName: isShared ? this.sharedSchemaName : this.tenantSchemaName
255
- };
256
- return this;
257
- }
258
- /**
259
- * Add a left join with automatic schema detection
260
- */
261
- leftJoin(table, condition) {
262
- return this.addJoin(table, condition, "left");
263
- }
264
- /**
265
- * Add an inner join with automatic schema detection
266
- */
267
- innerJoin(table, condition) {
268
- return this.addJoin(table, condition, "inner");
269
- }
270
- /**
271
- * Add a right join with automatic schema detection
272
- */
273
- rightJoin(table, condition) {
274
- return this.addJoin(table, condition, "right");
275
- }
276
- /**
277
- * Add a full outer join with automatic schema detection
278
- */
279
- fullJoin(table, condition) {
280
- return this.addJoin(table, condition, "full");
281
- }
282
- /**
283
- * Select specific fields
284
- */
285
- select(fields) {
286
- this.selectFields = fields;
287
- return this;
288
- }
289
- /**
290
- * Add a WHERE condition
291
- */
292
- where(condition) {
293
- this.whereCondition = condition;
294
- return this;
295
- }
296
- /**
297
- * Add ORDER BY
298
- */
299
- orderBy(...fields) {
300
- this.orderByFields = fields;
301
- return this;
302
- }
303
- /**
304
- * Set LIMIT
305
- */
306
- limit(value) {
307
- this.limitValue = value;
308
- return this;
309
- }
310
- /**
311
- * Set OFFSET
312
- */
313
- offset(value) {
314
- this.offsetValue = value;
315
- return this;
316
- }
317
- /**
318
- * Execute the query and return typed results
319
- */
320
- async execute() {
321
- if (!this.fromTable) {
322
- throw new Error("[drizzle-multitenant] No table specified. Use .from() first.");
323
- }
324
- const sqlQuery = this.buildSql();
325
- const result = await this.tenantDb.execute(sqlQuery);
326
- return result.rows;
327
- }
328
- /**
329
- * Add a join to the query
330
- */
331
- addJoin(table, condition, type) {
332
- const isShared = isSharedTable(table, this.sharedTables);
333
- this.joins.push({
334
- table,
335
- isShared,
336
- schemaName: isShared ? this.sharedSchemaName : this.tenantSchemaName,
337
- condition,
338
- type
339
- });
340
- return this;
341
- }
342
- /**
343
- * Build the SQL query
344
- */
345
- buildSql() {
346
- if (!this.fromTable) {
347
- throw new Error("[drizzle-multitenant] No table specified");
348
- }
349
- const parts = [];
350
- const selectParts = Object.entries(this.selectFields).map(([alias, column]) => {
351
- const columnName = column.name;
352
- const tableName = this.getTableAliasForColumn(column);
353
- if (tableName) {
354
- return sql`${sql.raw(`"${tableName}"."${columnName}"`)} as ${sql.raw(`"${alias}"`)}`;
355
- }
356
- return sql`${sql.raw(`"${columnName}"`)} as ${sql.raw(`"${alias}"`)}`;
357
- });
358
- if (selectParts.length === 0) {
359
- parts.push(sql`SELECT *`);
360
- } else {
361
- parts.push(sql`SELECT ${sql.join(selectParts, sql`, `)}`);
362
- }
363
- const fromTableName = getTableName(this.fromTable.table);
364
- const fromTableRef = `"${this.fromTable.schemaName}"."${fromTableName}"`;
365
- parts.push(sql` FROM ${sql.raw(fromTableRef)} "${sql.raw(fromTableName)}"`);
366
- for (const join of this.joins) {
367
- const joinTableName = getTableName(join.table);
368
- const joinTableRef = `"${join.schemaName}"."${joinTableName}"`;
369
- const joinKeyword = this.getJoinKeyword(join.type);
370
- parts.push(
371
- sql` ${sql.raw(joinKeyword)} ${sql.raw(joinTableRef)} "${sql.raw(joinTableName)}" ON ${join.condition}`
372
- );
373
- }
374
- if (this.whereCondition) {
375
- parts.push(sql` WHERE ${this.whereCondition}`);
376
- }
377
- if (this.orderByFields.length > 0) {
378
- parts.push(sql` ORDER BY ${sql.join(this.orderByFields, sql`, `)}`);
379
- }
380
- if (this.limitValue !== null) {
381
- parts.push(sql` LIMIT ${sql.raw(this.limitValue.toString())}`);
382
- }
383
- if (this.offsetValue !== null) {
384
- parts.push(sql` OFFSET ${sql.raw(this.offsetValue.toString())}`);
385
- }
386
- return sql.join(parts, sql``);
387
- }
388
- /**
389
- * Get table alias for a column (used in SELECT)
390
- */
391
- getTableAliasForColumn(column) {
392
- const columnTable = column.table;
393
- if (columnTable) {
394
- return getTableName(columnTable);
395
- }
396
- return null;
397
- }
398
- /**
399
- * Get SQL keyword for join type
400
- */
401
- getJoinKeyword(type) {
402
- switch (type) {
403
- case "inner":
404
- return "INNER JOIN";
405
- case "left":
406
- return "LEFT JOIN";
407
- case "right":
408
- return "RIGHT JOIN";
409
- case "full":
410
- return "FULL OUTER JOIN";
411
- }
412
- }
413
- };
414
- function withShared(tenantDb, _sharedDb, schemas, options) {
415
- const sharedTables = extractTablesFromSchema(schemas.shared);
416
- return new WithSharedQueryBuilder(
417
- tenantDb,
418
- sharedTables,
419
- options?.tenantSchema ?? "tenant",
420
- options?.sharedSchema ?? "public"
421
- );
422
- }
423
-
424
- export { CrossSchemaQueryBuilder, WithSharedQueryBuilder, buildCrossSchemaSelect, createCrossSchemaQuery, crossSchemaRaw, withShared, withSharedLookup };
425
- //# sourceMappingURL=index.js.map
426
- //# sourceMappingURL=index.js.map
1
+ import {sql,getTableName}from'drizzle-orm';var c=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(([s,a])=>{let l=a.name;return sql`${sql.raw(`"${l}"`)} as ${sql.raw(`"${s}"`)}`});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 s of this.joins){let a=this.getFullTableName(s.schemaName,s.table),l=this.getJoinKeyword(s.type);e.push(sql` ${sql.raw(l)} ${sql.raw(a)} ON ${s.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,s){let a=this.getSchemaName(e);return this.joins.push({table:t,source:e,schemaName:a,condition:n,type:s}),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 g(o){return new c(o)}async function y(o){let{tenantDb:e,tenantTable:t,sharedTable:n,foreignKey:s,sharedKey:a="id",sharedFields:l,where:h}=o,u=getTableName(t),f=getTableName(n),S=[`SELECT t.*, ${l.map(w=>`s."${String(w)}"`).join(", ")}`,`FROM "${u}" t`,`LEFT JOIN "public"."${f}" s ON t."${String(s)}" = s."${String(a)}"`];h&&S.push("WHERE");let p=sql.raw(S.join(" "));return (await e.execute(p)).rows}async function R(o,e){let{tenantSchema:t,sharedSchema:n,sql:s}=e,a=s.replace(/\$tenant\./g,`"${t}".`).replace(/\$shared\./g,`"${n}".`),l=sql.raw(a);return (await o.execute(l)).rows}function C(o,e,t){return {columns:Object.entries(o).map(([a,l])=>`"${l.name}" as "${a}"`),getSchema:()=>e}}function N(o){let e=new Set;for(let t of Object.values(o))t&&typeof t=="object"&&"_"in t&&t._?.brand==="Table"&&e.add(t);return e}function b(o,e){return e.has(o)}var d=class{constructor(e,t,n,s="public"){this.tenantDb=e;this.sharedTables=t;this.tenantSchemaName=n;this.sharedSchemaName=s;}fromTable=null;joins=[];selectFields={};whereCondition=null;orderByFields=[];limitValue=null;offsetValue=null;from(e){let t=b(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 s=b(e,this.sharedTables);return this.joins.push({table:e,isShared:s,schemaName:s?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(([a,l])=>{let h=l.name,u=this.getTableAliasForColumn(l);return u?sql`${sql.raw(`"${u}"."${h}"`)} as ${sql.raw(`"${a}"`)}`:sql`${sql.raw(`"${h}"`)} as ${sql.raw(`"${a}"`)}`});t.length===0?e.push(sql`SELECT *`):e.push(sql`SELECT ${sql.join(t,sql`, `)}`);let n=getTableName(this.fromTable.table),s=`"${this.fromTable.schemaName}"."${n}"`;e.push(sql` FROM ${sql.raw(s)} "${sql.raw(n)}"`);for(let a of this.joins){let l=getTableName(a.table),h=`"${a.schemaName}"."${l}"`,u=this.getJoinKeyword(a.type);e.push(sql` ${sql.raw(u)} ${sql.raw(h)} "${sql.raw(l)}" 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``)}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 J(o,e,t,n){let s=N(t.shared);return new d(o,s,n?.tenantSchema??"tenant",n?.sharedSchema??"public")}export{c as CrossSchemaQueryBuilder,d as WithSharedQueryBuilder,C as buildCrossSchemaSelect,g as createCrossSchemaQuery,R as crossSchemaRaw,J as withShared,y as withSharedLookup};