@zmdb/orm 1.0.0-beta.1
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/LICENSE +674 -0
- package/README.md +30 -0
- package/dist/cache/index.d.ts +34 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +149 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/drivers/transactional.d.ts +6 -0
- package/dist/drivers/transactional.d.ts.map +1 -0
- package/dist/drivers/transactional.js +2 -0
- package/dist/drivers/transactional.js.map +1 -0
- package/dist/dto/index.d.ts +41 -0
- package/dist/dto/index.d.ts.map +1 -0
- package/dist/dto/index.js +334 -0
- package/dist/dto/index.js.map +1 -0
- package/dist/entity-modeling/index.d.ts +18 -0
- package/dist/entity-modeling/index.d.ts.map +1 -0
- package/dist/entity-modeling/index.js +26 -0
- package/dist/entity-modeling/index.js.map +1 -0
- package/dist/filters/index.d.ts +62 -0
- package/dist/filters/index.d.ts.map +1 -0
- package/dist/filters/index.js +163 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/index.d.ts +413 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2003 -0
- package/dist/index.js.map +1 -0
- package/dist/loaders/index.d.ts +38 -0
- package/dist/loaders/index.d.ts.map +1 -0
- package/dist/loaders/index.js +164 -0
- package/dist/loaders/index.js.map +1 -0
- package/dist/outbox/index.d.ts +59 -0
- package/dist/outbox/index.d.ts.map +1 -0
- package/dist/outbox/index.js +323 -0
- package/dist/outbox/index.js.map +1 -0
- package/dist/outbox/sql.d.ts +52 -0
- package/dist/outbox/sql.d.ts.map +1 -0
- package/dist/outbox/sql.js +115 -0
- package/dist/outbox/sql.js.map +1 -0
- package/dist/relations/index.d.ts +38 -0
- package/dist/relations/index.d.ts.map +1 -0
- package/dist/relations/index.js +164 -0
- package/dist/relations/index.js.map +1 -0
- package/dist/replicas/index.d.ts +10 -0
- package/dist/replicas/index.d.ts.map +1 -0
- package/dist/replicas/index.js +42 -0
- package/dist/replicas/index.js.map +1 -0
- package/dist/seeding/index.d.ts +18 -0
- package/dist/seeding/index.d.ts.map +1 -0
- package/dist/seeding/index.js +66 -0
- package/dist/seeding/index.js.map +1 -0
- package/dist/streaming/index.d.ts +7 -0
- package/dist/streaming/index.d.ts.map +1 -0
- package/dist/streaming/index.js +67 -0
- package/dist/streaming/index.js.map +1 -0
- package/dist/testing/official-dialects.fixture.d.ts +16 -0
- package/dist/testing/official-dialects.fixture.d.ts.map +1 -0
- package/dist/testing/official-dialects.fixture.js +21 -0
- package/dist/testing/official-dialects.fixture.js.map +1 -0
- package/dist/testing/repository.fixture.d.ts +11 -0
- package/dist/testing/repository.fixture.d.ts.map +1 -0
- package/dist/testing/repository.fixture.js +33 -0
- package/dist/testing/repository.fixture.js.map +1 -0
- package/dist/transactions/index.d.ts +40 -0
- package/dist/transactions/index.d.ts.map +1 -0
- package/dist/transactions/index.js +249 -0
- package/dist/transactions/index.js.map +1 -0
- package/dist/typed-populate/nested.fixtures.d.ts +34 -0
- package/dist/typed-populate/nested.fixtures.d.ts.map +1 -0
- package/dist/typed-populate/nested.fixtures.js +4 -0
- package/dist/typed-populate/nested.fixtures.js.map +1 -0
- package/package.json +78 -0
- package/src/cache/index.ts +188 -0
- package/src/drivers/transactional.ts +6 -0
- package/src/dto/index.ts +379 -0
- package/src/entity-modeling/index.ts +38 -0
- package/src/filters/index.ts +267 -0
- package/src/index.ts +2757 -0
- package/src/loaders/index.ts +256 -0
- package/src/outbox/index.ts +409 -0
- package/src/outbox/sql.ts +179 -0
- package/src/relations/index.ts +221 -0
- package/src/replicas/index.ts +51 -0
- package/src/seeding/index.ts +72 -0
- package/src/streaming/index.ts +67 -0
- package/src/testing/repository.fixture.ts +44 -0
- package/src/transactions/index.ts +315 -0
- package/src/typed-populate/nested.fixtures.ts +59 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type LifecycleEvent = 'beforeCreate' | 'afterCreate' | 'beforeUpdate' | 'afterUpdate' | 'beforeDelete' | 'afterDelete';
|
|
2
|
+
export interface Subscriber {
|
|
3
|
+
on: LifecycleEvent;
|
|
4
|
+
run: (ctx: unknown) => void | Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Sequential entity-lifecycle subscribers for repository write hooks.
|
|
8
|
+
*
|
|
9
|
+
* A failure intentionally stops the remaining subscribers and rejects the
|
|
10
|
+
* write, so this is not the application-event emitter. Use `createEvents` from
|
|
11
|
+
* `@zmdb/app/events` when handlers must run concurrently with isolated errors.
|
|
12
|
+
*/
|
|
13
|
+
export declare class EventBus {
|
|
14
|
+
private subs;
|
|
15
|
+
subscribe(s: Subscriber): () => void;
|
|
16
|
+
emit(event: LifecycleEvent, ctx: unknown): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/entity-modeling/index.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GACtB,cAAc,GACd,aAAa,GACb,cAAc,GACd,aAAa,GACb,cAAc,GACd,aAAa,CAAC;AAElB,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,cAAc,CAAC;IACnB,GAAG,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED;;;;;;GAMG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,IAAI,CAAoB;IAChC,SAAS,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,IAAI,CAMnC;IACK,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Entity modeling: lifecycle events — see ./SPEC.md.
|
|
2
|
+
/**
|
|
3
|
+
* Sequential entity-lifecycle subscribers for repository write hooks.
|
|
4
|
+
*
|
|
5
|
+
* A failure intentionally stops the remaining subscribers and rejects the
|
|
6
|
+
* write, so this is not the application-event emitter. Use `createEvents` from
|
|
7
|
+
* `@zmdb/app/events` when handlers must run concurrently with isolated errors.
|
|
8
|
+
*/
|
|
9
|
+
export class EventBus {
|
|
10
|
+
subs = [];
|
|
11
|
+
subscribe(s) {
|
|
12
|
+
this.subs.push(s);
|
|
13
|
+
return () => {
|
|
14
|
+
const i = this.subs.indexOf(s);
|
|
15
|
+
if (i >= 0)
|
|
16
|
+
this.subs.splice(i, 1);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
async emit(event, ctx) {
|
|
20
|
+
for (const s of this.subs) {
|
|
21
|
+
if (s.on === event)
|
|
22
|
+
await s.run(ctx);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/entity-modeling/index.ts"],"names":[],"mappings":"AAAA,qDAAqD;AAgBrD;;;;;;GAMG;AACH,MAAM,OAAO,QAAQ;IACX,IAAI,GAAiB,EAAE,CAAC;IAChC,SAAS,CAAC,CAAa;QACrB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrC,CAAC,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,KAAqB,EAAE,GAAY;QAC5C,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1B,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK;gBAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type CoreSchema } from '@zmdb/schema';
|
|
2
|
+
import { type Predicate } from '@zmdb/sql';
|
|
3
|
+
/** One compiler predicate contributed by a named repository filter. */
|
|
4
|
+
export interface FilterPredicate {
|
|
5
|
+
readonly col: string;
|
|
6
|
+
readonly op: string;
|
|
7
|
+
readonly value: unknown;
|
|
8
|
+
readonly connector?: 'AND' | 'OR';
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A named predicate applied to repository reads unless it is disabled for one call.
|
|
12
|
+
*
|
|
13
|
+
* `table` is optional for the repository's own table and explicit for a join or
|
|
14
|
+
* populate target. That keeps target filters scoped to this repository instance;
|
|
15
|
+
* there is no process-global registry.
|
|
16
|
+
*/
|
|
17
|
+
export interface FilterDef<P = void> {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
readonly table?: string;
|
|
20
|
+
/** Required for a target table unless the read supplies that table's schema directly. */
|
|
21
|
+
readonly schema?: CoreSchema<string>;
|
|
22
|
+
readonly where: {
|
|
23
|
+
bivarianceHack(params: P): readonly FilterPredicate[];
|
|
24
|
+
}['bivarianceHack'];
|
|
25
|
+
readonly enabled?: boolean;
|
|
26
|
+
readonly appliesToWrites?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export type FilterParams<F> = F extends {
|
|
29
|
+
readonly where: (params: infer P) => readonly FilterPredicate[];
|
|
30
|
+
} ? P : never;
|
|
31
|
+
export type FilterOverride<F> = [FilterParams<F>] extends [never] ? unknown | false : [FilterParams<F>] extends [void] ? false : FilterParams<F> | false;
|
|
32
|
+
export type FilterOverrides<Defs extends readonly FilterDef<unknown>[]> = {
|
|
33
|
+
readonly [Def in Defs[number] as Def['name']]?: FilterOverride<Def>;
|
|
34
|
+
};
|
|
35
|
+
export interface ResolvedFilters {
|
|
36
|
+
readonly names: readonly string[];
|
|
37
|
+
readonly predicates: readonly FilterPredicate[];
|
|
38
|
+
readonly groups: readonly {
|
|
39
|
+
readonly name: string;
|
|
40
|
+
readonly predicates: readonly FilterPredicate[];
|
|
41
|
+
}[];
|
|
42
|
+
}
|
|
43
|
+
export interface ResolveFiltersOptions {
|
|
44
|
+
readonly method: string;
|
|
45
|
+
readonly table: string;
|
|
46
|
+
readonly columnPrefix?: string;
|
|
47
|
+
readonly schema?: CoreSchema<string>;
|
|
48
|
+
readonly qualifyColumns?: boolean;
|
|
49
|
+
readonly knownNames?: readonly string[];
|
|
50
|
+
}
|
|
51
|
+
export interface FilterTarget {
|
|
52
|
+
where(col: string, op: string, value: unknown): this;
|
|
53
|
+
orWhere?(col: string, op: string, value: unknown): this;
|
|
54
|
+
whereGroup?(predicates: readonly FilterPredicate[]): this;
|
|
55
|
+
}
|
|
56
|
+
/** Resolve disables and parameters before a builder is allowed to compile. */
|
|
57
|
+
export declare function resolveFilters(definitions: readonly FilterDef<unknown>[], overrides: unknown, options: ResolveFiltersOptions): ResolvedFilters;
|
|
58
|
+
/** Preserve each filter's boolean boundary when it is placed in WHERE or JOIN ON. */
|
|
59
|
+
export declare function filtersAsPredicates(resolved: ResolvedFilters): readonly Predicate[];
|
|
60
|
+
/** Conjoin an already-resolved set with the predicates a read builder already carries. */
|
|
61
|
+
export declare function applyResolvedFilters<B extends FilterTarget>(builder: B, resolved: ResolvedFilters): B;
|
|
62
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/filters/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { isRecord } from '@zmdb/schema';
|
|
2
|
+
import { appTypeOf } from '@zmdb/schema/ir';
|
|
3
|
+
import {} from '@zmdb/sql';
|
|
4
|
+
import { issuesFor, ValidationError } from '@zmdb/validator';
|
|
5
|
+
function missingParameterError(filter, method, names) {
|
|
6
|
+
const required = names.length === 0 ? ['parameters'] : names;
|
|
7
|
+
const rendered = required.join(', ');
|
|
8
|
+
return new ValidationError(`filter \`${filter.name}\` requires parameters (${rendered}) and none were supplied; pass them per call — ` +
|
|
9
|
+
`${method}({ filters: { ${filter.name}: { ${rendered} } } }) — or disable it by name`);
|
|
10
|
+
}
|
|
11
|
+
function trackedObject(value, accessed) {
|
|
12
|
+
return new Proxy(value, {
|
|
13
|
+
get(target, property, receiver) {
|
|
14
|
+
if (typeof property === 'string')
|
|
15
|
+
accessed.add(property);
|
|
16
|
+
return Reflect.get(target, property, receiver);
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function parametersFor(filter, override, supplied, method) {
|
|
21
|
+
const accessed = new Set();
|
|
22
|
+
const rawParameters = supplied && override !== null && override !== undefined ? override : trackedObject(Object.create(null), accessed);
|
|
23
|
+
const parameters = isRecord(rawParameters) ? trackedObject(rawParameters, accessed) : rawParameters;
|
|
24
|
+
let predicates;
|
|
25
|
+
try {
|
|
26
|
+
predicates = filter.where(parameters);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (accessed.size > 0 &&
|
|
30
|
+
(!supplied || [...accessed].some(name => !isRecord(rawParameters) || rawParameters[name] == null))) {
|
|
31
|
+
throw missingParameterError(filter, method, [...accessed]);
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
const missing = [...accessed].filter(name => !isRecord(rawParameters) || rawParameters[name] == null);
|
|
36
|
+
if (!supplied && accessed.size > 0)
|
|
37
|
+
throw missingParameterError(filter, method, [...accessed]);
|
|
38
|
+
if (missing.length > 0)
|
|
39
|
+
throw missingParameterError(filter, method, missing);
|
|
40
|
+
return { predicates, accessed: [...accessed] };
|
|
41
|
+
}
|
|
42
|
+
function validatePredicate(filter, predicate, schema, accessed) {
|
|
43
|
+
if (!isRecord(predicate) || typeof predicate.col !== 'string' || typeof predicate.op !== 'string') {
|
|
44
|
+
throw new ValidationError(`filter \`${filter.name}\` returned an invalid predicate`);
|
|
45
|
+
}
|
|
46
|
+
if (predicate.connector !== undefined && predicate.connector !== 'AND' && predicate.connector !== 'OR') {
|
|
47
|
+
throw new ValidationError(`filter \`${filter.name}\` returned an invalid connector`);
|
|
48
|
+
}
|
|
49
|
+
const validationSchema = filter.schema ?? schema;
|
|
50
|
+
if (validationSchema === undefined) {
|
|
51
|
+
throw new ValidationError(`filter \`${filter.name}\` targets \`${filter.table}\` without a schema; provide FilterDef.schema so its columns and parameters can be validated`);
|
|
52
|
+
}
|
|
53
|
+
const columnName = predicate.col.slice(predicate.col.lastIndexOf('.') + 1);
|
|
54
|
+
const column = validationSchema.ir.columns.find(candidate => candidate.name === columnName);
|
|
55
|
+
if (column === undefined) {
|
|
56
|
+
throw new ValidationError(`filter \`${filter.name}\` names column \`${predicate.col}\`, which is not declared by \`${validationSchema.ir.table}\``);
|
|
57
|
+
}
|
|
58
|
+
const operator = predicate.op.toLowerCase().trim();
|
|
59
|
+
if (operator === 'is null' || operator === 'is not null')
|
|
60
|
+
return column;
|
|
61
|
+
if (predicate.value !== null &&
|
|
62
|
+
typeof predicate.value === 'object' &&
|
|
63
|
+
'compile' in predicate.value &&
|
|
64
|
+
typeof predicate.value.compile === 'function') {
|
|
65
|
+
return column;
|
|
66
|
+
}
|
|
67
|
+
const path = `filters.${filter.name}.${accessed[0] ?? columnName}`;
|
|
68
|
+
const values = (operator === 'in' || operator === 'not in' || operator === 'nin') && Array.isArray(predicate.value)
|
|
69
|
+
? predicate.value
|
|
70
|
+
: [predicate.value];
|
|
71
|
+
const issues = values.flatMap((value, index) => issuesFor(value, appTypeOf(column), values.length === 1 ? path : `${path}.${index}`));
|
|
72
|
+
if (issues.length > 0) {
|
|
73
|
+
throw new ValidationError(`validation failed: ${issues.map(issue => issue.path).join(', ')}`, issues);
|
|
74
|
+
}
|
|
75
|
+
return column;
|
|
76
|
+
}
|
|
77
|
+
/** Resolve disables and parameters before a builder is allowed to compile. */
|
|
78
|
+
export function resolveFilters(definitions, overrides, options) {
|
|
79
|
+
const values = overrides === undefined ? undefined : isRecord(overrides) ? overrides : undefined;
|
|
80
|
+
if (overrides !== undefined && values === undefined) {
|
|
81
|
+
throw new ValidationError('filters must be an object keyed by declared filter name');
|
|
82
|
+
}
|
|
83
|
+
const knownNames = new Set(options.knownNames ?? definitions.map(filter => filter.name));
|
|
84
|
+
for (const name of Object.keys(values ?? {})) {
|
|
85
|
+
if (!knownNames.has(name)) {
|
|
86
|
+
const declared = [...knownNames].toSorted();
|
|
87
|
+
throw new ValidationError(`unknown filter \`${name}\`; declared filters: ${declared.length === 0 ? '(none)' : declared.join(', ')}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const names = [];
|
|
91
|
+
const predicates = [];
|
|
92
|
+
const groups = [];
|
|
93
|
+
for (const filter of definitions) {
|
|
94
|
+
const supplied = values !== undefined && Object.hasOwn(values, filter.name);
|
|
95
|
+
const override = supplied ? values[filter.name] : undefined;
|
|
96
|
+
if (override === false || (!supplied && filter.enabled === false))
|
|
97
|
+
continue;
|
|
98
|
+
const resolved = parametersFor(filter, override, supplied, options.method);
|
|
99
|
+
if (!Array.isArray(resolved.predicates) || resolved.predicates.length === 0) {
|
|
100
|
+
throw new ValidationError(`filter \`${filter.name}\` returned no predicates`);
|
|
101
|
+
}
|
|
102
|
+
names.push(filter.name);
|
|
103
|
+
const group = [];
|
|
104
|
+
for (let index = 0; index < resolved.predicates.length; index++) {
|
|
105
|
+
const predicate = resolved.predicates[index];
|
|
106
|
+
if (predicate === undefined)
|
|
107
|
+
throw new ValidationError(`filter \`${filter.name}\` returned an empty predicate`);
|
|
108
|
+
const column = validatePredicate(filter, predicate, options.schema, resolved.accessed);
|
|
109
|
+
const separator = predicate.col.lastIndexOf('.');
|
|
110
|
+
const physicalColumn = separator === -1 ? column.physicalName : `${predicate.col.slice(0, separator + 1)}${column.physicalName}`;
|
|
111
|
+
const col = options.qualifyColumns === true && separator === -1
|
|
112
|
+
? `${options.columnPrefix ?? options.table}.${physicalColumn}`
|
|
113
|
+
: physicalColumn;
|
|
114
|
+
const qualified = {
|
|
115
|
+
...predicate,
|
|
116
|
+
col,
|
|
117
|
+
connector: index === 0 ? 'AND' : (predicate.connector ?? 'AND'),
|
|
118
|
+
};
|
|
119
|
+
predicates.push(qualified);
|
|
120
|
+
group.push(qualified);
|
|
121
|
+
}
|
|
122
|
+
groups.push({ name: filter.name, predicates: Object.freeze(group) });
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
names: Object.freeze([...new Set(names)]),
|
|
126
|
+
predicates: Object.freeze(predicates),
|
|
127
|
+
groups: Object.freeze(groups),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function needsGrouping(predicates) {
|
|
131
|
+
return predicates.some((predicate, index) => index > 0 && predicate.connector === 'OR');
|
|
132
|
+
}
|
|
133
|
+
/** Preserve each filter's boolean boundary when it is placed in WHERE or JOIN ON. */
|
|
134
|
+
export function filtersAsPredicates(resolved) {
|
|
135
|
+
const predicates = [];
|
|
136
|
+
for (const group of resolved.groups) {
|
|
137
|
+
if (needsGrouping(group.predicates)) {
|
|
138
|
+
predicates.push({ kind: 'group', predicates: group.predicates, connector: 'AND' });
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
predicates.push(...group.predicates);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return Object.freeze(predicates);
|
|
145
|
+
}
|
|
146
|
+
/** Conjoin an already-resolved set with the predicates a read builder already carries. */
|
|
147
|
+
export function applyResolvedFilters(builder, resolved) {
|
|
148
|
+
let filtered = builder;
|
|
149
|
+
for (const group of resolved.groups) {
|
|
150
|
+
if (needsGrouping(group.predicates)) {
|
|
151
|
+
if (filtered.whereGroup === undefined) {
|
|
152
|
+
throw new ValidationError('this statement builder cannot represent a grouped filter predicate');
|
|
153
|
+
}
|
|
154
|
+
filtered = filtered.whereGroup(group.predicates);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
for (const predicate of group.predicates) {
|
|
158
|
+
filtered = filtered.where(predicate.col, predicate.op, predicate.value);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return filtered;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/filters/index.ts"],"names":[],"mappings":"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"}
|