metal-orm 1.1.0 → 1.1.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/README.md CHANGED
@@ -110,8 +110,10 @@ Full docs live in the `docs/` folder:
110
110
  - **Table-valued functions**: use the new `tvf(key, …)` helper when you want portable intents such as `ARRAY_UNNEST`, letting the dialects’ `TableFunctionStrategy` renderers emit dialect-specific syntax (`LATERAL`/`WITH ORDINALITY`, alias validation, quoting, etc.). `fnTable()` remains available as the raw escape hatch when you need to emit a specific SQL function directly.
111
111
  - **String helpers**: `lower`, `upper`, `trim`, `ltrim/rtrim`, `concat/concatWs`, `substr/left/right`, `position/instr/locate`, `replace`, `repeat`, `lpad/rpad`, `space`, and more with dialect-aware rendering.
112
112
  - **Set operations**: `union`, `unionAll`, `intersect`, `except` across all dialects (ORDER/LIMIT apply to the combined result; hydration is disabled for compound queries so rows are returned as-is without collapsing duplicates).
113
- - **Expression builders**: `eq`, `and`, `or`, `between`, `inList`, `exists`, `jsonPath`, `caseWhen`, window functions like `rowNumber`, `rank`, `lag`, `lead`, etc., all backed by typed AST nodes.
114
- - **Relation-aware hydration**: turn flat rows into nested objects (`user.posts`, `user.roles`, etc.) using a hydration plan derived from the AST metadata.
113
+ - **Expression builders**: `eq`, `and`, `or`, `between`, `inList`, `exists`, `jsonPath`, `caseWhen`, window functions like `rowNumber`, `rank`, `lag`, `lead`, etc., all backed by typed AST nodes.
114
+ - **Operator safety**: scalar operators (`eq`, `neq`, `gt`, `gte`, `lt`, `lte`) are for single values; for arrays, use `inList`/`notInList`.
115
+ - Migration example: `where(eq(tipoAcao.columns.codigo, codigos))` -> `where(inList(tipoAcao.columns.codigo, codigos))`.
116
+ - **Relation-aware hydration**: turn flat rows into nested objects (`user.posts`, `user.roles`, etc.) using a hydration plan derived from the AST metadata.
115
117
  - **Multi-dialect**: compile once, run on MySQL/MariaDB, PostgreSQL, SQLite, or SQL Server via pluggable dialects.
116
118
  - **DML**: type-safe INSERT / UPDATE / DELETE with `RETURNING` where supported.
117
119
 
