@mikro-orm/core 7.0.0-dev.169 → 7.0.0-dev.170
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/errors.d.ts +1 -0
- package/errors.js +3 -0
- package/metadata/MetadataValidator.d.ts +5 -0
- package/metadata/MetadataValidator.js +24 -1
- package/metadata/types.d.ts +8 -2
- package/package.json +1 -1
- package/typings.d.ts +2 -0
- package/typings.js +4 -2
- package/utils/Utils.js +1 -1
package/errors.d.ts
CHANGED
|
@@ -66,6 +66,7 @@ export declare class MetadataError<T extends AnyEntity = AnyEntity> extends Vali
|
|
|
66
66
|
static targetKeyNotUnique(meta: EntityMetadata, prop: EntityProperty): MetadataError<Partial<any>>;
|
|
67
67
|
static targetKeyNotFound(meta: EntityMetadata, prop: EntityProperty): MetadataError<Partial<any>>;
|
|
68
68
|
static dangerousPropertyName(meta: EntityMetadata, prop: EntityProperty): MetadataError<Partial<any>>;
|
|
69
|
+
static viewEntityWithoutExpression(meta: EntityMetadata): MetadataError;
|
|
69
70
|
private static fromMessage;
|
|
70
71
|
}
|
|
71
72
|
export declare class NotFoundError<T extends AnyEntity = AnyEntity> extends ValidationError<T> {
|
package/errors.js
CHANGED
|
@@ -225,6 +225,9 @@ export class MetadataError extends ValidationError {
|
|
|
225
225
|
static dangerousPropertyName(meta, prop) {
|
|
226
226
|
return this.fromMessage(meta, prop, `uses a dangerous property name '${prop.name}' which could lead to prototype pollution. Please use a different property name.`);
|
|
227
227
|
}
|
|
228
|
+
static viewEntityWithoutExpression(meta) {
|
|
229
|
+
return new MetadataError(`View entity ${meta.className} is missing 'expression'. View entities must have an expression defining the SQL query.`);
|
|
230
|
+
}
|
|
228
231
|
static fromMessage(meta, prop, message) {
|
|
229
232
|
return new MetadataError(`${meta.className}.${prop.name} ${message}`);
|
|
230
233
|
}
|
|
@@ -19,7 +19,15 @@ const DANGEROUS_PROPERTY_NAMES = ['__proto__', 'constructor', 'prototype'];
|
|
|
19
19
|
export class MetadataValidator {
|
|
20
20
|
validateEntityDefinition(metadata, name, options) {
|
|
21
21
|
const meta = metadata.get(name);
|
|
22
|
-
|
|
22
|
+
// View entities (expression with view flag) behave like regular tables but are read-only
|
|
23
|
+
// They can have primary keys and are created as actual database views
|
|
24
|
+
if (meta.view) {
|
|
25
|
+
this.validateViewEntity(meta);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Virtual entities (expression without view flag) have restrictions - no PKs, limited relation types
|
|
29
|
+
// Note: meta.virtual is set later in sync(), so we check for expression && !view here
|
|
30
|
+
if (meta.virtual || (meta.expression && !meta.view)) {
|
|
23
31
|
for (const prop of Utils.values(meta.properties)) {
|
|
24
32
|
if (![ReferenceKind.SCALAR, ReferenceKind.EMBEDDED, ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
|
25
33
|
throw new MetadataError(`Only scalars, embedded properties and to-many relations are allowed inside virtual entity. Found '${prop.kind}' in ${meta.className}.${prop.name}`);
|
|
@@ -240,4 +248,19 @@ export class MetadataValidator {
|
|
|
240
248
|
}
|
|
241
249
|
}
|
|
242
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* Validates view entity configuration.
|
|
253
|
+
* View entities must have an expression.
|
|
254
|
+
*/
|
|
255
|
+
validateViewEntity(meta) {
|
|
256
|
+
// View entities must have an expression
|
|
257
|
+
if (!meta.expression) {
|
|
258
|
+
throw MetadataError.viewEntityWithoutExpression(meta);
|
|
259
|
+
}
|
|
260
|
+
// Validate indexes if present
|
|
261
|
+
this.validateIndexes(meta, meta.indexes ?? [], 'index');
|
|
262
|
+
this.validateIndexes(meta, meta.uniques ?? [], 'unique');
|
|
263
|
+
// Validate property names
|
|
264
|
+
this.validatePropertyNames(meta);
|
|
265
|
+
}
|
|
243
266
|
}
|
package/metadata/types.d.ts
CHANGED
|
@@ -27,11 +27,17 @@ export type EntityOptions<T, E = T extends EntityClass<infer P> ? P : T> = {
|
|
|
27
27
|
abstract?: boolean;
|
|
28
28
|
/** Disables change tracking - such entities are ignored during flush. */
|
|
29
29
|
readonly?: boolean;
|
|
30
|
-
/** Marks entity as {@doclink virtual-entities | virtual}. This is set automatically when you use `expression` option. */
|
|
30
|
+
/** Marks entity as {@doclink virtual-entities | virtual}. This is set automatically when you use `expression` option (unless `view` is set). */
|
|
31
31
|
virtual?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Marks entity as a database view. Unlike virtual entities which evaluate expressions at query time,
|
|
34
|
+
* view entities create actual database views. The `expression` option must be provided when `view` is true.
|
|
35
|
+
* View entities are read-only by default.
|
|
36
|
+
*/
|
|
37
|
+
view?: boolean;
|
|
32
38
|
/** Used to make ORM aware of externally defined triggers. This is needed for MS SQL Server multi inserts, ignored in other dialects. */
|
|
33
39
|
hasTriggers?: boolean;
|
|
34
|
-
/** SQL query that maps to a {@doclink virtual-entities | virtual entity}. */
|
|
40
|
+
/** SQL query that maps to a {@doclink virtual-entities | virtual entity}, or for view entities, the view definition. */
|
|
35
41
|
expression?: string | ((em: any, where: ObjectQuery<E>, options: FindOptions<E, any, any, any>, stream?: boolean) => object);
|
|
36
42
|
/** Set {@doclink repositories#custom-repository | custom repository class}. */
|
|
37
43
|
repository?: () => Constructor;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.0.0-dev.
|
|
4
|
+
"version": "7.0.0-dev.170",
|
|
5
5
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./package.json": "./package.json",
|
package/typings.d.ts
CHANGED
|
@@ -472,6 +472,8 @@ export interface EntityMetadata<Entity = any, Class extends EntityCtor<Entity> =
|
|
|
472
472
|
schema?: string;
|
|
473
473
|
pivotTable?: boolean;
|
|
474
474
|
virtual?: boolean;
|
|
475
|
+
/** True if this entity represents a database view (not a virtual entity). */
|
|
476
|
+
view?: boolean;
|
|
475
477
|
expression?: string | ((em: any, where: ObjectQuery<Entity>, options: FindOptions<Entity, any, any, any>, stream?: boolean) => MaybePromise<Raw | object | string>);
|
|
476
478
|
discriminatorColumn?: EntityKey<Entity> | AnyString;
|
|
477
479
|
discriminatorValue?: number | string;
|
package/typings.js
CHANGED
|
@@ -109,7 +109,9 @@ export class EntityMetadata {
|
|
|
109
109
|
return this.root.uniqueName === prop.targetMeta?.root.uniqueName;
|
|
110
110
|
});
|
|
111
111
|
this.hasUniqueProps = this.uniques.length + this.uniqueProps.length > 0;
|
|
112
|
-
this
|
|
112
|
+
// If `view` is set, this is a database view entity (not a virtual entity).
|
|
113
|
+
// Virtual entities evaluate expressions at query time, view entities create actual database views.
|
|
114
|
+
this.virtual = !!this.expression && !this.view;
|
|
113
115
|
if (config) {
|
|
114
116
|
for (const prop of this.props) {
|
|
115
117
|
if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => typeof item === 'string')) {
|
|
@@ -132,7 +134,7 @@ export class EntityMetadata {
|
|
|
132
134
|
for (const hook of Utils.keys(this.hooks)) {
|
|
133
135
|
this.hooks[hook] = Utils.removeDuplicates(this.hooks[hook]);
|
|
134
136
|
}
|
|
135
|
-
if (this.virtual) {
|
|
137
|
+
if (this.virtual || this.view) {
|
|
136
138
|
this.readonly = true;
|
|
137
139
|
}
|
|
138
140
|
if (initIndexes && this.name) {
|
package/utils/Utils.js
CHANGED
|
@@ -123,7 +123,7 @@ export function parseJsonSafe(value) {
|
|
|
123
123
|
}
|
|
124
124
|
export class Utils {
|
|
125
125
|
static PK_SEPARATOR = '~~~';
|
|
126
|
-
static #ORM_VERSION = '7.0.0-dev.
|
|
126
|
+
static #ORM_VERSION = '7.0.0-dev.170';
|
|
127
127
|
/**
|
|
128
128
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
129
129
|
*/
|