vsrepo 2.5.0 → 2.7.0

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +611 -531
  2. package/LICENSE +20 -20
  3. package/README.md +221 -1243
  4. package/README.pt-BR.md +221 -1246
  5. package/dist/VSRepoAdapter.d.ts +12 -0
  6. package/dist/VSRepoAdapter.js.map +1 -1
  7. package/dist/VSRepository.d.ts +93 -5
  8. package/dist/VSRepository.js +116 -35
  9. package/dist/VSRepository.js.map +1 -1
  10. package/dist/decorators/dynamic-method.decorator.d.ts +1 -1
  11. package/dist/decorators/dynamic-method.decorator.js +2 -4
  12. package/dist/decorators/dynamic-method.decorator.js.map +1 -1
  13. package/dist/decorators/query-method.decorator.d.ts +3 -24
  14. package/dist/decorators/query-method.decorator.js +4 -27
  15. package/dist/decorators/query-method.decorator.js.map +1 -1
  16. package/dist/index.d.ts +5 -0
  17. package/dist/index.js +7 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/internal/enums/vsrepo-error-type.enum.d.ts +3 -1
  20. package/dist/internal/enums/vsrepo-error-type.enum.js +2 -0
  21. package/dist/internal/enums/vsrepo-error-type.enum.js.map +1 -1
  22. package/dist/internal/resolvers/dynamic-methods.resolver.d.ts +7 -1
  23. package/dist/internal/resolvers/dynamic-methods.resolver.js +191 -112
  24. package/dist/internal/resolvers/dynamic-methods.resolver.js.map +1 -1
  25. package/dist/internal/utils/vs-logger.util.js.map +1 -1
  26. package/dist/internal/utils/vs-placeholder-parser.util.d.ts +2 -0
  27. package/dist/internal/utils/vs-placeholder-parser.util.js +62 -0
  28. package/dist/internal/utils/vs-placeholder-parser.util.js.map +1 -0
  29. package/dist/internal/utils/vs-query-builder.util.d.ts +239 -0
  30. package/dist/internal/utils/vs-query-builder.util.js +401 -0
  31. package/dist/internal/utils/vs-query-builder.util.js.map +1 -0
  32. package/dist/internal/utils/vs-raw-query-builder.util.d.ts +238 -0
  33. package/dist/internal/utils/vs-raw-query-builder.util.js +433 -0
  34. package/dist/internal/utils/vs-raw-query-builder.util.js.map +1 -0
  35. package/dist/internal/utils/vs-sql.util.d.ts +100 -0
  36. package/dist/internal/utils/vs-sql.util.js +151 -0
  37. package/dist/internal/utils/vs-sql.util.js.map +1 -0
  38. package/dist/internal/utils/with-db.util.js.map +1 -1
  39. package/dist/internal/validators/decorators.validator.js +3 -7
  40. package/dist/internal/validators/decorators.validator.js.map +1 -1
  41. package/dist/internal/validators/schemas/pagination.schema.d.ts +2 -2
  42. package/dist/internal/validators/schemas/pagination.schema.js +2 -2
  43. package/dist/internal/validators/schemas/pagination.schema.js.map +1 -1
  44. package/dist/internal/validators/schemas/relations.schema.d.ts +4 -0
  45. package/dist/internal/validators/schemas/relations.schema.js +39 -0
  46. package/dist/internal/validators/schemas/relations.schema.js.map +1 -0
  47. package/dist/internal/validators/schemas/see-mode.schema.d.ts +3 -0
  48. package/dist/internal/validators/schemas/see-mode.schema.js +38 -0
  49. package/dist/internal/validators/schemas/see-mode.schema.js.map +1 -0
  50. package/dist/internal/validators/schemas/select.schema.d.ts +4 -0
  51. package/dist/internal/validators/schemas/select.schema.js +39 -0
  52. package/dist/internal/validators/schemas/select.schema.js.map +1 -0
  53. package/dist/internal/validators/vsrepo.validator.js +7 -5
  54. package/dist/internal/validators/vsrepo.validator.js.map +1 -1
  55. package/dist/types/dynamic-methods/dynamic-method-info.type.d.ts +1 -0
  56. package/dist/types/utils/query-args.type.d.ts +1 -4
  57. package/dist/types/vsrepo/vs-raw-query-builder-cte-query.type.d.ts +8 -0
  58. package/dist/types/vsrepo/vs-raw-query-builder-cte-query.type.js +3 -0
  59. package/dist/types/vsrepo/vs-raw-query-builder-cte-query.type.js.map +1 -0
  60. package/dist/types/vsrepo/vs-raw-query-builder-target.type.d.ts +7 -0
  61. package/dist/types/vsrepo/vs-raw-query-builder-target.type.js +3 -0
  62. package/dist/types/vsrepo/vs-raw-query-builder-target.type.js.map +1 -0
  63. package/dist/types/vsrepo/vsrepo-options.type.d.ts +27 -0
  64. package/package.json +88 -80
