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.
- package/README.md +28 -8
- package/dist/cli/index.js +1809 -5949
- package/dist/{context-Vki959ri.d.ts → context-BBLPNjmk.d.ts} +1 -1
- package/dist/cross-schema/index.js +1 -426
- package/dist/export/index.d.ts +395 -0
- package/dist/export/index.js +9 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +34 -4745
- package/dist/integrations/express.d.ts +3 -3
- package/dist/integrations/express.js +1 -110
- package/dist/integrations/fastify.d.ts +3 -3
- package/dist/integrations/fastify.js +1 -236
- package/dist/integrations/hono.js +0 -3
- package/dist/integrations/nestjs/index.d.ts +1 -1
- package/dist/integrations/nestjs/index.js +3 -11006
- package/dist/lint/index.d.ts +475 -0
- package/dist/lint/index.js +5 -0
- package/dist/metrics/index.d.ts +530 -0
- package/dist/metrics/index.js +3 -0
- package/dist/migrator/index.d.ts +116 -4
- package/dist/migrator/index.js +34 -2990
- package/dist/{migrator-BDgFzSh8.d.ts → migrator-C7FtsZ0H.d.ts} +263 -2
- package/dist/scaffold/index.d.ts +330 -0
- package/dist/scaffold/index.js +277 -0
- package/dist/{types-BhK96FPC.d.ts → types-CGqsPe2Q.d.ts} +49 -1
- package/package.json +18 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cross-schema/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/integrations/express.js.map +0 -1
- package/dist/integrations/fastify.js.map +0 -1
- package/dist/integrations/hono.js.map +0 -1
- package/dist/integrations/nestjs/index.js.map +0 -1
- package/dist/migrator/index.js.map +0 -1
|
@@ -1,426 +1 @@
|
|
|
1
|
-
import { sql, getTableName } from
|
|
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};
|