@nest-yalc-2/omnikernel-module 1.1.0
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 +661 -0
- package/README.md +193 -0
- package/package.json +52 -0
- package/src/__tests__/omni-collection.entity.spec.ts +49 -0
- package/src/__tests__/omni-collection.service.spec.ts +83 -0
- package/src/__tests__/omni-document.entity.spec.ts +55 -0
- package/src/__tests__/omni-document.service.spec.ts +83 -0
- package/src/__tests__/omni-extension-projection-constraints.spec.ts +518 -0
- package/src/__tests__/omni-extension-projection.registration.spec.ts +946 -0
- package/src/__tests__/omni-extension-projection.service.spec.ts +806 -0
- package/src/__tests__/omni-external-ref.entity.spec.ts +36 -0
- package/src/__tests__/omni-external-ref.service.spec.ts +252 -0
- package/src/__tests__/omni-named.entity.spec.ts +33 -0
- package/src/__tests__/omni-record.entity.spec.ts +32 -0
- package/src/__tests__/omni-record.service.spec.ts +107 -0
- package/src/__tests__/omni-relation-semantics.spec.ts +102 -0
- package/src/__tests__/omni-relation.entity.spec.ts +38 -0
- package/src/__tests__/omni-scope-substrate.spec.ts +81 -0
- package/src/__tests__/omni-scoped.backend.spec.ts +115 -0
- package/src/__tests__/omni-scoped.service.spec.ts +354 -0
- package/src/__tests__/omnikernel.diagnostics.spec.ts +94 -0
- package/src/__tests__/omnikernel.module.spec.ts +40 -0
- package/src/__tests__/omnikernel.persistence.spec.ts +154 -0
- package/src/__tests__/omnikernel.public-api.spec.ts +238 -0
- package/src/__tests__/omnikernel.query.service.spec.ts +155 -0
- package/src/__tests__/tsconfig.json +6 -0
- package/src/base/omni-base.entity.d.ts +9 -0
- package/src/base/omni-base.entity.js +53 -0
- package/src/base/omni-base.entity.js.map +1 -0
- package/src/base/omni-base.entity.ts +41 -0
- package/src/base/omni-external-ref.entity.d.ts +13 -0
- package/src/base/omni-external-ref.entity.js +72 -0
- package/src/base/omni-external-ref.entity.js.map +1 -0
- package/src/base/omni-external-ref.entity.ts +53 -0
- package/src/base/omni-named.entity.d.ts +6 -0
- package/src/base/omni-named.entity.js +35 -0
- package/src/base/omni-named.entity.js.map +1 -0
- package/src/base/omni-named.entity.ts +16 -0
- package/src/base/omni-record.entity.d.ts +13 -0
- package/src/base/omni-record.entity.js +71 -0
- package/src/base/omni-record.entity.js.map +1 -0
- package/src/base/omni-record.entity.ts +51 -0
- package/src/base/omni-relation.entity.d.ts +15 -0
- package/src/base/omni-relation.entity.js +91 -0
- package/src/base/omni-relation.entity.js.map +1 -0
- package/src/base/omni-relation.entity.ts +72 -0
- package/src/index.d.ts +49 -0
- package/src/index.js +66 -0
- package/src/index.js.map +1 -0
- package/src/index.ts +49 -0
- package/src/omni-collection-kind.enum.d.ts +4 -0
- package/src/omni-collection-kind.enum.js +13 -0
- package/src/omni-collection-kind.enum.js.map +1 -0
- package/src/omni-collection-kind.enum.ts +10 -0
- package/src/omni-collection.backend.d.ts +2 -0
- package/src/omni-collection.backend.js +15 -0
- package/src/omni-collection.backend.js.map +1 -0
- package/src/omni-collection.backend.ts +16 -0
- package/src/omni-collection.dto.d.ts +32 -0
- package/src/omni-collection.dto.js +184 -0
- package/src/omni-collection.dto.js.map +1 -0
- package/src/omni-collection.dto.ts +170 -0
- package/src/omni-collection.entity.d.ts +7 -0
- package/src/omni-collection.entity.js +41 -0
- package/src/omni-collection.entity.js.map +1 -0
- package/src/omni-collection.entity.ts +21 -0
- package/src/omni-collection.service.d.ts +14 -0
- package/src/omni-collection.service.js +24 -0
- package/src/omni-collection.service.js.map +1 -0
- package/src/omni-collection.service.ts +75 -0
- package/src/omni-document-kind.enum.d.ts +6 -0
- package/src/omni-document-kind.enum.js +15 -0
- package/src/omni-document-kind.enum.js.map +1 -0
- package/src/omni-document-kind.enum.ts +12 -0
- package/src/omni-document.backend.d.ts +2 -0
- package/src/omni-document.backend.js +15 -0
- package/src/omni-document.backend.js.map +1 -0
- package/src/omni-document.backend.ts +16 -0
- package/src/omni-document.dto.d.ts +35 -0
- package/src/omni-document.dto.js +213 -0
- package/src/omni-document.dto.js.map +1 -0
- package/src/omni-document.dto.ts +198 -0
- package/src/omni-document.entity.d.ts +10 -0
- package/src/omni-document.entity.js +53 -0
- package/src/omni-document.entity.js.map +1 -0
- package/src/omni-document.entity.ts +30 -0
- package/src/omni-document.service.d.ts +14 -0
- package/src/omni-document.service.js +24 -0
- package/src/omni-document.service.js.map +1 -0
- package/src/omni-document.service.ts +75 -0
- package/src/omni-dto.helpers.d.ts +1 -0
- package/src/omni-dto.helpers.js +10 -0
- package/src/omni-dto.helpers.js.map +1 -0
- package/src/omni-dto.helpers.ts +21 -0
- package/src/omni-extension-projection.definition.d.ts +17 -0
- package/src/omni-extension-projection.definition.js +160 -0
- package/src/omni-extension-projection.definition.js.map +1 -0
- package/src/omni-extension-projection.definition.ts +294 -0
- package/src/omni-extension-projection.resource.d.ts +42 -0
- package/src/omni-extension-projection.resource.js +127 -0
- package/src/omni-extension-projection.resource.js.map +1 -0
- package/src/omni-extension-projection.resource.ts +274 -0
- package/src/omni-extension-projection.service.d.ts +33 -0
- package/src/omni-extension-projection.service.js +332 -0
- package/src/omni-extension-projection.service.js.map +1 -0
- package/src/omni-extension-projection.service.ts +452 -0
- package/src/omni-external-ref-binding.validator.d.ts +14 -0
- package/src/omni-external-ref-binding.validator.js +34 -0
- package/src/omni-external-ref-binding.validator.js.map +1 -0
- package/src/omni-external-ref-binding.validator.ts +53 -0
- package/src/omni-external-ref-internal-type.enum.d.ts +5 -0
- package/src/omni-external-ref-internal-type.enum.js +14 -0
- package/src/omni-external-ref-internal-type.enum.js.map +1 -0
- package/src/omni-external-ref-internal-type.enum.ts +11 -0
- package/src/omni-external-ref.backend.d.ts +2 -0
- package/src/omni-external-ref.backend.js +19 -0
- package/src/omni-external-ref.backend.js.map +1 -0
- package/src/omni-external-ref.backend.ts +25 -0
- package/src/omni-external-ref.dto.d.ts +26 -0
- package/src/omni-external-ref.dto.js +140 -0
- package/src/omni-external-ref.dto.js.map +1 -0
- package/src/omni-external-ref.dto.ts +128 -0
- package/src/omni-external-ref.service.d.ts +33 -0
- package/src/omni-external-ref.service.js +133 -0
- package/src/omni-external-ref.service.js.map +1 -0
- package/src/omni-external-ref.service.ts +255 -0
- package/src/omni-migration.d.ts +28 -0
- package/src/omni-migration.js +239 -0
- package/src/omni-migration.js.map +1 -0
- package/src/omni-migration.ts +365 -0
- package/src/omni-named.backend.d.ts +2 -0
- package/src/omni-named.backend.js +13 -0
- package/src/omni-named.backend.js.map +1 -0
- package/src/omni-named.backend.ts +11 -0
- package/src/omni-named.dto.d.ts +19 -0
- package/src/omni-named.dto.js +94 -0
- package/src/omni-named.dto.js.map +1 -0
- package/src/omni-named.dto.ts +86 -0
- package/src/omni-projection.catalog.d.ts +49 -0
- package/src/omni-projection.catalog.js +177 -0
- package/src/omni-projection.catalog.js.map +1 -0
- package/src/omni-projection.catalog.ts +345 -0
- package/src/omni-projection.lifecycle.d.ts +20 -0
- package/src/omni-projection.lifecycle.js +3 -0
- package/src/omni-projection.lifecycle.js.map +1 -0
- package/src/omni-projection.lifecycle.ts +53 -0
- package/src/omni-record-status.enum.d.ts +5 -0
- package/src/omni-record-status.enum.js +14 -0
- package/src/omni-record-status.enum.js.map +1 -0
- package/src/omni-record-status.enum.ts +11 -0
- package/src/omni-record.backend.d.ts +2 -0
- package/src/omni-record.backend.js +13 -0
- package/src/omni-record.backend.js.map +1 -0
- package/src/omni-record.backend.ts +19 -0
- package/src/omni-record.dto.d.ts +29 -0
- package/src/omni-record.dto.js +169 -0
- package/src/omni-record.dto.js.map +1 -0
- package/src/omni-record.dto.ts +157 -0
- package/src/omni-record.service.d.ts +18 -0
- package/src/omni-record.service.js +45 -0
- package/src/omni-record.service.js.map +1 -0
- package/src/omni-record.service.ts +113 -0
- package/src/omni-relation-kind.contract.d.ts +9 -0
- package/src/omni-relation-kind.contract.js +33 -0
- package/src/omni-relation-kind.contract.js.map +1 -0
- package/src/omni-relation-kind.contract.ts +49 -0
- package/src/omni-relation-kind.enum.d.ts +6 -0
- package/src/omni-relation-kind.enum.js +15 -0
- package/src/omni-relation-kind.enum.js.map +1 -0
- package/src/omni-relation-kind.enum.ts +12 -0
- package/src/omni-relation-projection.definition.d.ts +25 -0
- package/src/omni-relation-projection.definition.js +83 -0
- package/src/omni-relation-projection.definition.js.map +1 -0
- package/src/omni-relation-projection.definition.ts +166 -0
- package/src/omni-relation-projection.resource.d.ts +51 -0
- package/src/omni-relation-projection.resource.js +203 -0
- package/src/omni-relation-projection.resource.js.map +1 -0
- package/src/omni-relation-projection.resource.ts +360 -0
- package/src/omni-relation-projection.service.d.ts +47 -0
- package/src/omni-relation-projection.service.js +385 -0
- package/src/omni-relation-projection.service.js.map +1 -0
- package/src/omni-relation-projection.service.ts +610 -0
- package/src/omni-relation-semantics.d.ts +11 -0
- package/src/omni-relation-semantics.js +34 -0
- package/src/omni-relation-semantics.js.map +1 -0
- package/src/omni-relation-semantics.ts +52 -0
- package/src/omni-relation-status.enum.d.ts +5 -0
- package/src/omni-relation-status.enum.js +14 -0
- package/src/omni-relation-status.enum.js.map +1 -0
- package/src/omni-relation-status.enum.ts +11 -0
- package/src/omni-relation.backend.d.ts +2 -0
- package/src/omni-relation.backend.js +17 -0
- package/src/omni-relation.backend.js.map +1 -0
- package/src/omni-relation.backend.ts +21 -0
- package/src/omni-relation.dto.d.ts +28 -0
- package/src/omni-relation.dto.js +153 -0
- package/src/omni-relation.dto.js.map +1 -0
- package/src/omni-relation.dto.ts +142 -0
- package/src/omni-relation.service.d.ts +19 -0
- package/src/omni-relation.service.js +76 -0
- package/src/omni-relation.service.js.map +1 -0
- package/src/omni-relation.service.ts +159 -0
- package/src/omni-scope.d.ts +33 -0
- package/src/omni-scope.js +91 -0
- package/src/omni-scope.js.map +1 -0
- package/src/omni-scope.ts +161 -0
- package/src/omni-scoped.backend.d.ts +21 -0
- package/src/omni-scoped.backend.js +47 -0
- package/src/omni-scoped.backend.js.map +1 -0
- package/src/omni-scoped.backend.ts +110 -0
- package/src/omni-scoped.repository.d.ts +10 -0
- package/src/omni-scoped.repository.js +26 -0
- package/src/omni-scoped.repository.js.map +1 -0
- package/src/omni-scoped.repository.ts +34 -0
- package/src/omni-scoped.service.d.ts +36 -0
- package/src/omni-scoped.service.js +171 -0
- package/src/omni-scoped.service.js.map +1 -0
- package/src/omni-scoped.service.ts +338 -0
- package/src/omnikernel.diagnostics.d.ts +16 -0
- package/src/omnikernel.diagnostics.js +50 -0
- package/src/omnikernel.diagnostics.js.map +1 -0
- package/src/omnikernel.diagnostics.ts +83 -0
- package/src/omnikernel.module.d.ts +5 -0
- package/src/omnikernel.module.js +87 -0
- package/src/omnikernel.module.js.map +1 -0
- package/src/omnikernel.module.ts +97 -0
- package/src/omnikernel.query.service.d.ts +17 -0
- package/src/omnikernel.query.service.js +85 -0
- package/src/omnikernel.query.service.js.map +1 -0
- package/src/omnikernel.query.service.ts +108 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OMNI_PROJECTION_READER_CATALOG = void 0;
|
|
4
|
+
exports.createOmniProjectionReaderCatalog = createOmniProjectionReaderCatalog;
|
|
5
|
+
exports.createOmniProjectionReaderCatalogProvider = createOmniProjectionReaderCatalogProvider;
|
|
6
|
+
const crud_gen_1 = require("@nest-yalc-2/crud-gen");
|
|
7
|
+
const typeorm_1 = require("typeorm");
|
|
8
|
+
const omni_record_entity_js_1 = require("./base/omni-record.entity.js");
|
|
9
|
+
const omni_relation_entity_js_1 = require("./base/omni-relation.entity.js");
|
|
10
|
+
const omni_relation_projection_definition_js_1 = require("./omni-relation-projection.definition.js");
|
|
11
|
+
const omni_relation_status_enum_js_1 = require("./omni-relation-status.enum.js");
|
|
12
|
+
exports.OMNI_PROJECTION_READER_CATALOG = Symbol('OMNI_PROJECTION_READER_CATALOG');
|
|
13
|
+
function freeze(value) {
|
|
14
|
+
if (value && typeof value === 'object')
|
|
15
|
+
Object.freeze(value);
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
function validateReaderTake(take) {
|
|
19
|
+
if (take === undefined)
|
|
20
|
+
return undefined;
|
|
21
|
+
if (!Number.isInteger(take) || take < 1 || take > 1_000) {
|
|
22
|
+
throw new TypeError('Omni projection reader take must be an integer from 1 to 1000.');
|
|
23
|
+
}
|
|
24
|
+
return take;
|
|
25
|
+
}
|
|
26
|
+
function relationWhere(definition) {
|
|
27
|
+
const relation = definition.relation;
|
|
28
|
+
return {
|
|
29
|
+
kind: (0, typeorm_1.In)([...(0, omni_relation_projection_definition_js_1.getOmniRelationProjectionAllowedKinds)(definition)]),
|
|
30
|
+
status: relation.status ?? omni_relation_status_enum_js_1.OmniRelationStatus.Active,
|
|
31
|
+
...(relation.schema
|
|
32
|
+
? {
|
|
33
|
+
payloadSchemaId: relation.schema.id,
|
|
34
|
+
payloadSchemaVersion: relation.schema.version,
|
|
35
|
+
}
|
|
36
|
+
: {
|
|
37
|
+
payloadSchemaId: (0, typeorm_1.IsNull)(),
|
|
38
|
+
payloadSchemaVersion: (0, typeorm_1.IsNull)(),
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function extensionReader(manager, scope, registration) {
|
|
43
|
+
const ownerWhere = {
|
|
44
|
+
scopeId: scope.scopeId,
|
|
45
|
+
kind: registration.definition.owner.kind,
|
|
46
|
+
payloadSchemaId: registration.definition.owner.schema.id,
|
|
47
|
+
payloadSchemaVersion: registration.definition.owner.schema.version,
|
|
48
|
+
deletedAt: (0, typeorm_1.IsNull)(),
|
|
49
|
+
};
|
|
50
|
+
const extensionRepository = manager.getRepository(registration.entity);
|
|
51
|
+
const ownerRepository = manager.getRepository(omni_record_entity_js_1.OmniRecordEntity);
|
|
52
|
+
const identity = registration.definition.identity.column;
|
|
53
|
+
const scopeColumn = registration.definition.scope.column;
|
|
54
|
+
const project = (entity, owner) => {
|
|
55
|
+
const projected = {
|
|
56
|
+
...entity,
|
|
57
|
+
scopeId: owner.scopeId,
|
|
58
|
+
guid: owner.guid,
|
|
59
|
+
[registration.definition.revision.column]: owner.revision,
|
|
60
|
+
createdAt: owner.createdAt,
|
|
61
|
+
updatedAt: owner.updatedAt,
|
|
62
|
+
deletedAt: owner.deletedAt,
|
|
63
|
+
};
|
|
64
|
+
return projected;
|
|
65
|
+
};
|
|
66
|
+
const getOwner = async (guid) => {
|
|
67
|
+
const owner = await ownerRepository.findOne({
|
|
68
|
+
where: { ...ownerWhere, guid },
|
|
69
|
+
});
|
|
70
|
+
return owner ?? undefined;
|
|
71
|
+
};
|
|
72
|
+
const dialect = (() => {
|
|
73
|
+
const type = manager.connection.options.type;
|
|
74
|
+
if (type !== 'sqlite' && type !== 'postgres') {
|
|
75
|
+
throw new TypeError('Omni projection readers require SQLite or PostgreSQL.');
|
|
76
|
+
}
|
|
77
|
+
return (0, crud_gen_1.createProjectionDialect)(type);
|
|
78
|
+
})();
|
|
79
|
+
const filtersFor = (where) => {
|
|
80
|
+
const filters = [];
|
|
81
|
+
for (const [fieldName, value] of Object.entries(where ?? {})) {
|
|
82
|
+
const field = registration.definition.fields.find((candidate) => candidate.name === fieldName);
|
|
83
|
+
if (!field || !field.query?.filter?.includes('eq')) {
|
|
84
|
+
throw new TypeError(`Omni extension reader only permits declared eq fields: ${fieldName}.`);
|
|
85
|
+
}
|
|
86
|
+
filters.push({ field, operator: 'eq', values: [value] });
|
|
87
|
+
}
|
|
88
|
+
return filters;
|
|
89
|
+
};
|
|
90
|
+
const projectMany = async (entities) => {
|
|
91
|
+
if (entities.length === 0)
|
|
92
|
+
return [];
|
|
93
|
+
const candidates = entities.map((entity) => entity[identity]);
|
|
94
|
+
const guids = candidates.filter((guid) => typeof guid === 'string');
|
|
95
|
+
const owners = await ownerRepository.find({
|
|
96
|
+
where: { ...ownerWhere, guid: (0, typeorm_1.In)(guids) },
|
|
97
|
+
});
|
|
98
|
+
const ownersByGuid = new Map(owners.map((owner) => [owner.guid, owner]));
|
|
99
|
+
return entities.flatMap((entity) => {
|
|
100
|
+
const guid = entity[identity];
|
|
101
|
+
const owner = typeof guid === 'string' ? ownersByGuid.get(guid) : undefined;
|
|
102
|
+
return owner ? [project(entity, owner)] : [];
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
return freeze({
|
|
106
|
+
async get(guid) {
|
|
107
|
+
const entity = await extensionRepository.findOne({
|
|
108
|
+
where: { [scopeColumn]: scope.scopeId, [identity]: guid },
|
|
109
|
+
});
|
|
110
|
+
if (!entity)
|
|
111
|
+
return undefined;
|
|
112
|
+
const owner = await getOwner(guid);
|
|
113
|
+
return owner ? project(entity, owner) : undefined;
|
|
114
|
+
},
|
|
115
|
+
async list(options = {}) {
|
|
116
|
+
const [entities] = await dialect.findMany(extensionRepository, registration.definition, scope.scopeId, filtersFor(options.where), [], { take: validateReaderTake(options.take) });
|
|
117
|
+
return projectMany(entities);
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function relationReader(manager, scope, registration) {
|
|
122
|
+
const repository = manager.getRepository(omni_relation_entity_js_1.OmniRelationEntity);
|
|
123
|
+
const fixed = relationWhere(registration.definition);
|
|
124
|
+
return freeze({
|
|
125
|
+
async get(guid) {
|
|
126
|
+
const entity = await repository.findOne({
|
|
127
|
+
where: { scopeId: scope.scopeId, guid, ...fixed },
|
|
128
|
+
});
|
|
129
|
+
return entity ?? undefined;
|
|
130
|
+
},
|
|
131
|
+
async list(options = {}) {
|
|
132
|
+
const { take, ...conditions } = options;
|
|
133
|
+
return await repository.find({
|
|
134
|
+
where: { scopeId: scope.scopeId, ...fixed, ...conditions },
|
|
135
|
+
take: validateReaderTake(take),
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function createOmniProjectionReaderCatalog(registrations) {
|
|
141
|
+
const byId = new Map();
|
|
142
|
+
for (const source of registrations) {
|
|
143
|
+
const registration = 'reader' in source ? source.reader : source;
|
|
144
|
+
if (!registration.id || byId.has(registration.id)) {
|
|
145
|
+
throw new TypeError('Omni projection reader registrations must have unique non-empty ids.');
|
|
146
|
+
}
|
|
147
|
+
byId.set(registration.id, registration);
|
|
148
|
+
}
|
|
149
|
+
const snapshot = freeze(new Map(byId));
|
|
150
|
+
return freeze({
|
|
151
|
+
bind(manager, scope) {
|
|
152
|
+
return freeze({
|
|
153
|
+
extension(id) {
|
|
154
|
+
const registration = snapshot.get(id);
|
|
155
|
+
if (!registration || registration.type !== 'extension') {
|
|
156
|
+
throw new TypeError(`Omni extension projection reader is not registered: ${id}.`);
|
|
157
|
+
}
|
|
158
|
+
return extensionReader(manager, scope, registration);
|
|
159
|
+
},
|
|
160
|
+
relation(id) {
|
|
161
|
+
const registration = snapshot.get(id);
|
|
162
|
+
if (!registration || registration.type !== 'relation') {
|
|
163
|
+
throw new TypeError(`Omni relation projection reader is not registered: ${id}.`);
|
|
164
|
+
}
|
|
165
|
+
return relationReader(manager, scope, registration);
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function createOmniProjectionReaderCatalogProvider(registrations, token = exports.OMNI_PROJECTION_READER_CATALOG) {
|
|
172
|
+
return {
|
|
173
|
+
provide: token,
|
|
174
|
+
useValue: createOmniProjectionReaderCatalog(registrations),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=omni-projection.catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"omni-projection.catalog.js","sourceRoot":"","sources":["omni-projection.catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createProjectionDialect,
|
|
3
|
+
type ProjectionFilter,
|
|
4
|
+
} from '@nest-yalc-2/crud-gen';
|
|
5
|
+
import type { InjectionToken, Provider } from '@nestjs/common';
|
|
6
|
+
import {
|
|
7
|
+
In,
|
|
8
|
+
IsNull,
|
|
9
|
+
type EntityManager,
|
|
10
|
+
type EntityTarget,
|
|
11
|
+
type ObjectLiteral,
|
|
12
|
+
} from 'typeorm';
|
|
13
|
+
import { OmniRecordEntity } from './base/omni-record.entity.js';
|
|
14
|
+
import { OmniRelationEntity } from './base/omni-relation.entity.js';
|
|
15
|
+
import type { OmniExtensionProjectionDefinition } from './omni-extension-projection.definition.js';
|
|
16
|
+
import {
|
|
17
|
+
getOmniRelationProjectionAllowedKinds,
|
|
18
|
+
type OmniRelationProjectionDefinition,
|
|
19
|
+
} from './omni-relation-projection.definition.js';
|
|
20
|
+
import { OmniRelationStatus } from './omni-relation-status.enum.js';
|
|
21
|
+
import type { OmniScope } from './omni-scope.js';
|
|
22
|
+
|
|
23
|
+
export interface OmniExtensionProjectionReaderRegistration<
|
|
24
|
+
Entity extends ObjectLiteral = ObjectLiteral,
|
|
25
|
+
> {
|
|
26
|
+
readonly type: 'extension';
|
|
27
|
+
readonly id: string;
|
|
28
|
+
readonly entity: EntityTarget<Entity>;
|
|
29
|
+
readonly definition: OmniExtensionProjectionDefinition;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface OmniRelationProjectionReaderRegistration {
|
|
33
|
+
readonly type: 'relation';
|
|
34
|
+
readonly id: string;
|
|
35
|
+
readonly definition: OmniRelationProjectionDefinition;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type OmniProjectionReaderRegistration =
|
|
39
|
+
| OmniExtensionProjectionReaderRegistration
|
|
40
|
+
| OmniRelationProjectionReaderRegistration;
|
|
41
|
+
|
|
42
|
+
export interface OmniExtensionProjectionReader<
|
|
43
|
+
Entity extends ObjectLiteral = ObjectLiteral,
|
|
44
|
+
> {
|
|
45
|
+
get(guid: string): Promise<Entity | undefined>;
|
|
46
|
+
list(options?: {
|
|
47
|
+
/** Equality only, on declared fields that explicitly allow eq filtering. */
|
|
48
|
+
where?: Readonly<Record<string, unknown>>;
|
|
49
|
+
/** A bounded result size; policies commonly use take: 1 for existence. */
|
|
50
|
+
take?: number;
|
|
51
|
+
}): Promise<Entity[]>;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface OmniRelationProjectionReader {
|
|
55
|
+
get(guid: string): Promise<OmniRelationEntity | undefined>;
|
|
56
|
+
list(options?: {
|
|
57
|
+
sourceRecordId?: string;
|
|
58
|
+
targetRecordId?: string;
|
|
59
|
+
/** A bounded result size for edge-existence checks. */
|
|
60
|
+
take?: number;
|
|
61
|
+
}): Promise<OmniRelationEntity[]>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Manager-bound readers available to a lifecycle policy. They intentionally
|
|
66
|
+
* expose projection identities and constrained graph records, never TypeORM
|
|
67
|
+
* repositories or query runners.
|
|
68
|
+
*/
|
|
69
|
+
export interface OmniProjectionTransactionReaders {
|
|
70
|
+
extension<Entity extends ObjectLiteral = ObjectLiteral>(
|
|
71
|
+
id: string,
|
|
72
|
+
): OmniExtensionProjectionReader<Entity>;
|
|
73
|
+
relation(id: string): OmniRelationProjectionReader;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface OmniProjectionReaderCatalog {
|
|
77
|
+
bind(
|
|
78
|
+
manager: EntityManager,
|
|
79
|
+
scope: OmniScope,
|
|
80
|
+
): OmniProjectionTransactionReaders;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface OmniProjectionReaderCatalogProvider {
|
|
84
|
+
readonly token: InjectionToken<OmniProjectionReaderCatalog>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface OmniProjectionReaderCatalogSource {
|
|
88
|
+
readonly reader: OmniProjectionReaderRegistration;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Default token for a composed set of generated Omni projection resources. */
|
|
92
|
+
export const OMNI_PROJECTION_READER_CATALOG = Symbol(
|
|
93
|
+
'OMNI_PROJECTION_READER_CATALOG',
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
function freeze<T>(value: T): Readonly<T> {
|
|
97
|
+
if (value && typeof value === 'object') Object.freeze(value);
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function validateReaderTake(take: number | undefined): number | undefined {
|
|
102
|
+
if (take === undefined) return undefined;
|
|
103
|
+
if (!Number.isInteger(take) || take < 1 || take > 1_000) {
|
|
104
|
+
throw new TypeError(
|
|
105
|
+
'Omni projection reader take must be an integer from 1 to 1000.',
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
return take;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function relationWhere(
|
|
112
|
+
definition: OmniRelationProjectionDefinition,
|
|
113
|
+
): Record<string, unknown> {
|
|
114
|
+
const relation = definition.relation;
|
|
115
|
+
return {
|
|
116
|
+
kind: In([...getOmniRelationProjectionAllowedKinds(definition)]),
|
|
117
|
+
status: relation.status ?? OmniRelationStatus.Active,
|
|
118
|
+
...(relation.schema
|
|
119
|
+
? {
|
|
120
|
+
payloadSchemaId: relation.schema.id,
|
|
121
|
+
payloadSchemaVersion: relation.schema.version,
|
|
122
|
+
}
|
|
123
|
+
: {
|
|
124
|
+
payloadSchemaId: IsNull(),
|
|
125
|
+
payloadSchemaVersion: IsNull(),
|
|
126
|
+
}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function extensionReader<Entity extends ObjectLiteral>(
|
|
131
|
+
manager: EntityManager,
|
|
132
|
+
scope: OmniScope,
|
|
133
|
+
registration: OmniExtensionProjectionReaderRegistration<Entity>,
|
|
134
|
+
): OmniExtensionProjectionReader<Entity> {
|
|
135
|
+
const ownerWhere = {
|
|
136
|
+
scopeId: scope.scopeId,
|
|
137
|
+
kind: registration.definition.owner.kind,
|
|
138
|
+
payloadSchemaId: registration.definition.owner.schema.id,
|
|
139
|
+
payloadSchemaVersion: registration.definition.owner.schema.version,
|
|
140
|
+
deletedAt: IsNull(),
|
|
141
|
+
};
|
|
142
|
+
const extensionRepository = manager.getRepository(registration.entity);
|
|
143
|
+
const ownerRepository = manager.getRepository(OmniRecordEntity);
|
|
144
|
+
const identity = registration.definition.identity.column;
|
|
145
|
+
const scopeColumn = registration.definition.scope.column;
|
|
146
|
+
|
|
147
|
+
const project = (entity: Entity, owner: OmniRecordEntity): Entity => {
|
|
148
|
+
const projected = {
|
|
149
|
+
...entity,
|
|
150
|
+
scopeId: owner.scopeId,
|
|
151
|
+
guid: owner.guid,
|
|
152
|
+
[registration.definition.revision.column]: owner.revision,
|
|
153
|
+
createdAt: owner.createdAt,
|
|
154
|
+
updatedAt: owner.updatedAt,
|
|
155
|
+
deletedAt: owner.deletedAt,
|
|
156
|
+
} as Entity;
|
|
157
|
+
return projected;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const getOwner = async (
|
|
161
|
+
guid: string,
|
|
162
|
+
): Promise<OmniRecordEntity | undefined> => {
|
|
163
|
+
const owner = await ownerRepository.findOne({
|
|
164
|
+
where: { ...ownerWhere, guid },
|
|
165
|
+
});
|
|
166
|
+
return owner ?? undefined;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const dialect = (() => {
|
|
170
|
+
const type = manager.connection.options.type;
|
|
171
|
+
if (type !== 'sqlite' && type !== 'postgres') {
|
|
172
|
+
throw new TypeError(
|
|
173
|
+
'Omni projection readers require SQLite or PostgreSQL.',
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
return createProjectionDialect(type);
|
|
177
|
+
})();
|
|
178
|
+
|
|
179
|
+
const filtersFor = (
|
|
180
|
+
where: Readonly<Record<string, unknown>> | undefined,
|
|
181
|
+
): ProjectionFilter[] => {
|
|
182
|
+
const filters: ProjectionFilter[] = [];
|
|
183
|
+
for (const [fieldName, value] of Object.entries(where ?? {})) {
|
|
184
|
+
const field = registration.definition.fields.find(
|
|
185
|
+
(candidate) => candidate.name === fieldName,
|
|
186
|
+
);
|
|
187
|
+
if (!field || !field.query?.filter?.includes('eq')) {
|
|
188
|
+
throw new TypeError(
|
|
189
|
+
`Omni extension reader only permits declared eq fields: ${fieldName}.`,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
filters.push({ field, operator: 'eq', values: [value] });
|
|
193
|
+
}
|
|
194
|
+
return filters;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const projectMany = async (entities: Entity[]): Promise<Entity[]> => {
|
|
198
|
+
if (entities.length === 0) return [];
|
|
199
|
+
const candidates: unknown[] = entities.map(
|
|
200
|
+
(entity) => entity[identity as keyof Entity] as unknown,
|
|
201
|
+
);
|
|
202
|
+
const guids = candidates.filter(
|
|
203
|
+
(guid): guid is string => typeof guid === 'string',
|
|
204
|
+
);
|
|
205
|
+
const owners = await ownerRepository.find({
|
|
206
|
+
where: { ...ownerWhere, guid: In(guids) },
|
|
207
|
+
});
|
|
208
|
+
const ownersByGuid = new Map(owners.map((owner) => [owner.guid, owner]));
|
|
209
|
+
return entities.flatMap((entity) => {
|
|
210
|
+
const guid = entity[identity as keyof Entity];
|
|
211
|
+
const owner =
|
|
212
|
+
typeof guid === 'string' ? ownersByGuid.get(guid) : undefined;
|
|
213
|
+
return owner ? [project(entity, owner)] : [];
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
return freeze({
|
|
218
|
+
async get(guid: string): Promise<Entity | undefined> {
|
|
219
|
+
const entity = await extensionRepository.findOne({
|
|
220
|
+
where: { [scopeColumn]: scope.scopeId, [identity]: guid } as never,
|
|
221
|
+
});
|
|
222
|
+
if (!entity) return undefined;
|
|
223
|
+
const owner = await getOwner(guid);
|
|
224
|
+
return owner ? project(entity, owner) : undefined;
|
|
225
|
+
},
|
|
226
|
+
async list(
|
|
227
|
+
options: {
|
|
228
|
+
where?: Readonly<Record<string, unknown>>;
|
|
229
|
+
take?: number;
|
|
230
|
+
} = {},
|
|
231
|
+
): Promise<Entity[]> {
|
|
232
|
+
const [entities] = await dialect.findMany(
|
|
233
|
+
extensionRepository,
|
|
234
|
+
registration.definition,
|
|
235
|
+
scope.scopeId,
|
|
236
|
+
filtersFor(options.where),
|
|
237
|
+
[],
|
|
238
|
+
{ take: validateReaderTake(options.take) },
|
|
239
|
+
);
|
|
240
|
+
return projectMany(entities);
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function relationReader(
|
|
246
|
+
manager: EntityManager,
|
|
247
|
+
scope: OmniScope,
|
|
248
|
+
registration: OmniRelationProjectionReaderRegistration,
|
|
249
|
+
): OmniRelationProjectionReader {
|
|
250
|
+
const repository = manager.getRepository(OmniRelationEntity);
|
|
251
|
+
const fixed = relationWhere(registration.definition);
|
|
252
|
+
return freeze({
|
|
253
|
+
async get(guid: string): Promise<OmniRelationEntity | undefined> {
|
|
254
|
+
const entity = await repository.findOne({
|
|
255
|
+
where: { scopeId: scope.scopeId, guid, ...fixed } as never,
|
|
256
|
+
});
|
|
257
|
+
return entity ?? undefined;
|
|
258
|
+
},
|
|
259
|
+
async list(
|
|
260
|
+
options: {
|
|
261
|
+
sourceRecordId?: string;
|
|
262
|
+
targetRecordId?: string;
|
|
263
|
+
take?: number;
|
|
264
|
+
} = {},
|
|
265
|
+
): Promise<OmniRelationEntity[]> {
|
|
266
|
+
const { take, ...conditions } = options;
|
|
267
|
+
return await repository.find({
|
|
268
|
+
where: { scopeId: scope.scopeId, ...fixed, ...conditions } as never,
|
|
269
|
+
take: validateReaderTake(take),
|
|
270
|
+
});
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Creates an immutable catalog from resource registrations. It has no global
|
|
277
|
+
* state: each hook binds the catalog to its active transaction manager.
|
|
278
|
+
*/
|
|
279
|
+
export function createOmniProjectionReaderCatalog(
|
|
280
|
+
registrations: readonly (
|
|
281
|
+
OmniProjectionReaderRegistration | OmniProjectionReaderCatalogSource
|
|
282
|
+
)[],
|
|
283
|
+
): OmniProjectionReaderCatalog {
|
|
284
|
+
const byId = new Map<string, OmniProjectionReaderRegistration>();
|
|
285
|
+
for (const source of registrations) {
|
|
286
|
+
const registration = 'reader' in source ? source.reader : source;
|
|
287
|
+
if (!registration.id || byId.has(registration.id)) {
|
|
288
|
+
throw new TypeError(
|
|
289
|
+
'Omni projection reader registrations must have unique non-empty ids.',
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
byId.set(registration.id, registration);
|
|
293
|
+
}
|
|
294
|
+
const snapshot = freeze(new Map(byId));
|
|
295
|
+
return freeze({
|
|
296
|
+
bind(
|
|
297
|
+
manager: EntityManager,
|
|
298
|
+
scope: OmniScope,
|
|
299
|
+
): OmniProjectionTransactionReaders {
|
|
300
|
+
return freeze({
|
|
301
|
+
extension<Entity extends ObjectLiteral = ObjectLiteral>(
|
|
302
|
+
id: string,
|
|
303
|
+
): OmniExtensionProjectionReader<Entity> {
|
|
304
|
+
const registration = snapshot.get(id);
|
|
305
|
+
if (!registration || registration.type !== 'extension') {
|
|
306
|
+
throw new TypeError(
|
|
307
|
+
`Omni extension projection reader is not registered: ${id}.`,
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
return extensionReader(
|
|
311
|
+
manager,
|
|
312
|
+
scope,
|
|
313
|
+
registration,
|
|
314
|
+
) as OmniExtensionProjectionReader<Entity>;
|
|
315
|
+
},
|
|
316
|
+
relation(id: string): OmniRelationProjectionReader {
|
|
317
|
+
const registration = snapshot.get(id);
|
|
318
|
+
if (!registration || registration.type !== 'relation') {
|
|
319
|
+
throw new TypeError(
|
|
320
|
+
`Omni relation projection reader is not registered: ${id}.`,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
return relationReader(manager, scope, registration);
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Creates the one Nest provider shared by lifecycle-enabled registrations.
|
|
332
|
+
* Call it after creating the individual resource registrations, passing those
|
|
333
|
+
* registrations directly; the catalog captures their immutable reader entries.
|
|
334
|
+
*/
|
|
335
|
+
export function createOmniProjectionReaderCatalogProvider(
|
|
336
|
+
registrations: readonly (
|
|
337
|
+
OmniProjectionReaderRegistration | OmniProjectionReaderCatalogSource
|
|
338
|
+
)[],
|
|
339
|
+
token: InjectionToken<OmniProjectionReaderCatalog> = OMNI_PROJECTION_READER_CATALOG,
|
|
340
|
+
): Provider {
|
|
341
|
+
return {
|
|
342
|
+
provide: token,
|
|
343
|
+
useValue: createOmniProjectionReaderCatalog(registrations),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { InjectionToken } from '@nestjs/common';
|
|
2
|
+
import type { EntityManager, ObjectLiteral } from 'typeorm';
|
|
3
|
+
import type { OmniProjectionTransactionReaders } from './omni-projection.catalog.js';
|
|
4
|
+
import type { OmniScope } from './omni-scope.js';
|
|
5
|
+
export interface OmniProjectionLifecycleContext<Definition, Entity extends ObjectLiteral> {
|
|
6
|
+
readonly definition: Definition;
|
|
7
|
+
readonly scope: OmniScope;
|
|
8
|
+
readonly manager: EntityManager;
|
|
9
|
+
readonly readers: OmniProjectionTransactionReaders;
|
|
10
|
+
readonly input: Readonly<Record<string, unknown>>;
|
|
11
|
+
readonly current?: Entity;
|
|
12
|
+
}
|
|
13
|
+
export interface OmniProjectionLifecycle<Definition, Entity extends ObjectLiteral> {
|
|
14
|
+
beforeCreate?(context: OmniProjectionLifecycleContext<Definition, Entity>): void | Promise<void>;
|
|
15
|
+
beforeUpdate?(context: OmniProjectionLifecycleContext<Definition, Entity>): void | Promise<void>;
|
|
16
|
+
beforeDelete?(context: OmniProjectionLifecycleContext<Definition, Entity>): void | Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export interface OmniProjectionLifecycleProvider<Definition, Entity extends ObjectLiteral> {
|
|
19
|
+
readonly token: InjectionToken<OmniProjectionLifecycle<Definition, Entity>>;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"omni-projection.lifecycle.js","sourceRoot":"","sources":["omni-projection.lifecycle.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { InjectionToken } from '@nestjs/common';
|
|
2
|
+
import type { EntityManager, ObjectLiteral } from 'typeorm';
|
|
3
|
+
import type { OmniProjectionTransactionReaders } from './omni-projection.catalog.js';
|
|
4
|
+
import type { OmniScope } from './omni-scope.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Transaction-aware policy seam shared by fixed Omni projections. Policies
|
|
8
|
+
* are optional, but when registered they are invoked by the store itself—not
|
|
9
|
+
* by transport adapters—so generated REST and GraphQL cannot bypass them.
|
|
10
|
+
*/
|
|
11
|
+
export interface OmniProjectionLifecycleContext<
|
|
12
|
+
Definition,
|
|
13
|
+
Entity extends ObjectLiteral,
|
|
14
|
+
> {
|
|
15
|
+
readonly definition: Definition;
|
|
16
|
+
readonly scope: OmniScope;
|
|
17
|
+
readonly manager: EntityManager;
|
|
18
|
+
/**
|
|
19
|
+
* Manager-bound, scope-constrained readers registered by the composed
|
|
20
|
+
* projections. Policies use these instead of reaching for repositories.
|
|
21
|
+
*/
|
|
22
|
+
readonly readers: OmniProjectionTransactionReaders;
|
|
23
|
+
readonly input: Readonly<Record<string, unknown>>;
|
|
24
|
+
/** Present for update and delete after fixed scope/metadata constraints. */
|
|
25
|
+
readonly current?: Entity;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface OmniProjectionLifecycle<
|
|
29
|
+
Definition,
|
|
30
|
+
Entity extends ObjectLiteral,
|
|
31
|
+
> {
|
|
32
|
+
beforeCreate?(
|
|
33
|
+
context: OmniProjectionLifecycleContext<Definition, Entity>,
|
|
34
|
+
): void | Promise<void>;
|
|
35
|
+
beforeUpdate?(
|
|
36
|
+
context: OmniProjectionLifecycleContext<Definition, Entity>,
|
|
37
|
+
): void | Promise<void>;
|
|
38
|
+
beforeDelete?(
|
|
39
|
+
context: OmniProjectionLifecycleContext<Definition, Entity>,
|
|
40
|
+
): void | Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A Nest token for a request-scoped policy. Resource registrations inject the
|
|
45
|
+
* token into their generated service factory, so the policy is shared by REST
|
|
46
|
+
* and GraphQL but remains app-owned and DI-created.
|
|
47
|
+
*/
|
|
48
|
+
export interface OmniProjectionLifecycleProvider<
|
|
49
|
+
Definition,
|
|
50
|
+
Entity extends ObjectLiteral,
|
|
51
|
+
> {
|
|
52
|
+
readonly token: InjectionToken<OmniProjectionLifecycle<Definition, Entity>>;
|
|
53
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OmniRecordStatus = void 0;
|
|
4
|
+
const graphql_1 = require("@nestjs/graphql");
|
|
5
|
+
var OmniRecordStatus;
|
|
6
|
+
(function (OmniRecordStatus) {
|
|
7
|
+
OmniRecordStatus["Draft"] = "draft";
|
|
8
|
+
OmniRecordStatus["Active"] = "active";
|
|
9
|
+
OmniRecordStatus["Archived"] = "archived";
|
|
10
|
+
})(OmniRecordStatus || (exports.OmniRecordStatus = OmniRecordStatus = {}));
|
|
11
|
+
(0, graphql_1.registerEnumType)(OmniRecordStatus, {
|
|
12
|
+
name: 'OmniRecordStatus',
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=omni-record-status.enum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"omni-record-status.enum.js","sourceRoot":"","sources":["omni-record-status.enum.ts"],"names":[],"mappings":";;;AAAA,6CAAmD;AAEnD,IAAY,gBAIX;AAJD,WAAY,gBAAgB;IAC1B,mCAAe,CAAA;IACf,qCAAiB,CAAA;IACjB,yCAAqB,CAAA;AACvB,CAAC,EAJW,gBAAgB,gCAAhB,gBAAgB,QAI3B;AAED,IAAA,0BAAgB,EAAC,gBAAgB,EAAE;IACjC,IAAI,EAAE,kBAAkB;CACzB,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.omniRecordBackendProvidersFactory = void 0;
|
|
4
|
+
const omni_record_entity_js_1 = require("./base/omni-record.entity.js");
|
|
5
|
+
const omni_scoped_backend_js_1 = require("./omni-scoped.backend.js");
|
|
6
|
+
const omni_record_service_js_1 = require("./omni-record.service.js");
|
|
7
|
+
const omniRecordBackendProvidersFactory = (dbConnection, reservedRecordKinds = []) => (0, omni_scoped_backend_js_1.omniScopedBackendProvidersFactory)({
|
|
8
|
+
entityModel: omni_record_entity_js_1.OmniRecordEntity,
|
|
9
|
+
dbConnection,
|
|
10
|
+
createService: (repository, scope, options) => new omni_record_service_js_1.OmniRecordService(repository, scope, options.deletion.record, reservedRecordKinds),
|
|
11
|
+
});
|
|
12
|
+
exports.omniRecordBackendProvidersFactory = omniRecordBackendProvidersFactory;
|
|
13
|
+
//# sourceMappingURL=omni-record.backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"omni-record.backend.js","sourceRoot":"","sources":["omni-record.backend.ts"],"names":[],"mappings":";;;AAAA,wEAAgE;AAChE,qEAA6E;AAC7E,qEAA6D;AAEtD,MAAM,iCAAiC,GAAG,CAC/C,YAAoB,EACpB,sBAAyC,EAAE,EAC3C,EAAE,CACF,IAAA,0DAAiC,EAAmB;IAClD,WAAW,EAAE,wCAAgB;IAC7B,YAAY;IACZ,aAAa,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAC5C,IAAI,0CAAiB,CACnB,UAAU,EACV,KAAK,EACL,OAAO,CAAC,QAAQ,CAAC,MAAM,EACvB,mBAAmB,CACpB;CACJ,CAAC,CAAC;AAdQ,QAAA,iCAAiC,qCAczC"}
|