package/dist/index.cjs CHANGED
@@ -202,6 +202,7 @@ __export(index_exports, {
202
202
  eq: () => eq,
203
203
  esel: () => esel,
204
204
  exclude: () => exclude,
205
+ executeFilteredPaged: () => executeFilteredPaged,
205
206
  executeHydrated: () => executeHydrated,
206
207
  executeHydratedPlain: () => executeHydratedPlain,
207
208
  executeHydratedPlainWithContexts: () => executeHydratedPlainWithContexts,
@@ -802,6 +803,11 @@ var toOperandNode = (value) => {
802
803
  if (isLiteralValue(value)) {
803
804
  return toLiteralNode(value);
804
805
  }
806
+ if (Array.isArray(value)) {
807
+ throw new Error(
808
+ "Array operands are not supported in scalar comparisons. Use inList/notInList for array matching."
809
+ );
810
+ }
805
811
  return columnRefToNode(value);
806
812
  };
807
813
  var valueToOperand = (value) => {
@@ -16208,6 +16214,129 @@ function computePaginationMetadata(totalItems, page, pageSize) {
16208
16214
  };
16209
16215
  }
16210
16216
 
16217
+ // src/dto/execute-filtered-paged.ts
16218
+ var normalizeSortBy = (sortBy) => {
16219
+ if (!sortBy) {
16220
+ return void 0;
16221
+ }
16222
+ const normalized = sortBy.trim();
16223
+ return normalized.length > 0 ? normalized : void 0;
16224
+ };
16225
+ var detectPrimaryKeyName = (table) => {
16226
+ const pk = Object.values(table.columns).find((column) => column.primary);
16227
+ return pk?.name;
16228
+ };
16229
+ var toColumnNode = (table, name) => ({
16230
+ type: "Column",
16231
+ table: table.name,
16232
+ name
16233
+ });
16234
+ var getColumnByName = (table, name) => {
16235
+ return Object.values(table.columns).find((column) => column.name === name);
16236
+ };
16237
+ var resolveSortTermFromAllowed = (sortBy, allowedSortColumns) => {
16238
+ if (!allowedSortColumns) {
16239
+ throw new Error("allowedSortColumns is required when sortBy/defaultSortBy is provided.");
16240
+ }
16241
+ const term = allowedSortColumns[sortBy];
16242
+ if (term) {
16243
+ return term;
16244
+ }
16245
+ const allowedKeys = Object.keys(allowedSortColumns);
16246
+ throw new Error(
16247
+ `Invalid sortBy "${sortBy}". Allowed values: ${allowedKeys.length > 0 ? allowedKeys.join(", ") : "(none)"}.`
16248
+ );
16249
+ };
16250
+ var resolvePrimarySort = (table, sortBy, sortDirection, allowedSortColumns, defaultSortBy, defaultSortDirection) => {
16251
+ const requestedSortBy = normalizeSortBy(sortBy);
16252
+ if (requestedSortBy) {
16253
+ return {
16254
+ term: resolveSortTermFromAllowed(requestedSortBy, allowedSortColumns),
16255
+ direction: sortDirection ?? ORDER_DIRECTIONS.ASC
16256
+ };
16257
+ }
16258
+ const configuredDefaultSortBy = normalizeSortBy(defaultSortBy);
16259
+ if (configuredDefaultSortBy) {
16260
+ return {
16261
+ term: resolveSortTermFromAllowed(configuredDefaultSortBy, allowedSortColumns),
16262
+ direction: defaultSortDirection ?? ORDER_DIRECTIONS.ASC
16263
+ };
16264
+ }
16265
+ const detectedPkName = detectPrimaryKeyName(table);
16266
+ if (detectedPkName) {
16267
+ const detectedPkColumn = getColumnByName(table, detectedPkName);
16268
+ if (detectedPkColumn) {
16269
+ return {
16270
+ term: detectedPkColumn,
16271
+ direction: ORDER_DIRECTIONS.ASC
16272
+ };
16273
+ }
16274
+ }
16275
+ const idColumn = getColumnByName(table, "id");
16276
+ return {
16277
+ term: idColumn ?? toColumnNode(table, "id"),
16278
+ direction: ORDER_DIRECTIONS.ASC
16279
+ };
16280
+ };
16281
+ var resolveTieBreaker = (table, tieBreakerColumn) => {
16282
+ const configuredName = normalizeSortBy(tieBreakerColumn);
16283
+ if (configuredName) {
16284
+ const configuredColumn = getColumnByName(table, configuredName);
16285
+ if (!configuredColumn) {
16286
+ throw new Error(
16287
+ `Invalid tieBreakerColumn "${configuredName}" for table "${table.name}".`
16288
+ );
16289
+ }
16290
+ return configuredColumn;
16291
+ }
16292
+ const idColumn = getColumnByName(table, "id");
16293
+ if (idColumn) {
16294
+ return idColumn;
16295
+ }
16296
+ const detectedPkName = detectPrimaryKeyName(table);
16297
+ if (detectedPkName) {
16298
+ const detectedPkColumn = getColumnByName(table, detectedPkName);
16299
+ if (detectedPkColumn) {
16300
+ return detectedPkColumn;
16301
+ }
16302
+ }
16303
+ return toColumnNode(table, "id");
16304
+ };
16305
+ var extractSortColumnName = (term) => {
16306
+ if (typeof term === "object" && term !== null && "name" in term && typeof term.name === "string") {
16307
+ return term.name;
16308
+ }
16309
+ return void 0;
16310
+ };
16311
+ var executeFilteredPaged = async (options) => {
16312
+ const table = options.qb.getTable();
16313
+ const primarySort = resolvePrimarySort(
16314
+ table,
16315
+ options.sortBy,
16316
+ options.sortDirection,
16317
+ options.allowedSortColumns,
16318
+ options.defaultSortBy,
16319
+ options.defaultSortDirection
16320
+ );
16321
+ const tieBreaker = resolveTieBreaker(table, options.tieBreakerColumn);
16322
+ let qb = applyFilter(
16323
+ options.qb,
16324
+ options.tableOrEntity,
16325
+ options.filters
16326
+ );
16327
+ qb = qb.orderBy(primarySort.term, primarySort.direction);
16328
+ const primarySortColumnName = extractSortColumnName(primarySort.term);
16329
+ const tieBreakerColumnName = extractSortColumnName(tieBreaker);
16330
+ if (primarySortColumnName !== tieBreakerColumnName) {
16331
+ qb = qb.orderBy(tieBreaker, ORDER_DIRECTIONS.ASC);
16332
+ }
16333
+ const result = await qb.executePaged(options.session, {
16334
+ page: options.page,
16335
+ pageSize: options.pageSize
16336
+ });
16337
+ return toPagedResponse(result);
16338
+ };
16339
+
16211
16340
  // src/dto/openapi/type-mappings.ts
16212
16341
  var IntegerTypeStrategy = class {
16213
16342
  types = ["INT", "INTEGER"];
@@ -19043,6 +19172,7 @@ var TagIndex = class {
19043
19172
  eq,
19044
19173
  esel,
19045
19174
  exclude,
19175
+ executeFilteredPaged,
19046
19176
  executeHydrated,
19047
19177
  executeHydratedPlain,
19048
19178
  executeHydratedPlainWithContexts,