@@ -0,0 +1,401 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.VSQueryBuilder = void 0;
40
+ const VSRepoError_1 = require("../../errors/VSRepoError");
41
+ const vsrepo_error_type_enum_1 = require("../enums/vsrepo-error-type.enum");
42
+ const ordering_schema_1 = __importDefault(require("../validators/schemas/ordering.schema"));
43
+ const relations_schema_1 = __importDefault(require("../validators/schemas/relations.schema"));
44
+ const see_mode_schema_1 = __importDefault(require("../validators/schemas/see-mode.schema"));
45
+ const select_schema_1 = __importDefault(require("../validators/schemas/select.schema"));
46
+ const where_schema_1 = __importDefault(require("../validators/schemas/where.schema"));
47
+ const v = __importStar(require("valibot"));
48
+ /**
49
+ * Fluent builder for queries whose shape is only known at runtime (optional filters, user-controlled
50
+ * ordering and pagination, ...). Get one from `VSRepository.createQueryBuilder()`.
51
+ *
52
+ * Chain the configuration methods (`select`, `relations`, `where`, `orderBy`, `limit`, `offset`,
53
+ * `distinctOn`, `see`) and run the query with a terminal method (`getResult`,
54
+ * `getOneResult`, `getOneResultOrThrow`, `getCount`, `getExistence` or `getResultAndCount`). Nothing
55
+ * reaches the database until a terminal method is called.
56
+ *
57
+ * The builder is **mutable**: every chained call changes the same instance and returns it. Use
58
+ * {@link VSQueryBuilder.clone} to derive variations from a common base.
59
+ *
60
+ * Soft-delete is respected the same way as in the repository methods: when the repository has a
61
+ * `softRemoveKey`, only non-deleted records are seen unless {@link VSQueryBuilder.see} says otherwise.
62
+ *
63
+ * Arguments are validated as soon as they are passed to a chained method; an invalid one throws a
64
+ * `VSRepoError` of type `QUERY_BUILDER` and leaves the builder unchanged.
65
+ *
66
+ * @template Entity Type of the entity being queried.
67
+ * @template OrmTypes ORM-specific client/transaction types. See `VSRepoOrmTypes`.
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * const { result, count } = await userRepository
72
+ * .createQueryBuilder()
73
+ * .where({ active: true, balance: { gte: 100 } })
74
+ * .relations({ address: true })
75
+ * .orderBy({ createdAt: "desc" })
76
+ * .limit(20)
77
+ * .offset(40)
78
+ * .getResultAndCount();
79
+ * ```
80
+ *
81
+ * @publicApi
82
+ */
83
+ class VSQueryBuilder {
84
+ db;
85
+ adapter;
86
+ mergeWheresResolver;
87
+ logger;
88
+ options = {};
89
+ distinct;
90
+ seeMode = "active";
91
+ whereFilter;
92
+ /**
93
+ * @internal
94
+ */
95
+ constructor(db, adapter, mergeWheresResolver, logger) {
96
+ this.db = db;
97
+ this.adapter = adapter;
98
+ this.mergeWheresResolver = mergeWheresResolver;
99
+ this.logger = logger;
100
+ }
101
+ failValidation(issue, fallbackPath = "options") {
102
+ const path = issue?.path?.length ? issue.path.map(p => String(p.key)).join(".") : fallbackPath;
103
+ const message = `${path}: ${issue?.message ?? "validation failed"}`;
104
+ this.logger?.logError(`Validation failed (${vsrepo_error_type_enum_1.VSRepoErrorType.QUERY_BUILDER}): ${message}`);
105
+ throw new VSRepoError_1.VSRepoError(message, vsrepo_error_type_enum_1.VSRepoErrorType.QUERY_BUILDER);
106
+ }
107
+ validate(value, schema, fallbackPath) {
108
+ const parsed = v.safeParse(schema, value);
109
+ if (!parsed.success) {
110
+ this.failValidation(parsed.issues[0], fallbackPath);
111
+ }
112
+ }
113
+ resolveWhere() {
114
+ return this.mergeWheresResolver.resolve(this.seeMode, this.whereFilter ?? {});
115
+ }
116
+ // * Log de debug dos passos do builder e das queries. O objeto só é serializado se o nível for DEBUG
117
+ trace(message, obj) {
118
+ this.logger?.logDebug(`VSQueryBuilder: ${message}`, obj);
119
+ }
120
+ // * Nunca logar o `db` aqui (client/transação do ORM), só os parâmetros da query
121
+ async execute(operation, params, run) {
122
+ this.trace(operation, { see: this.seeMode, ...params });
123
+ const start = this.logger?.startPerformLog(`run query builder ${operation}`);
124
+ try {
125
+ return await run();
126
+ }
127
+ finally {
128
+ this.logger?.endPerformLog(start);
129
+ }
130
+ }
131
+ setOptions(options) {
132
+ this.options = options;
133
+ }
134
+ setWhereFilter(whereFilter) {
135
+ this.whereFilter = whereFilter;
136
+ }
137
+ setDistinct(distinct) {
138
+ this.distinct = distinct;
139
+ }
140
+ setSeeMode(seeMode) {
141
+ this.seeMode = seeMode;
142
+ }
143
+ /**
144
+ * Sets the client or transaction the query runs on, replacing the one given to `createQueryBuilder()`.
145
+ *
146
+ * It's lazy — it only matters when a terminal method runs — so a builder can be created before a
147
+ * transaction and pointed at it from inside, or a {@link VSQueryBuilder.clone} can be pointed at another
148
+ * client without touching the original builder.
149
+ *
150
+ * @param db Client or transaction that every following terminal call will use.
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const qb = userRepository.createQueryBuilder().where({ active: true });
155
+ *
156
+ * await userRepository.transaction(async tx => {
157
+ * qb.setDb(tx);
158
+ * return qb.getResult();
159
+ * });
160
+ * ```
161
+ */
162
+ setDb(db) {
163
+ this.db = db;
164
+ this.trace("db replaced");
165
+ }
166
+ /**
167
+ * Runs the query and returns every matching record.
168
+ *
169
+ * Uses everything configured on the builder: filter, `select`, `relations`, `orderBy`, `limit`/`offset`
170
+ * and `distinctOn` (the only terminal method that applies `distinct`).
171
+ *
172
+ * @returns The matching records (an empty array if none).
173
+ */
174
+ async getResult() {
175
+ const where = this.resolveWhere();
176
+ const options = { ...this.options, distinct: this.distinct };
177
+ return this.execute("getResult", { where, options }, () => this.adapter.findMany(where, { ...options, db: this.db }));
178
+ }
179
+ /**
180
+ * Runs the query and returns the first matching record, or `null` if there is none.
181
+ *
182
+ * Uses the filter, `select`, `relations`, `orderBy` and `limit`/`offset`. `distinctOn` is not applied.
183
+ *
184
+ * @returns The record, or `null` when nothing matches.
185
+ */
186
+ async getOneResult() {
187
+ const where = this.resolveWhere();
188
+ const options = { ...this.options };
189
+ return this.execute("getOneResult", { where, options }, () => this.adapter.findOne(where, { ...options, db: this.db }));
190
+ }
191
+ /**
192
+ * Same as {@link VSQueryBuilder.getOneResult}, but throws instead of returning `null`.
193
+ *
194
+ * The error thrown when nothing matches is the one the adapter's `findOneOrThrow` raises; it is not wrapped.
195
+ *
196
+ * @returns The first matching record.
197
+ */
198
+ async getOneResultOrThrow() {
199
+ const where = this.resolveWhere();
200
+ const options = { ...this.options };
201
+ return this.execute("getOneResultOrThrow", { where, options }, () => this.adapter.findOneOrThrow(where, { ...options, db: this.db }));
202
+ }
203
+ /**
204
+ * Counts the records matching the filter.
205
+ *
206
+ * Forwards `orderBy` and `limit`/`offset` to the adapter's `count` as configured, so if you want the
207
+ * total of a builder that has pagination use {@link VSQueryBuilder.getResultAndCount} or count from a
208
+ * {@link VSQueryBuilder.clone} without it. `select`, `relations` and `distinctOn` are not used
209
+ * (`count` doesn't support `distinct`).
210
+ *
211
+ * @returns The number of matching records.
212
+ */
213
+ async getCount() {
214
+ const where = this.resolveWhere();
215
+ const options = { order: this.options.order, pagination: this.options.pagination };
216
+ return this.execute("getCount", { where, options }, () => this.adapter.count(where, { ...options, db: this.db }));
217
+ }
218
+ /**
219
+ * Checks whether at least one record matches the filter. Only the filter (and soft-delete visibility) is used.
220
+ *
221
+ * @returns `true` if a matching record exists, `false` otherwise.
222
+ */
223
+ async getExistence() {
224
+ const where = this.resolveWhere();
225
+ return this.execute("getExistence", { where }, () => this.adapter.exists(where, { db: this.db }));
226
+ }
227
+ /**
228
+ * Fetches a page of records and the total of records matching the filter, in a single call
229
+ * (like MikroORM's `getResultAndCount()`).
230
+ *
231
+ * `result` honors `orderBy` and `limit`/`offset`; `count` deliberately ignores `orderBy` and
232
+ * pagination, so it is the total that lets you compute the number of pages. Both queries run in
233
+ * parallel with the same filter and the same `db`. `distinctOn` is not used by either.
234
+ *
235
+ * @returns The page (`result`) and the total of matching records (`count`).
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * const { result, count } = await userRepository
240
+ * .createQueryBuilder()
241
+ * .where({ active: true })
242
+ * .limit(20)
243
+ * .offset(40)
244
+ * .getResultAndCount();
245
+ *
246
+ * const totalPages = Math.ceil(count / 20);
247
+ * ```
248
+ */
249
+ async getResultAndCount() {
250
+ const where = this.resolveWhere();
251
+ const options = { ...this.options };
252
+ return this.execute("getResultAndCount", { where, options }, async () => {
253
+ const [result, count] = await Promise.all([
254
+ this.adapter.findMany(where, { ...options, db: this.db }),
255
+ this.adapter.count(where, { db: this.db }),
256
+ ]);
257
+ return { result, count };
258
+ });
259
+ }
260
+ /**
261
+ * Returns an independent builder with the same filter, options, `distinctOn` fields, `see` mode and `db`.
262
+ * Changes made to either builder afterwards don't affect the other.
263
+ *
264
+ * @returns The new builder.
265
+ *
266
+ * @example
267
+ * ```typescript
268
+ * const active = userRepository.createQueryBuilder().where({ active: true });
269
+ *
270
+ * const total = await active.clone().getCount();
271
+ * const firstPage = await active.clone().orderBy({ name: "asc" }).limit(10).getResult();
272
+ * ```
273
+ */
274
+ clone() {
275
+ const qbClone = new VSQueryBuilder(this.db, this.adapter, this.mergeWheresResolver, this.logger);
276
+ qbClone.setOptions(structuredClone(this.options));
277
+ qbClone.setWhereFilter(this.whereFilter);
278
+ qbClone.setDistinct(this.distinct);
279
+ qbClone.setSeeMode(this.seeMode);
280
+ this.trace("clone");
281
+ return qbClone;
282
+ }
283
+ /**
284
+ * Sets the fields (and nested relation fields) to select. Replaces any previous `select`.
285
+ *
286
+ * @param select Fields to select, e.g. `{ id: true, name: true, address: { city: true } }`.
287
+ * @throws {VSRepoError} `QUERY_BUILDER` if `select` doesn't have a valid shape.
288
+ */
289
+ select(select) {
290
+ this.validate(select, select_schema_1.default, "select");
291
+ this.options.select = select;
292
+ this.trace("select", select);
293
+ return this;
294
+ }
295
+ /**
296
+ * Sets the relations to load together with the records. Replaces any previous `relations`.
297
+ *
298
+ * @param relations Relations to load, e.g. `{ address: true, products: true }`.
299
+ * @throws {VSRepoError} `QUERY_BUILDER` if `relations` doesn't have a valid shape.
300
+ */
301
+ relations(relations) {
302
+ this.validate(relations, relations_schema_1.default, "relations");
303
+ this.options.relations = relations;
304
+ this.trace("relations", relations);
305
+ return this;
306
+ }
307
+ /**
308
+ * Sets the filter, replacing any previous one. It accepts the same `VSRepoWhere` used by the rest of
309
+ * the library: field-level filters (`{ active: true, balance: { gte: 100 } }`), relation filters
310
+ * (`_some`/`_every`/`_none`, `_with`/`_without`) and the logical operators `AND`, `OR` and `NOT`.
311
+ *
312
+ * The soft-delete filter (see {@link VSQueryBuilder.see}) is added on top of it when the query runs.
313
+ *
314
+ * @param where Filter of the query.
315
+ * @throws {VSRepoError} `QUERY_BUILDER` if `where` doesn't have a valid shape.
316
+ *
317
+ * @example
318
+ * ```typescript
319
+ * qb.where({
320
+ * active: true,
321
+ * OR: [{ name: { contains: "Maria" } }, { email: { contains: "maria" } }],
322
+ * });
323
+ * ```
324
+ */
325
+ where(where) {
326
+ this.validate(where, where_schema_1.default, "where");
327
+ this.whereFilter = where;
328
+ this.trace("where", where);
329
+ return this;
330
+ }
331
+ /**
332
+ * Sets the ordering. Replaces any previous ordering.
333
+ *
334
+ * @param order An object, or an array of objects, mapping primitive fields to `"asc"`/`"desc"`
335
+ * (lower or upper case), e.g. `{ createdAt: "desc" }`.
336
+ * @throws {VSRepoError} `QUERY_BUILDER` if `order` doesn't have a valid shape.
337
+ */
338
+ orderBy(order) {
339
+ this.validate(order, ordering_schema_1.default, "order");
340
+ this.options.order = order;
341
+ this.trace("orderBy", order);
342
+ return this;
343
+ }
344
+ /**
345
+ * Sets the maximum number of records to return. Can be combined with {@link VSQueryBuilder.offset}.
346
+ *
347
+ * @param limit Non-negative integer.
348
+ * @throws {VSRepoError} `QUERY_BUILDER` if `limit` isn't a non-negative integer.
349
+ */
350
+ limit(limit) {
351
+ this.validate(limit, v.pipe(v.number(), v.integer(), v.minValue(0)), "limit");
352
+ this.options.pagination ??= {};
353
+ this.options.pagination.limit = limit;
354
+ this.trace(`limit ${limit}`);
355
+ return this;
356
+ }
357
+ /**
358
+ * Sets how many records to skip. Can be combined with {@link VSQueryBuilder.limit}.
359
+ *
360
+ * @param offset Non-negative integer.
361
+ * @throws {VSRepoError} `QUERY_BUILDER` if `offset` isn't a non-negative integer.
362
+ */
363
+ offset(offset) {
364
+ this.validate(offset, v.pipe(v.number(), v.integer(), v.minValue(0)), "offset");
365
+ this.options.pagination ??= {};
366
+ this.options.pagination.offset = offset;
367
+ this.trace(`offset ${offset}`);
368
+ return this;
369
+ }
370
+ /**
371
+ * Sets the field(s) to apply `distinct` on. Replaces any previous `distinctOn`.
372
+ *
373
+ * Only {@link VSQueryBuilder.getResult} uses it: the ecosystem's `count` doesn't support `distinct`.
374
+ *
375
+ * @param fields A primitive field, or an array of them.
376
+ * @throws {VSRepoError} `QUERY_BUILDER` if `fields` isn't a string or an array of strings.
377
+ */
378
+ distinctOn(fields) {
379
+ this.validate(fields, v.union([v.string(), v.array(v.string())]), "fields");
380
+ this.distinct = Array.isArray(fields) ? fields : [fields];
381
+ this.trace("distinctOn", this.distinct);
382
+ return this;
383
+ }
384
+ /**
385
+ * Sets which records the query sees when the repository has a `softRemoveKey`. Applies to every
386
+ * terminal method (both queries of `getResultAndCount` included) and is ignored by repositories
387
+ * without soft-delete.
388
+ *
389
+ * @param seeMode `"active"` (default) for non-deleted records, `"removed"` for soft-deleted ones
390
+ * or `"all"` to ignore soft-delete.
391
+ * @throws {VSRepoError} `QUERY_BUILDER` if `seeMode` isn't one of the modes above.
392
+ */
393
+ see(seeMode) {
394
+ this.validate(seeMode, see_mode_schema_1.default, "seeMode");
395
+ this.seeMode = seeMode;
396
+ this.trace(`see '${seeMode}'`);
397
+ return this;
398
+ }
399
+ }
400
+ exports.VSQueryBuilder = VSQueryBuilder;
401
+ //# sourceMappingURL=vs-query-builder.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vs-query-builder.util.js","sourceRoot":"","sources":["../../../src/internal/utils/vs-query-builder.util.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,238 @@
1
+ import { VSRawQueryBuilderCteQuery } from "../../types/vsrepo/vs-raw-query-builder-cte-query.type";
2
+ import { VSRawQueryBuilderTarget } from "../../types/vsrepo/vs-raw-query-builder-target.type";
3
+ import { VSRepoOrmTypes } from "../../types/vsrepo/vsrepo-orm-types.type";
4
+ import { VSSql } from "./vs-sql.util";
5
+ /**
6
+ * Fluent, SQL-agnostic builder for hand-written **`SELECT`** queries whose shape is only known
7
+ * at runtime, but whose SQL is too specific (window functions, CTEs referenced elsewhere,
8
+ * vendor-specific syntax, ...) to express through {@link VSQueryBuilder}'s `where`/`relations`
9
+ * model. Compiles down to a single {@link VSSql} fragment — get one from
10
+ * `VSRepository.createRawQueryBuilder()`.
11
+ *
12
+ * Nothing reaches the database until {@link VSRawQueryBuilder.execute} is called. The builder is
13
+ * **mutable**: every chained call changes the same instance and returns it. Use
14
+ * {@link VSRawQueryBuilder.clone} to derive variations from a common base.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { VSSql } from "vsrepo";
19
+ *
20
+ * const rows = await orderRepository
21
+ * .createRawQueryBuilder()
22
+ * .select("o.id", "o.total", "u.name")
23
+ * .from("order", "o")
24
+ * .innerJoin("user", "u", "u.id = o.user_id")
25
+ * .where(VSSql.sql`u.active = ${true}`)
26
+ * .andWhere(VSSql.sql`o.total > ${100}`)
27
+ * .andWhere("o.deleted_at is null")
28
+ * .groupBy("o.id", "u.name")
29
+ * .having(VSSql.sql`count(*) > ${1}`)
30
+ * .orderBy("o.total", "desc")
31
+ * .limit(20)
32
+ * .offset(0)
33
+ * .execute<{ id: string; total: number; name: string }[]>();
34
+ * ```
35
+ *
36
+ * @publicApi
37
+ */
38
+ export declare class VSRawQueryBuilder<OrmTypes extends VSRepoOrmTypes = VSRepoOrmTypes> {
39
+ private db;
40
+ private readonly adapter;
41
+ private readonly logger?;
42
+ private cteClauses;
43
+ private recursiveWith;
44
+ private selectColumns;
45
+ private fromTarget?;
46
+ private joinClauses;
47
+ private whereConditions;
48
+ private groupByColumns;
49
+ private havingConditions;
50
+ private orderByClauses;
51
+ private limitValue?;
52
+ private offsetValue?;
53
+ private trace;
54
+ private static validateNonEmptyString;
55
+ /** Converts a raw string into a `VSSql.raw` fragment (validating it isn't empty/blank first,
56
+ * since that would silently compile into broken SQL — e.g. a trailing comma or an empty
57
+ * `WHERE ()`) or passes an already-built `VSSql` fragment through untouched.
58
+ *
59
+ * @param context Name of the calling method/argument, used in the `VSRepoError` message. */
60
+ private static toFragment;
61
+ private newSubBuilder;
62
+ private resolveSubquery;
63
+ private resolveTarget;
64
+ private resolveCteQuery;
65
+ private static combine;
66
+ private static validateNonNegativeInt;
67
+ /**
68
+ * Sets the columns to select, replacing any previous `select`. Each column is either a raw,
69
+ * trusted string (an identifier, passed through as-is — like `VSSql.raw`, never pass
70
+ * user-controlled input) or a `VSSql` fragment for anything parameterized or aliased
71
+ * (**VSSql.sql\`count(*) AS total\`**).
72
+ *
73
+ * @param columns One or more columns/expressions. `select()` with no arguments is equivalent
74
+ * to `SELECT *`.
75
+ */
76
+ select(...columns: (string | VSSql)[]): this;
77
+ /**
78
+ * Sets the `FROM` target, replacing any previous one.
79
+ *
80
+ * @param target A raw table name, a `VSSql` fragment, or another `VSRawQueryBuilder`
81
+ * (compiled inline as a subquery, wrapped in parentheses).
82
+ * @param alias Optional alias, appended as `AS alias` (raw, trusted text).
83
+ */
84
+ from(target: VSRawQueryBuilderTarget, alias?: string): this;
85
+ private addCte;
86
+ /**
87
+ * Adds a `WITH` (common table expression). Each call adds one CTE; call it
88
+ * again to add more — they're all listed under a single `WITH`, in the order added.
89
+ *
90
+ * @param name Name the CTE is referenced by elsewhere in the query (raw, trusted text).
91
+ * @param query The CTE's body: a `VSRawQueryBuilder`, a subquery function, or a `VSSql` fragment — needed for
92
+ * anything a single `SELECT` builder can't express (e.g. a `UNION`).
93
+ * @param columns Optional explicit column list, rendered as `name(col1, col2) AS (...)`.
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * const rows = await orderRepository
98
+ * .createRawQueryBuilder()
99
+ * .with("big_spenders", qb => qb.select("user_id").from("order").groupBy("user_id").having("sum(total) > 1000"))
100
+ * .select("u.*")
101
+ * .from("user", "u")
102
+ * .innerJoin("big_spenders", "bs", "bs.user_id = u.id")
103
+ * .execute();
104
+ * ```
105
+ */
106
+ with(name: string, query: VSRawQueryBuilderCteQuery, columns?: string[]): this;
107
+ /**
108
+ * Same as {@link VSRawQueryBuilder.with}, but marks the whole `WITH` clause as `RECURSIVE`
109
+ * (required by the SQL standard for a CTE that references itself in its own body — usually
110
+ * a `VSSql` fragment with a `... UNION ALL SELECT ... FROM name ...` shape). One recursive
111
+ * CTE is enough to make the whole clause `WITH RECURSIVE`, even when combined with other,
112
+ * non-recursive ones added via {@link VSRawQueryBuilder.with}.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * const orgChart = await employeeRepository
117
+ * .createRawQueryBuilder()
118
+ * .withRecursive(
119
+ * "subordinates",
120
+ * VSSql.sql`
121
+ * SELECT id, manager_id, 1 AS depth FROM employee WHERE id = ${managerId}
122
+ * UNION ALL
123
+ * SELECT e.id, e.manager_id, s.depth + 1 FROM employee e
124
+ * INNER JOIN subordinates s ON e.manager_id = s.id
125
+ * `,
126
+ * ["id", "manager_id", "depth"],
127
+ * )
128
+ * .select("*")
129
+ * .from("subordinates")
130
+ * .orderBy("depth")
131
+ * .execute();
132
+ * ```
133
+ */
134
+ withRecursive(name: string, query: VSRawQueryBuilderCteQuery, columns?: string[]): this;
135
+ private addJoin;
136
+ /**
137
+ * Adds an `INNER JOIN`.
138
+ */
139
+ innerJoin(target: VSRawQueryBuilderTarget, alias: string, on: string | VSSql): this;
140
+ /**
141
+ * Adds a `LEFT JOIN`.
142
+ */
143
+ leftJoin(target: VSRawQueryBuilderTarget, alias: string, on: string | VSSql): this;
144
+ /**
145
+ * Adds a `RIGHT JOIN`.
146
+ */
147
+ rightJoin(target: VSRawQueryBuilderTarget, alias: string, on: string | VSSql): this;
148
+ /**
149
+ * Adds a `FULL JOIN`.
150
+ */
151
+ fullJoin(target: VSRawQueryBuilderTarget, alias: string, on: string | VSSql): this;
152
+ /**
153
+ * Adds a `WHERE` condition. The first call sets the filter; every later call (`where` or
154
+ * {@link VSRawQueryBuilder.andWhere}) is `AND`-combined with it, each wrapped in parentheses.
155
+ * Use {@link VSRawQueryBuilder.orWhere} to `OR`-combine instead.
156
+ */
157
+ where(condition: string | VSSql): this;
158
+ /** Alias for {@link VSRawQueryBuilder.where} — `AND`-combines `condition` with the existing filter. */
159
+ andWhere(condition: string | VSSql): this;
160
+ /** `OR`-combines `condition` with the existing `WHERE` filter. */
161
+ orWhere(condition: string | VSSql): this;
162
+ /**
163
+ * Adds columns to `GROUP BY`. Each call appends; call {@link VSRawQueryBuilder.clone} from a
164
+ * common base if you need independent variations.
165
+ */
166
+ groupBy(...columns: (string | VSSql)[]): this;
167
+ /**
168
+ * Adds a `HAVING` condition, `AND`-combined with any previous one (same semantics as
169
+ * {@link VSRawQueryBuilder.where}). Use {@link VSRawQueryBuilder.orHaving} to `OR`-combine.
170
+ */
171
+ having(condition: string | VSSql): this;
172
+ /** Alias for {@link VSRawQueryBuilder.having} — `AND`-combines `condition` with the existing `HAVING` filter. */
173
+ andHaving(condition: string | VSSql): this;
174
+ /** `OR`-combines `condition` with the existing `HAVING` filter. */
175
+ orHaving(condition: string | VSSql): this;
176
+ /**
177
+ * Adds a column to `ORDER BY`. Each call appends, in order, so call it once per column for a
178
+ * multi-column ordering.
179
+ */
180
+ orderBy(column: string | VSSql, direction?: "asc" | "desc" | "ASC" | "DESC"): this;
181
+ /**
182
+ * Sets the maximum number of rows to return, replacing any previous `limit`.
183
+ */
184
+ limit(limit: number): this;
185
+ /**
186
+ * Sets how many rows to skip, replacing any previous `offset`.
187
+ */
188
+ offset(offset: number): this;
189
+ /**
190
+ * Sets the client or transaction the query runs on, replacing the one given to
191
+ * `createRawQueryBuilder()`.
192
+ *
193
+ * It's lazy — it only matters when {@link VSRawQueryBuilder.execute} runs — so a builder can
194
+ * be created before a transaction and pointed at it from inside, or a
195
+ * {@link VSRawQueryBuilder.clone} can be pointed at another client without touching the
196
+ * original builder.
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * const qb = orderRepository.createRawQueryBuilder().select("*").from("order");
201
+ *
202
+ * await orderRepository.transaction(async tx => {
203
+ * qb.setDb(tx);
204
+ * return qb.execute();
205
+ * });
206
+ * ```
207
+ */
208
+ setDb(db: OrmTypes["dbClient"] | OrmTypes["dbTransaction"]): void;
209
+ /**
210
+ * Returns an independent builder with the same clauses and `db`. Changes made to either one
211
+ * afterwards don't affect the other (the underlying `VSSql`/`VSRawQueryBuilder` values
212
+ * themselves are immutable, so a shallow copy of every clause array is enough).
213
+ */
214
+ clone(): VSRawQueryBuilder<OrmTypes>;
215
+ private compileCteClause;
216
+ /**
217
+ * Compiles every configured clause into a single {@link VSSql} fragment, in the order
218
+ * `WITH` (CTEs) -> `SELECT` -> `FROM` -> `JOIN`s -> `WHERE` -> `GROUP BY` -> `HAVING` -> `ORDER BY`
219
+ * -> `LIMIT` -> `OFFSET`. Nothing runs by itself — splice the result into another `VSSql`
220
+ * fragment as a subquery, or pass it to `VSRepository.query()`.
221
+ */
222
+ toVSSql(): VSSql;
223
+ private compileForAdapter;
224
+ /**
225
+ * Compiles the builder down to a plain SQL string, rendered with the adapter's own
226
+ * placeholder syntax (e.g. `$1`, `$2`, ...). Values themselves are **not** interpolated into
227
+ * the string — use {@link VSRawQueryBuilder.toVSSql} (`.compile()`) or
228
+ * {@link VSRawQueryBuilder.execute} if you also need the parameter values/to run the query.
229
+ */
230
+ toSql(): string;
231
+ /**
232
+ * Compiles and runs the query against the underlying database, through the same adapter as
233
+ * every other `VSRepository` method.
234
+ *
235
+ * @template T Shape of the returned rows. Defaults to `any`.
236
+ */
237
+ execute<T = any>(): Promise<T>;
238
+ }