@mikro-orm/core 7.2.0-dev.14 → 7.2.0-dev.16
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/EntityManager.d.ts +30 -2
- package/EntityManager.js +192 -40
- package/MikroORM.js +3 -0
- package/connections/Connection.d.ts +3 -1
- package/entity/Collection.js +4 -2
- package/entity/EntityLoader.js +1 -1
- package/entity/defineEntity.d.ts +7 -0
- package/entity/defineEntity.js +4 -0
- package/enums.d.ts +3 -1
- package/errors.d.ts +34 -0
- package/errors.js +82 -0
- package/exceptions.d.ts +5 -0
- package/exceptions.js +5 -0
- package/index.d.ts +1 -1
- package/metadata/MetadataDiscovery.d.ts +3 -0
- package/metadata/MetadataDiscovery.js +88 -6
- package/metadata/types.d.ts +19 -3
- package/package.json +1 -1
- package/platforms/Platform.d.ts +15 -1
- package/platforms/Platform.js +48 -0
- package/typings.d.ts +47 -0
- package/typings.js +1 -0
- package/unit-of-work/UnitOfWork.js +1 -0
- package/utils/Configuration.d.ts +15 -1
- package/utils/Configuration.js +11 -1
- package/utils/QueryHelper.d.ts +12 -0
- package/utils/QueryHelper.js +63 -0
- package/utils/TransactionManager.js +1 -1
- package/utils/Utils.d.ts +2 -0
- package/utils/Utils.js +5 -1
- package/utils/env-vars.js +1 -0
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/rls-utils.d.ts +35 -0
- package/utils/rls-utils.js +97 -0
package/utils/Configuration.d.ts
CHANGED
|
@@ -439,7 +439,7 @@ export interface Options<Driver extends IDatabaseDriver = IDatabaseDriver, EM ex
|
|
|
439
439
|
*/
|
|
440
440
|
filters: Dictionary<{
|
|
441
441
|
name?: string;
|
|
442
|
-
} & Omit<FilterDef, 'name'>>;
|
|
442
|
+
} & Omit<FilterDef, 'name' | 'rls'>>;
|
|
443
443
|
/**
|
|
444
444
|
* Metadata discovery configuration options.
|
|
445
445
|
* Controls how entities are discovered and validated.
|
|
@@ -480,6 +480,12 @@ export interface Options<Driver extends IDatabaseDriver = IDatabaseDriver, EM ex
|
|
|
480
480
|
* @default false
|
|
481
481
|
*/
|
|
482
482
|
disableTransactions?: boolean;
|
|
483
|
+
/**
|
|
484
|
+
* How `em.setSessionContext()` session variables/role are applied for row level security.
|
|
485
|
+
* `'transaction'` (default) emits `set_config(..., true)` inside each transaction; `'connection'` applies them on every pooled connection acquire (PostgreSQL only).
|
|
486
|
+
* @default 'transaction'
|
|
487
|
+
*/
|
|
488
|
+
sessionContext?: 'transaction' | 'connection';
|
|
483
489
|
/**
|
|
484
490
|
* Enable verbose logging of internal operations.
|
|
485
491
|
* @default false
|
|
@@ -840,6 +846,14 @@ export interface Options<Driver extends IDatabaseDriver = IDatabaseDriver, EM ex
|
|
|
840
846
|
* @default false
|
|
841
847
|
*/
|
|
842
848
|
ignoreRoutines?: boolean;
|
|
849
|
+
/**
|
|
850
|
+
* Leave row level security policies unmanaged. Declared policies are still created and RLS is still enabled or
|
|
851
|
+
* forced based on the entity metadata, but existing policies are never dropped or altered and RLS is never
|
|
852
|
+
* disabled or unforced — use this to protect hand-written policies from being removed when they are not
|
|
853
|
+
* mirrored in the entity definitions.
|
|
854
|
+
* @default false
|
|
855
|
+
*/
|
|
856
|
+
ignorePolicies?: boolean;
|
|
843
857
|
/**
|
|
844
858
|
* Table names or patterns to skip during schema generation.
|
|
845
859
|
* @default []
|
package/utils/Configuration.js
CHANGED
|
@@ -7,7 +7,7 @@ import { Utils } from '../utils/Utils.js';
|
|
|
7
7
|
import { Routine } from '../metadata/Routine.js';
|
|
8
8
|
import { MetadataValidator } from '../metadata/MetadataValidator.js';
|
|
9
9
|
import { MetadataProvider } from '../metadata/MetadataProvider.js';
|
|
10
|
-
import { NotFoundError } from '../errors.js';
|
|
10
|
+
import { MetadataError, NotFoundError, ValidationError } from '../errors.js';
|
|
11
11
|
import { RequestContext } from './RequestContext.js';
|
|
12
12
|
import { DataloaderType, FlushMode, LoadStrategy, PopulateHint } from '../enums.js';
|
|
13
13
|
import { MemoryCacheAdapter } from '../cache/MemoryCacheAdapter.js';
|
|
@@ -71,6 +71,7 @@ const DEFAULTS = {
|
|
|
71
71
|
ensureDatabase: true,
|
|
72
72
|
ensureIndexes: false,
|
|
73
73
|
batchSize: 300,
|
|
74
|
+
sessionContext: 'transaction',
|
|
74
75
|
debug: false,
|
|
75
76
|
ignoreDeprecations: false,
|
|
76
77
|
verbose: false,
|
|
@@ -94,6 +95,7 @@ const DEFAULTS = {
|
|
|
94
95
|
ignoreSchema: [],
|
|
95
96
|
ignoreTriggers: false,
|
|
96
97
|
ignoreRoutines: false,
|
|
98
|
+
ignorePolicies: false,
|
|
97
99
|
skipTables: [],
|
|
98
100
|
skipViews: [],
|
|
99
101
|
skipColumns: {},
|
|
@@ -393,7 +395,15 @@ export class Configuration {
|
|
|
393
395
|
}
|
|
394
396
|
this.#options.schema ??= this.#platform.getDefaultSchemaName();
|
|
395
397
|
this.#options.charset ??= this.#platform.getDefaultCharset();
|
|
398
|
+
// fail closed instead of silently applying no session state on drivers without the reserve hook (e.g. pglite)
|
|
399
|
+
if (this.#options.sessionContext === 'connection' && !this.#platform.supportsConnectionSessionContext()) {
|
|
400
|
+
throw ValidationError.connectionSessionContextNotSupported();
|
|
401
|
+
}
|
|
396
402
|
Object.keys(this.#options.filters).forEach(key => {
|
|
403
|
+
// global filters have no entity to attach a policy to, so `rls` is only valid on entity-scoped filters
|
|
404
|
+
if (this.#options.filters[key].rls) {
|
|
405
|
+
throw MetadataError.rlsFilterMustBeEntityScoped(key);
|
|
406
|
+
}
|
|
397
407
|
this.#options.filters[key].default ??= true;
|
|
398
408
|
});
|
|
399
409
|
if (!this.#options.filtersOnRelations) {
|
package/utils/QueryHelper.d.ts
CHANGED
|
@@ -37,6 +37,18 @@ export declare class QueryHelper {
|
|
|
37
37
|
static inlinePrimaryKeyObjects<T extends object>(where: Dictionary, meta: EntityMetadata<T>, metadata: MetadataStorage, key?: string): boolean;
|
|
38
38
|
static processWhere<T extends object>(options: ProcessWhereOptions<T>): FilterQuery<T>;
|
|
39
39
|
static getActiveFilters<T>(meta: EntityMetadata<T>, options: FilterOptions | undefined, filters: Dictionary<FilterDef>): FilterDef[];
|
|
40
|
+
/** @internal Sentinel wrapping for arguments accessed while statically resolving an `rls` filter condition. */
|
|
41
|
+
static readonly RLS_SENTINEL_PREFIX = "__mikro_rls_arg__";
|
|
42
|
+
/** @internal */
|
|
43
|
+
static readonly RLS_SENTINEL_SUFFIX = "__";
|
|
44
|
+
/**
|
|
45
|
+
* Resolves an `rls` filter's condition to a static `FilterQuery`. Function conditions are called with a proxy `args`
|
|
46
|
+
* that yields a unique sentinel per accessed argument, real `type`/`entityName` strings (validated to not affect the
|
|
47
|
+
* result), and a poison proxy or `undefined` for the remaining runtime-only parameters.
|
|
48
|
+
*
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
static resolveRlsFilterCond(filter: FilterDef, accessed: Set<string>, entityName?: string): Dictionary;
|
|
40
52
|
static mergePropertyFilters(propFilters: FilterOptions | undefined, options: FilterOptions | undefined): FilterOptions | undefined;
|
|
41
53
|
static isFilterActive<T>(meta: EntityMetadata<T>, filterName: string, filter: FilterDef, options: Dictionary<boolean | Dictionary>): boolean;
|
|
42
54
|
static processCustomType<T extends object>(prop: EntityProperty<T>, cond: FilterQuery<T>, platform: Platform, key?: string, fromQuery?: boolean): FilterQuery<T>;
|
package/utils/QueryHelper.js
CHANGED
|
@@ -4,6 +4,7 @@ import { ARRAY_OPERATORS, GroupOperator, JSON_KEY_OPERATORS, ReferenceKind } fro
|
|
|
4
4
|
import { JsonType } from '../types/JsonType.js';
|
|
5
5
|
import { helper } from '../entity/wrap.js';
|
|
6
6
|
import { isRaw, Raw } from './RawQueryFragment.js';
|
|
7
|
+
import { MetadataError } from '../errors.js';
|
|
7
8
|
/** @internal */
|
|
8
9
|
export class QueryHelper {
|
|
9
10
|
static SUPPORTED_OPERATORS = ['>', '<', '<=', '>=', '!', '!='];
|
|
@@ -286,6 +287,68 @@ export class QueryHelper {
|
|
|
286
287
|
return filters[f];
|
|
287
288
|
});
|
|
288
289
|
}
|
|
290
|
+
/** @internal Sentinel wrapping for arguments accessed while statically resolving an `rls` filter condition. */
|
|
291
|
+
static RLS_SENTINEL_PREFIX = '__mikro_rls_arg__';
|
|
292
|
+
/** @internal */
|
|
293
|
+
static RLS_SENTINEL_SUFFIX = '__';
|
|
294
|
+
/**
|
|
295
|
+
* Resolves an `rls` filter's condition to a static `FilterQuery`. Function conditions are called with a proxy `args`
|
|
296
|
+
* that yields a unique sentinel per accessed argument, real `type`/`entityName` strings (validated to not affect the
|
|
297
|
+
* result), and a poison proxy or `undefined` for the remaining runtime-only parameters.
|
|
298
|
+
*
|
|
299
|
+
* @internal
|
|
300
|
+
*/
|
|
301
|
+
static resolveRlsFilterCond(filter, accessed, entityName) {
|
|
302
|
+
if (!(filter.cond instanceof Function)) {
|
|
303
|
+
return filter.cond;
|
|
304
|
+
}
|
|
305
|
+
const args = new Proxy({}, {
|
|
306
|
+
get: (_target, prop) => {
|
|
307
|
+
if (typeof prop === 'symbol') {
|
|
308
|
+
// e.g. coercing `args` itself in a template literal triggers a `Symbol.toPrimitive` lookup
|
|
309
|
+
throw MetadataError.rlsFilterUnsupportedCond(filter.name);
|
|
310
|
+
}
|
|
311
|
+
accessed.add(prop);
|
|
312
|
+
return `${this.RLS_SENTINEL_PREFIX}${prop}${this.RLS_SENTINEL_SUFFIX}`;
|
|
313
|
+
},
|
|
314
|
+
});
|
|
315
|
+
const poison = new Proxy({}, {
|
|
316
|
+
get: () => {
|
|
317
|
+
throw MetadataError.rlsFilterDependsOnRuntimeState(filter.name);
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
// property access on the poison proxies throws, but equality/truthiness checks (`type === 'read'`,
|
|
321
|
+
// `entityName === 'X'`, `options ? a : b`) cannot be trapped — vary all three across the evaluations and require
|
|
322
|
+
// identical results, so a command-, entity-, or options-dependent condition cannot silently compile one branch.
|
|
323
|
+
// `entityName` uses the real class name (plus two derived-distinct variants) so an `=== '<name>'` check diverges;
|
|
324
|
+
// `options` alternates the poison proxy and `undefined` so a truthiness check flips. `em` stays poison throughout.
|
|
325
|
+
const name = entityName ?? `${this.RLS_SENTINEL_PREFIX}entity${this.RLS_SENTINEL_SUFFIX}`;
|
|
326
|
+
const evaluate = (type, entity, options) => {
|
|
327
|
+
let result;
|
|
328
|
+
try {
|
|
329
|
+
result = filter.cond(args, type, poison, options, entity);
|
|
330
|
+
}
|
|
331
|
+
catch (e) {
|
|
332
|
+
// a raw TypeError from touching the `undefined` options/em must fail closed like the poison proxy does,
|
|
333
|
+
// but the descriptive MetadataErrors thrown above are already correct — let them surface unchanged
|
|
334
|
+
if (e instanceof MetadataError) {
|
|
335
|
+
throw e;
|
|
336
|
+
}
|
|
337
|
+
throw MetadataError.rlsFilterDependsOnRuntimeState(filter.name);
|
|
338
|
+
}
|
|
339
|
+
if (result instanceof Promise) {
|
|
340
|
+
throw MetadataError.rlsFilterDependsOnRuntimeState(filter.name);
|
|
341
|
+
}
|
|
342
|
+
return result;
|
|
343
|
+
};
|
|
344
|
+
const read = evaluate('read', name, poison);
|
|
345
|
+
const update = evaluate('update', `${name}\0a`, undefined);
|
|
346
|
+
const del = evaluate('delete', `${name}\0b`, poison);
|
|
347
|
+
if (JSON.stringify(read) !== JSON.stringify(update) || JSON.stringify(read) !== JSON.stringify(del)) {
|
|
348
|
+
throw MetadataError.rlsFilterDependsOnRuntimeState(filter.name);
|
|
349
|
+
}
|
|
350
|
+
return read;
|
|
351
|
+
}
|
|
289
352
|
static mergePropertyFilters(propFilters, options) {
|
|
290
353
|
if (!options || !propFilters || options === true || propFilters === true) {
|
|
291
354
|
return options ?? propFilters;
|
|
@@ -239,7 +239,7 @@ export class TransactionManager {
|
|
|
239
239
|
return TransactionContext.create(fork, () => fork.getConnection().transactional(async (trx) => {
|
|
240
240
|
fork.setTransactionContext(trx);
|
|
241
241
|
return this.executeTransactionFlow(fork, cb, propagateToUpperContext, em);
|
|
242
|
-
}, { ...options, eventBroadcaster }));
|
|
242
|
+
}, { sessionContext: fork.getTransactionSessionContext(), ...options, eventBroadcaster }));
|
|
243
243
|
}
|
|
244
244
|
/**
|
|
245
245
|
* Executes transaction workflow with entity synchronization.
|
package/utils/Utils.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export declare function parseJsonSafe<T = unknown>(value: unknown): T;
|
|
|
33
33
|
export declare class Utils {
|
|
34
34
|
#private;
|
|
35
35
|
static readonly PK_SEPARATOR = "~~~";
|
|
36
|
+
/** Default session variable name backing an RLS filter argument (`current_setting('mikro.<filter>.<arg>')`). */
|
|
37
|
+
static getRlsSettingName(filterName: string, argName: string): string;
|
|
36
38
|
/**
|
|
37
39
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
38
40
|
*/
|
package/utils/Utils.js
CHANGED
|
@@ -153,7 +153,11 @@ export function parseJsonSafe(value) {
|
|
|
153
153
|
/** Collection of general-purpose utility methods used throughout the ORM. */
|
|
154
154
|
export class Utils {
|
|
155
155
|
static PK_SEPARATOR = '~~~';
|
|
156
|
-
static #ORM_VERSION = '7.2.0-dev.
|
|
156
|
+
static #ORM_VERSION = '7.2.0-dev.16';
|
|
157
|
+
/** Default session variable name backing an RLS filter argument (`current_setting('mikro.<filter>.<arg>')`). */
|
|
158
|
+
static getRlsSettingName(filterName, argName) {
|
|
159
|
+
return `mikro.${filterName}.${argName}`;
|
|
160
|
+
}
|
|
157
161
|
/**
|
|
158
162
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
159
163
|
*/
|
package/utils/env-vars.js
CHANGED
|
@@ -88,6 +88,7 @@ export function loadEnvironmentVars() {
|
|
|
88
88
|
read3('createForeignKeyConstraints', bool);
|
|
89
89
|
read3('ignoreTriggers', bool);
|
|
90
90
|
read3('ignoreRoutines', bool);
|
|
91
|
+
read3('ignorePolicies', bool);
|
|
91
92
|
cleanup(ret, 'schemaGenerator');
|
|
92
93
|
ret.seeder = {};
|
|
93
94
|
const read4 = read.bind(null, ret.seeder, 'MIKRO_ORM_SEEDER_');
|
package/utils/index.d.ts
CHANGED
package/utils/index.js
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { MetadataStorage } from '../metadata/MetadataStorage.js';
|
|
2
|
+
import type { Dictionary, FilterDef } from '../typings.js';
|
|
3
|
+
/** An `rls`-flagged filter definition together with the entity it is declared on. @internal */
|
|
4
|
+
export interface RlsFilterEntry {
|
|
5
|
+
filter: FilterDef;
|
|
6
|
+
entityName: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Collects all `rls`-flagged filter definitions with the given name (only entity-scoped filters can be `rls`).
|
|
10
|
+
* The full name -> defs lookup is built once and cached on the shared (immutable) MetadataStorage, so repeated
|
|
11
|
+
* `setFilterParams` calls and forks reuse it instead of walking every entity each time.
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare function findRlsFilterDefs(metadata: MetadataStorage, name: string): RlsFilterEntry[];
|
|
15
|
+
/**
|
|
16
|
+
* Drops the cached `rls` filter lookup — `MikroORM.discoverEntity()` mutates the shared MetadataStorage,
|
|
17
|
+
* so a lookup built before the call would miss the newly discovered filters.
|
|
18
|
+
*
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export declare function clearRlsFilterDefsCache(metadata: MetadataStorage): void;
|
|
22
|
+
/**
|
|
23
|
+
* Computes the `rls` session variables a set of same-named filter defs stages for the given args, mirroring the
|
|
24
|
+
* policy compilation (`current_setting` names and custom `setting` binding). Shared by staging and `fork({ session })`.
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export declare function computeRlsFilterVariables(filters: RlsFilterEntry[], args: Dictionary): Dictionary<string | number | boolean | Date>;
|
|
28
|
+
/**
|
|
29
|
+
* Computes which staged session variables a `setFilterParams` call may prune: the variables the OLD args staged for
|
|
30
|
+
* this filter that the new args no longer set, minus any variable another filter's current params still stage
|
|
31
|
+
* (a custom `setting` name can be shared by differently named filters). Recomputing from the old args rather than
|
|
32
|
+
* matching by prefix keeps a filter named `tenant` from also pruning a `tenant.x` filter's `mikro.tenant.x.*` variables.
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function computeRemovedRlsVariables(metadata: MetadataStorage, name: string, filters: RlsFilterEntry[], previousArgs: Dictionary, nextVariables: Dictionary, allFilterParams: Dictionary<Dictionary>): string[];
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { MetadataError, ValidationError } from '../errors.js';
|
|
2
|
+
import { QueryHelper } from './QueryHelper.js';
|
|
3
|
+
import { Utils } from './Utils.js';
|
|
4
|
+
/** Lazily-built `rls` filter lookup keyed by the shared (immutable) MetadataStorage, so all forks reuse it. */
|
|
5
|
+
const rlsFilterDefs = new WeakMap();
|
|
6
|
+
/**
|
|
7
|
+
* Collects all `rls`-flagged filter definitions with the given name (only entity-scoped filters can be `rls`).
|
|
8
|
+
* The full name -> defs lookup is built once and cached on the shared (immutable) MetadataStorage, so repeated
|
|
9
|
+
* `setFilterParams` calls and forks reuse it instead of walking every entity each time.
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export function findRlsFilterDefs(metadata, name) {
|
|
13
|
+
let cache = rlsFilterDefs.get(metadata);
|
|
14
|
+
if (!cache) {
|
|
15
|
+
cache = new Map();
|
|
16
|
+
for (const meta of metadata) {
|
|
17
|
+
for (const filterName of Object.keys(meta.filters)) {
|
|
18
|
+
const filter = meta.filters[filterName];
|
|
19
|
+
if (!filter.rls) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const defs = cache.get(filterName) ?? [];
|
|
23
|
+
// inheritance shares the same filter object across base and child metadata — keep a single entry
|
|
24
|
+
if (!defs.some(d => d.filter === filter)) {
|
|
25
|
+
defs.push({ filter, entityName: meta.className });
|
|
26
|
+
}
|
|
27
|
+
cache.set(filterName, defs);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
rlsFilterDefs.set(metadata, cache);
|
|
31
|
+
}
|
|
32
|
+
return cache.get(name) ?? [];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Drops the cached `rls` filter lookup — `MikroORM.discoverEntity()` mutates the shared MetadataStorage,
|
|
36
|
+
* so a lookup built before the call would miss the newly discovered filters.
|
|
37
|
+
*
|
|
38
|
+
* @internal
|
|
39
|
+
*/
|
|
40
|
+
export function clearRlsFilterDefsCache(metadata) {
|
|
41
|
+
rlsFilterDefs.delete(metadata);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Computes the `rls` session variables a set of same-named filter defs stages for the given args, mirroring the
|
|
45
|
+
* policy compilation (`current_setting` names and custom `setting` binding). Shared by staging and `fork({ session })`.
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export function computeRlsFilterVariables(filters, args) {
|
|
49
|
+
const variables = {};
|
|
50
|
+
for (const { filter, entityName } of filters) {
|
|
51
|
+
const setting = typeof filter.rls === 'object' ? filter.rls.setting : undefined;
|
|
52
|
+
let settingArg;
|
|
53
|
+
if (setting) {
|
|
54
|
+
// mirror the policy compilation — a custom `setting` binds the single argument the condition accesses
|
|
55
|
+
const accessed = new Set();
|
|
56
|
+
QueryHelper.resolveRlsFilterCond(filter, accessed, entityName);
|
|
57
|
+
if (accessed.size > 1) {
|
|
58
|
+
throw MetadataError.rlsFilterMultiArgSetting(filter.name, [...accessed]);
|
|
59
|
+
}
|
|
60
|
+
settingArg = [...accessed][0];
|
|
61
|
+
}
|
|
62
|
+
for (const key of Object.keys(args)) {
|
|
63
|
+
const value = args[key];
|
|
64
|
+
// treat `undefined` like an omitted arg — staging it would serialize as the literal string 'undefined'
|
|
65
|
+
if (value === undefined) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
// a non-scalar arg has no equivalent in the compiled `= current_setting(...)` comparison — the app-level
|
|
69
|
+
// filter would apply `$in`/`is null` semantics while the policy compares against `String(value)`
|
|
70
|
+
if (value === null || (typeof value === 'object' && !(value instanceof Date))) {
|
|
71
|
+
throw ValidationError.cannotStageNonScalarSessionVariable(filter.name, key);
|
|
72
|
+
}
|
|
73
|
+
const settingName = key === settingArg ? setting : Utils.getRlsSettingName(filter.name, key);
|
|
74
|
+
variables[settingName] = value;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return variables;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Computes which staged session variables a `setFilterParams` call may prune: the variables the OLD args staged for
|
|
81
|
+
* this filter that the new args no longer set, minus any variable another filter's current params still stage
|
|
82
|
+
* (a custom `setting` name can be shared by differently named filters). Recomputing from the old args rather than
|
|
83
|
+
* matching by prefix keeps a filter named `tenant` from also pruning a `tenant.x` filter's `mikro.tenant.x.*` variables.
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
export function computeRemovedRlsVariables(metadata, name, filters, previousArgs, nextVariables, allFilterParams) {
|
|
87
|
+
const removed = Object.keys(computeRlsFilterVariables(filters, previousArgs)).filter(key => !(key in nextVariables));
|
|
88
|
+
const keptByOthers = new Set();
|
|
89
|
+
for (const otherName of removed.length > 0 ? Object.keys(allFilterParams) : []) {
|
|
90
|
+
if (otherName !== name) {
|
|
91
|
+
for (const key of Object.keys(computeRlsFilterVariables(findRlsFilterDefs(metadata, otherName), allFilterParams[otherName]))) {
|
|
92
|
+
keptByOthers.add(key);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return removed.filter(key => !keptByOthers.has(key));
|
|
97
|
+
}
|