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 +4 -2
- package/dist/index.cjs +130 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -13
- package/dist/index.d.ts +33 -13
- package/dist/index.js +129 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/scripts/generate-entities/cli.mjs +7 -0
- package/scripts/generate-entities/generate.mjs +10 -6
- package/scripts/inspect-schema.mjs +181 -0
- package/scripts/naming-strategy.mjs +17 -7
- package/src/core/ast/expression-builders.ts +62 -55
- package/src/dto/execute-filtered-paged.ts +206 -0
- package/src/dto/index.ts +40 -31
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
|
-
- **
|
|
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,
|