@nest-yalc-2/omnikernel-module 2.2.2 → 2.2.6
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/package.json +17 -15
- package/src/__tests__/omni-collection.entity.spec.ts +49 -49
- package/src/__tests__/omni-collection.service.spec.ts +83 -83
- package/src/__tests__/omni-document.entity.spec.ts +55 -55
- package/src/__tests__/omni-document.service.spec.ts +83 -83
- package/src/__tests__/omni-extension-projection-constraints.spec.ts +518 -518
- package/src/__tests__/omni-extension-projection.registration.spec.ts +947 -946
- package/src/__tests__/omni-extension-projection.service.spec.ts +806 -806
- package/src/__tests__/omni-external-ref.entity.spec.ts +36 -36
- package/src/__tests__/omni-external-ref.service.spec.ts +252 -252
- package/src/__tests__/omni-named.entity.spec.ts +33 -33
- package/src/__tests__/omni-record.entity.spec.ts +32 -32
- package/src/__tests__/omni-record.service.spec.ts +107 -107
- package/src/__tests__/omni-relation-semantics.spec.ts +102 -102
- package/src/__tests__/omni-relation.entity.spec.ts +38 -38
- package/src/__tests__/omni-scope-substrate.spec.ts +81 -81
- package/src/__tests__/omni-scoped.backend.spec.ts +115 -115
- package/src/__tests__/omni-scoped.service.spec.ts +354 -354
- package/src/__tests__/omnikernel.diagnostics.spec.ts +94 -94
- package/src/__tests__/omnikernel.module.spec.ts +38 -40
- package/src/__tests__/omnikernel.persistence.spec.ts +154 -154
- package/src/__tests__/omnikernel.public-api.spec.ts +238 -238
- package/src/__tests__/omnikernel.query.service.spec.ts +155 -155
- package/src/base/omni-base.entity.ts +41 -41
- package/src/base/omni-external-ref.entity.ts +53 -53
- package/src/base/omni-named.entity.ts +16 -16
- package/src/base/omni-record.entity.ts +51 -51
- package/src/base/omni-relation.entity.ts +72 -72
- package/src/index.ts +49 -49
- package/src/omni-collection-kind.enum.ts +10 -10
- package/src/omni-collection.backend.ts +16 -16
- package/src/omni-collection.dto.ts +170 -170
- package/src/omni-collection.entity.ts +21 -21
- package/src/omni-collection.service.ts +75 -75
- package/src/omni-document-kind.enum.ts +12 -12
- package/src/omni-document.backend.ts +16 -16
- package/src/omni-document.dto.ts +198 -198
- package/src/omni-document.entity.ts +30 -30
- package/src/omni-document.service.ts +75 -75
- package/src/omni-dto.helpers.ts +21 -21
- package/src/omni-extension-projection.definition.ts +294 -294
- package/src/omni-extension-projection.resource.ts +274 -274
- package/src/omni-extension-projection.service.ts +452 -452
- package/src/omni-external-ref-binding.validator.ts +53 -53
- package/src/omni-external-ref-internal-type.enum.ts +11 -11
- package/src/omni-external-ref.backend.ts +25 -25
- package/src/omni-external-ref.dto.ts +128 -128
- package/src/omni-external-ref.service.ts +255 -255
- package/src/omni-migration.ts +365 -365
- package/src/omni-named.backend.ts +11 -11
- package/src/omni-named.dto.ts +86 -86
- package/src/omni-projection.catalog.ts +345 -345
- package/src/omni-projection.lifecycle.ts +53 -53
- package/src/omni-record-status.enum.ts +11 -11
- package/src/omni-record.backend.ts +19 -19
- package/src/omni-record.dto.ts +157 -157
- package/src/omni-record.service.ts +113 -113
- package/src/omni-relation-kind.contract.ts +49 -49
- package/src/omni-relation-kind.enum.ts +12 -12
- package/src/omni-relation-projection.definition.ts +166 -166
- package/src/omni-relation-projection.resource.ts +360 -360
- package/src/omni-relation-projection.service.ts +610 -610
- package/src/omni-relation-semantics.ts +52 -52
- package/src/omni-relation-status.enum.ts +11 -11
- package/src/omni-relation.backend.ts +21 -21
- package/src/omni-relation.dto.ts +142 -142
- package/src/omni-relation.service.ts +159 -159
- package/src/omni-scope.ts +161 -161
- package/src/omni-scoped.backend.ts +110 -110
- package/src/omni-scoped.repository.ts +34 -34
- package/src/omni-scoped.service.ts +338 -338
- package/src/omnikernel.diagnostics.ts +83 -83
- package/src/omnikernel.module.ts +97 -97
- package/src/omnikernel.query.service.ts +108 -108
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import { describe, expect, it } from '@jest/globals';
|
|
2
|
-
import { getMetadataArgsStorage } from 'typeorm';
|
|
3
|
-
|
|
4
|
-
import { OmniNamedEntity } from '../base/omni-named.entity.js';
|
|
5
|
-
import { OmniRecordEntity } from '../base/omni-record.entity.js';
|
|
6
|
-
|
|
7
|
-
describe('OmniRecordEntity', () => {
|
|
8
|
-
it('extends OmniNamedEntity', () => {
|
|
9
|
-
expect(new OmniRecordEntity()).toBeInstanceOf(OmniNamedEntity);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('registers core columns and directional relations', () => {
|
|
13
|
-
const metadata = getMetadataArgsStorage();
|
|
14
|
-
const table = metadata.tables.find(
|
|
15
|
-
(item) => item.target === OmniRecordEntity,
|
|
16
|
-
);
|
|
17
|
-
const entityColumns = metadata.columns
|
|
18
|
-
.filter((item) => item.target === OmniRecordEntity)
|
|
19
|
-
.map((item) => item.propertyName);
|
|
20
|
-
const relations = metadata.relations
|
|
21
|
-
.filter((item) => item.target === OmniRecordEntity)
|
|
22
|
-
.map((item) => item.propertyName);
|
|
23
|
-
|
|
24
|
-
expect(table?.name).toBe('omni-record');
|
|
25
|
-
expect(entityColumns).toEqual(
|
|
26
|
-
expect.arrayContaining(['kind', 'status', 'payload']),
|
|
27
|
-
);
|
|
28
|
-
expect(relations).toEqual(
|
|
29
|
-
expect.arrayContaining(['outgoingRelations', 'incomingRelations']),
|
|
30
|
-
);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
1
|
+
import { describe, expect, it } from '@jest/globals';
|
|
2
|
+
import { getMetadataArgsStorage } from 'typeorm';
|
|
3
|
+
|
|
4
|
+
import { OmniNamedEntity } from '../base/omni-named.entity.js';
|
|
5
|
+
import { OmniRecordEntity } from '../base/omni-record.entity.js';
|
|
6
|
+
|
|
7
|
+
describe('OmniRecordEntity', () => {
|
|
8
|
+
it('extends OmniNamedEntity', () => {
|
|
9
|
+
expect(new OmniRecordEntity()).toBeInstanceOf(OmniNamedEntity);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('registers core columns and directional relations', () => {
|
|
13
|
+
const metadata = getMetadataArgsStorage();
|
|
14
|
+
const table = metadata.tables.find(
|
|
15
|
+
(item) => item.target === OmniRecordEntity,
|
|
16
|
+
);
|
|
17
|
+
const entityColumns = metadata.columns
|
|
18
|
+
.filter((item) => item.target === OmniRecordEntity)
|
|
19
|
+
.map((item) => item.propertyName);
|
|
20
|
+
const relations = metadata.relations
|
|
21
|
+
.filter((item) => item.target === OmniRecordEntity)
|
|
22
|
+
.map((item) => item.propertyName);
|
|
23
|
+
|
|
24
|
+
expect(table?.name).toBe('omni-record');
|
|
25
|
+
expect(entityColumns).toEqual(
|
|
26
|
+
expect.arrayContaining(['kind', 'status', 'payload']),
|
|
27
|
+
);
|
|
28
|
+
expect(relations).toEqual(
|
|
29
|
+
expect.arrayContaining(['outgoingRelations', 'incomingRelations']),
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -1,107 +1,107 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it } from '@jest/globals';
|
|
2
|
-
import { DataSource } from 'typeorm';
|
|
3
|
-
|
|
4
|
-
import { OmniNamedEntity } from '../base/omni-named.entity.js';
|
|
5
|
-
import { OmniRecordEntity } from '../base/omni-record.entity.js';
|
|
6
|
-
import { OmniRelationEntity } from '../base/omni-relation.entity.js';
|
|
7
|
-
import { OmniExternalRefEntity } from '../base/omni-external-ref.entity.js';
|
|
8
|
-
import { OmniRecordStatus } from '../omni-record-status.enum.js';
|
|
9
|
-
import { OmniRecordService } from '../omni-record.service.js';
|
|
10
|
-
|
|
11
|
-
const scope = {
|
|
12
|
-
scopeId: 'scope-record-guard',
|
|
13
|
-
cacheKey: (key: string) => `scope-record-guard:${key}`,
|
|
14
|
-
};
|
|
15
|
-
const reservedKind = 'registered_extension';
|
|
16
|
-
const ownerGuid = '10000000-0000-4000-8000-000000000301';
|
|
17
|
-
const normalGuid = '10000000-0000-4000-8000-000000000302';
|
|
18
|
-
|
|
19
|
-
describe('OmniRecordService extension owner guard', () => {
|
|
20
|
-
let dataSource: DataSource;
|
|
21
|
-
let service: InstanceType<typeof OmniRecordService>;
|
|
22
|
-
|
|
23
|
-
beforeEach(async () => {
|
|
24
|
-
dataSource = new DataSource({
|
|
25
|
-
type: 'sqlite',
|
|
26
|
-
database: ':memory:',
|
|
27
|
-
dropSchema: true,
|
|
28
|
-
synchronize: true,
|
|
29
|
-
entities: [
|
|
30
|
-
OmniNamedEntity,
|
|
31
|
-
OmniRecordEntity,
|
|
32
|
-
OmniRelationEntity,
|
|
33
|
-
OmniExternalRefEntity,
|
|
34
|
-
],
|
|
35
|
-
});
|
|
36
|
-
await dataSource.initialize();
|
|
37
|
-
service = new OmniRecordService(
|
|
38
|
-
dataSource.getRepository(OmniRecordEntity) as never,
|
|
39
|
-
scope,
|
|
40
|
-
'tombstone',
|
|
41
|
-
[reservedKind],
|
|
42
|
-
);
|
|
43
|
-
await dataSource.getRepository(OmniRecordEntity).save({
|
|
44
|
-
scopeId: scope.scopeId,
|
|
45
|
-
guid: ownerGuid,
|
|
46
|
-
title: 'Extension-owned record',
|
|
47
|
-
kind: reservedKind,
|
|
48
|
-
status: OmniRecordStatus.Active,
|
|
49
|
-
payloadSchemaId: 'registered.extension.v1',
|
|
50
|
-
payloadSchemaVersion: 1,
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
afterEach(async () => {
|
|
55
|
-
await dataSource.destroy();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('rejects generic creation, mutation, promotion, and deletion of a reserved extension owner', async () => {
|
|
59
|
-
await expect(
|
|
60
|
-
service.createEntity({
|
|
61
|
-
guid: '10000000-0000-4000-8000-000000000303',
|
|
62
|
-
title: 'Attempted extension owner',
|
|
63
|
-
kind: reservedKind,
|
|
64
|
-
status: OmniRecordStatus.Active,
|
|
65
|
-
}),
|
|
66
|
-
).rejects.toThrow('owned by a registered extension projection');
|
|
67
|
-
|
|
68
|
-
await service.createEntity({
|
|
69
|
-
guid: normalGuid,
|
|
70
|
-
title: 'Normal record',
|
|
71
|
-
kind: 'normal_record',
|
|
72
|
-
status: OmniRecordStatus.Active,
|
|
73
|
-
});
|
|
74
|
-
await expect(
|
|
75
|
-
service.updateEntity(
|
|
76
|
-
{ guid: normalGuid },
|
|
77
|
-
{ kind: reservedKind },
|
|
78
|
-
),
|
|
79
|
-
).rejects.toThrow('owned by a registered extension projection');
|
|
80
|
-
await expect(
|
|
81
|
-
service.updateEntity(
|
|
82
|
-
{ guid: ownerGuid },
|
|
83
|
-
{ kind: 'normal_record' },
|
|
84
|
-
),
|
|
85
|
-
).rejects.toThrow('owned by a registered extension projection');
|
|
86
|
-
await expect(service.deleteEntity({ guid: ownerGuid })).rejects.toThrow(
|
|
87
|
-
'owned by a registered extension projection',
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
expect(
|
|
91
|
-
await dataSource.getRepository(OmniRecordEntity).findOneByOrFail({
|
|
92
|
-
scopeId: scope.scopeId,
|
|
93
|
-
guid: ownerGuid,
|
|
94
|
-
}),
|
|
95
|
-
).toMatchObject({
|
|
96
|
-
kind: reservedKind,
|
|
97
|
-
payloadSchemaId: 'registered.extension.v1',
|
|
98
|
-
payloadSchemaVersion: 1,
|
|
99
|
-
});
|
|
100
|
-
expect(
|
|
101
|
-
await dataSource.getRepository(OmniRecordEntity).findOneByOrFail({
|
|
102
|
-
scopeId: scope.scopeId,
|
|
103
|
-
guid: normalGuid,
|
|
104
|
-
}),
|
|
105
|
-
).toMatchObject({ kind: 'normal_record' });
|
|
106
|
-
});
|
|
107
|
-
});
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from '@jest/globals';
|
|
2
|
+
import { DataSource } from 'typeorm';
|
|
3
|
+
|
|
4
|
+
import { OmniNamedEntity } from '../base/omni-named.entity.js';
|
|
5
|
+
import { OmniRecordEntity } from '../base/omni-record.entity.js';
|
|
6
|
+
import { OmniRelationEntity } from '../base/omni-relation.entity.js';
|
|
7
|
+
import { OmniExternalRefEntity } from '../base/omni-external-ref.entity.js';
|
|
8
|
+
import { OmniRecordStatus } from '../omni-record-status.enum.js';
|
|
9
|
+
import { OmniRecordService } from '../omni-record.service.js';
|
|
10
|
+
|
|
11
|
+
const scope = {
|
|
12
|
+
scopeId: 'scope-record-guard',
|
|
13
|
+
cacheKey: (key: string) => `scope-record-guard:${key}`,
|
|
14
|
+
};
|
|
15
|
+
const reservedKind = 'registered_extension';
|
|
16
|
+
const ownerGuid = '10000000-0000-4000-8000-000000000301';
|
|
17
|
+
const normalGuid = '10000000-0000-4000-8000-000000000302';
|
|
18
|
+
|
|
19
|
+
describe('OmniRecordService extension owner guard', () => {
|
|
20
|
+
let dataSource: DataSource;
|
|
21
|
+
let service: InstanceType<typeof OmniRecordService>;
|
|
22
|
+
|
|
23
|
+
beforeEach(async () => {
|
|
24
|
+
dataSource = new DataSource({
|
|
25
|
+
type: 'sqlite',
|
|
26
|
+
database: ':memory:',
|
|
27
|
+
dropSchema: true,
|
|
28
|
+
synchronize: true,
|
|
29
|
+
entities: [
|
|
30
|
+
OmniNamedEntity,
|
|
31
|
+
OmniRecordEntity,
|
|
32
|
+
OmniRelationEntity,
|
|
33
|
+
OmniExternalRefEntity,
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
await dataSource.initialize();
|
|
37
|
+
service = new OmniRecordService(
|
|
38
|
+
dataSource.getRepository(OmniRecordEntity) as never,
|
|
39
|
+
scope,
|
|
40
|
+
'tombstone',
|
|
41
|
+
[reservedKind],
|
|
42
|
+
);
|
|
43
|
+
await dataSource.getRepository(OmniRecordEntity).save({
|
|
44
|
+
scopeId: scope.scopeId,
|
|
45
|
+
guid: ownerGuid,
|
|
46
|
+
title: 'Extension-owned record',
|
|
47
|
+
kind: reservedKind,
|
|
48
|
+
status: OmniRecordStatus.Active,
|
|
49
|
+
payloadSchemaId: 'registered.extension.v1',
|
|
50
|
+
payloadSchemaVersion: 1,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
afterEach(async () => {
|
|
55
|
+
await dataSource.destroy();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('rejects generic creation, mutation, promotion, and deletion of a reserved extension owner', async () => {
|
|
59
|
+
await expect(
|
|
60
|
+
service.createEntity({
|
|
61
|
+
guid: '10000000-0000-4000-8000-000000000303',
|
|
62
|
+
title: 'Attempted extension owner',
|
|
63
|
+
kind: reservedKind,
|
|
64
|
+
status: OmniRecordStatus.Active,
|
|
65
|
+
}),
|
|
66
|
+
).rejects.toThrow('owned by a registered extension projection');
|
|
67
|
+
|
|
68
|
+
await service.createEntity({
|
|
69
|
+
guid: normalGuid,
|
|
70
|
+
title: 'Normal record',
|
|
71
|
+
kind: 'normal_record',
|
|
72
|
+
status: OmniRecordStatus.Active,
|
|
73
|
+
});
|
|
74
|
+
await expect(
|
|
75
|
+
service.updateEntity(
|
|
76
|
+
{ guid: normalGuid },
|
|
77
|
+
{ kind: reservedKind },
|
|
78
|
+
),
|
|
79
|
+
).rejects.toThrow('owned by a registered extension projection');
|
|
80
|
+
await expect(
|
|
81
|
+
service.updateEntity(
|
|
82
|
+
{ guid: ownerGuid },
|
|
83
|
+
{ kind: 'normal_record' },
|
|
84
|
+
),
|
|
85
|
+
).rejects.toThrow('owned by a registered extension projection');
|
|
86
|
+
await expect(service.deleteEntity({ guid: ownerGuid })).rejects.toThrow(
|
|
87
|
+
'owned by a registered extension projection',
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
expect(
|
|
91
|
+
await dataSource.getRepository(OmniRecordEntity).findOneByOrFail({
|
|
92
|
+
scopeId: scope.scopeId,
|
|
93
|
+
guid: ownerGuid,
|
|
94
|
+
}),
|
|
95
|
+
).toMatchObject({
|
|
96
|
+
kind: reservedKind,
|
|
97
|
+
payloadSchemaId: 'registered.extension.v1',
|
|
98
|
+
payloadSchemaVersion: 1,
|
|
99
|
+
});
|
|
100
|
+
expect(
|
|
101
|
+
await dataSource.getRepository(OmniRecordEntity).findOneByOrFail({
|
|
102
|
+
scopeId: scope.scopeId,
|
|
103
|
+
guid: normalGuid,
|
|
104
|
+
}),
|
|
105
|
+
).toMatchObject({ kind: 'normal_record' });
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
import { describe, expect, it } from '@jest/globals';
|
|
2
|
-
|
|
3
|
-
import { OmniCollectionKind } from '../omni-collection-kind.enum.js';
|
|
4
|
-
import { OmniDocumentKind } from '../omni-document-kind.enum.js';
|
|
5
|
-
import { OmniRelationKind } from '../omni-relation-kind.enum.js';
|
|
6
|
-
import {
|
|
7
|
-
OMNI_COLLECTION_MEMBERSHIP_RELATION_KIND,
|
|
8
|
-
isAllowedOmniRelation,
|
|
9
|
-
isCanonicalCollectionMembershipRelation,
|
|
10
|
-
isOmniCollectionRecordKind,
|
|
11
|
-
isOmniDocumentRecordKind,
|
|
12
|
-
} from '../omni-relation-semantics.js';
|
|
13
|
-
|
|
14
|
-
describe('Omni relation semantics', () => {
|
|
15
|
-
it('treats collection contains as the canonical collection membership edge', () => {
|
|
16
|
-
expect(OMNI_COLLECTION_MEMBERSHIP_RELATION_KIND).toBe(
|
|
17
|
-
OmniRelationKind.Contains,
|
|
18
|
-
);
|
|
19
|
-
expect(
|
|
20
|
-
isCanonicalCollectionMembershipRelation({
|
|
21
|
-
sourceKind: OmniCollectionKind.Collection,
|
|
22
|
-
relationKind: OmniRelationKind.Contains,
|
|
23
|
-
}),
|
|
24
|
-
).toBe(true);
|
|
25
|
-
expect(
|
|
26
|
-
isCanonicalCollectionMembershipRelation({
|
|
27
|
-
sourceKind: OmniDocumentKind.Document,
|
|
28
|
-
relationKind: OmniRelationKind.Contains,
|
|
29
|
-
}),
|
|
30
|
-
).toBe(false);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('recognizes the current concrete record families', () => {
|
|
34
|
-
expect(isOmniCollectionRecordKind(OmniCollectionKind.Collection)).toBe(
|
|
35
|
-
true,
|
|
36
|
-
);
|
|
37
|
-
expect(isOmniCollectionRecordKind(OmniDocumentKind.Document)).toBe(false);
|
|
38
|
-
expect(isOmniDocumentRecordKind(OmniDocumentKind.Document)).toBe(true);
|
|
39
|
-
expect(isOmniDocumentRecordKind(OmniCollectionKind.Collection)).toBe(false);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('allows collection-to-document contains links and rejects the reversed organization edge', () => {
|
|
43
|
-
expect(
|
|
44
|
-
isAllowedOmniRelation({
|
|
45
|
-
sourceKind: OmniCollectionKind.Collection,
|
|
46
|
-
targetKind: OmniDocumentKind.Document,
|
|
47
|
-
relationKind: OmniRelationKind.Contains,
|
|
48
|
-
}),
|
|
49
|
-
).toBe(true);
|
|
50
|
-
expect(
|
|
51
|
-
isAllowedOmniRelation({
|
|
52
|
-
sourceKind: OmniDocumentKind.Document,
|
|
53
|
-
targetKind: OmniCollectionKind.Collection,
|
|
54
|
-
relationKind: OmniRelationKind.Contains,
|
|
55
|
-
}),
|
|
56
|
-
).toBe(false);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('limits derived_from to document lineage', () => {
|
|
60
|
-
expect(
|
|
61
|
-
isAllowedOmniRelation({
|
|
62
|
-
sourceKind: OmniDocumentKind.Document,
|
|
63
|
-
targetKind: OmniDocumentKind.Document,
|
|
64
|
-
relationKind: OmniRelationKind.DerivedFrom,
|
|
65
|
-
}),
|
|
66
|
-
).toBe(true);
|
|
67
|
-
expect(
|
|
68
|
-
isAllowedOmniRelation({
|
|
69
|
-
sourceKind: OmniCollectionKind.Collection,
|
|
70
|
-
targetKind: OmniDocumentKind.Document,
|
|
71
|
-
relationKind: OmniRelationKind.DerivedFrom,
|
|
72
|
-
}),
|
|
73
|
-
).toBe(false);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('keeps references and related_to flexible for cross-record graph links', () => {
|
|
77
|
-
expect(
|
|
78
|
-
isAllowedOmniRelation({
|
|
79
|
-
sourceKind: OmniDocumentKind.Document,
|
|
80
|
-
targetKind: OmniCollectionKind.Collection,
|
|
81
|
-
relationKind: OmniRelationKind.References,
|
|
82
|
-
}),
|
|
83
|
-
).toBe(true);
|
|
84
|
-
expect(
|
|
85
|
-
isAllowedOmniRelation({
|
|
86
|
-
sourceKind: OmniCollectionKind.Collection,
|
|
87
|
-
targetKind: OmniDocumentKind.Document,
|
|
88
|
-
relationKind: OmniRelationKind.RelatedTo,
|
|
89
|
-
}),
|
|
90
|
-
).toBe(true);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('returns false for unexpected relation values at runtime', () => {
|
|
94
|
-
expect(
|
|
95
|
-
isAllowedOmniRelation({
|
|
96
|
-
sourceKind: OmniCollectionKind.Collection,
|
|
97
|
-
targetKind: OmniDocumentKind.Document,
|
|
98
|
-
relationKind: 'unexpected' as OmniRelationKind,
|
|
99
|
-
}),
|
|
100
|
-
).toBe(false);
|
|
101
|
-
});
|
|
102
|
-
});
|
|
1
|
+
import { describe, expect, it } from '@jest/globals';
|
|
2
|
+
|
|
3
|
+
import { OmniCollectionKind } from '../omni-collection-kind.enum.js';
|
|
4
|
+
import { OmniDocumentKind } from '../omni-document-kind.enum.js';
|
|
5
|
+
import { OmniRelationKind } from '../omni-relation-kind.enum.js';
|
|
6
|
+
import {
|
|
7
|
+
OMNI_COLLECTION_MEMBERSHIP_RELATION_KIND,
|
|
8
|
+
isAllowedOmniRelation,
|
|
9
|
+
isCanonicalCollectionMembershipRelation,
|
|
10
|
+
isOmniCollectionRecordKind,
|
|
11
|
+
isOmniDocumentRecordKind,
|
|
12
|
+
} from '../omni-relation-semantics.js';
|
|
13
|
+
|
|
14
|
+
describe('Omni relation semantics', () => {
|
|
15
|
+
it('treats collection contains as the canonical collection membership edge', () => {
|
|
16
|
+
expect(OMNI_COLLECTION_MEMBERSHIP_RELATION_KIND).toBe(
|
|
17
|
+
OmniRelationKind.Contains,
|
|
18
|
+
);
|
|
19
|
+
expect(
|
|
20
|
+
isCanonicalCollectionMembershipRelation({
|
|
21
|
+
sourceKind: OmniCollectionKind.Collection,
|
|
22
|
+
relationKind: OmniRelationKind.Contains,
|
|
23
|
+
}),
|
|
24
|
+
).toBe(true);
|
|
25
|
+
expect(
|
|
26
|
+
isCanonicalCollectionMembershipRelation({
|
|
27
|
+
sourceKind: OmniDocumentKind.Document,
|
|
28
|
+
relationKind: OmniRelationKind.Contains,
|
|
29
|
+
}),
|
|
30
|
+
).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('recognizes the current concrete record families', () => {
|
|
34
|
+
expect(isOmniCollectionRecordKind(OmniCollectionKind.Collection)).toBe(
|
|
35
|
+
true,
|
|
36
|
+
);
|
|
37
|
+
expect(isOmniCollectionRecordKind(OmniDocumentKind.Document)).toBe(false);
|
|
38
|
+
expect(isOmniDocumentRecordKind(OmniDocumentKind.Document)).toBe(true);
|
|
39
|
+
expect(isOmniDocumentRecordKind(OmniCollectionKind.Collection)).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('allows collection-to-document contains links and rejects the reversed organization edge', () => {
|
|
43
|
+
expect(
|
|
44
|
+
isAllowedOmniRelation({
|
|
45
|
+
sourceKind: OmniCollectionKind.Collection,
|
|
46
|
+
targetKind: OmniDocumentKind.Document,
|
|
47
|
+
relationKind: OmniRelationKind.Contains,
|
|
48
|
+
}),
|
|
49
|
+
).toBe(true);
|
|
50
|
+
expect(
|
|
51
|
+
isAllowedOmniRelation({
|
|
52
|
+
sourceKind: OmniDocumentKind.Document,
|
|
53
|
+
targetKind: OmniCollectionKind.Collection,
|
|
54
|
+
relationKind: OmniRelationKind.Contains,
|
|
55
|
+
}),
|
|
56
|
+
).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('limits derived_from to document lineage', () => {
|
|
60
|
+
expect(
|
|
61
|
+
isAllowedOmniRelation({
|
|
62
|
+
sourceKind: OmniDocumentKind.Document,
|
|
63
|
+
targetKind: OmniDocumentKind.Document,
|
|
64
|
+
relationKind: OmniRelationKind.DerivedFrom,
|
|
65
|
+
}),
|
|
66
|
+
).toBe(true);
|
|
67
|
+
expect(
|
|
68
|
+
isAllowedOmniRelation({
|
|
69
|
+
sourceKind: OmniCollectionKind.Collection,
|
|
70
|
+
targetKind: OmniDocumentKind.Document,
|
|
71
|
+
relationKind: OmniRelationKind.DerivedFrom,
|
|
72
|
+
}),
|
|
73
|
+
).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('keeps references and related_to flexible for cross-record graph links', () => {
|
|
77
|
+
expect(
|
|
78
|
+
isAllowedOmniRelation({
|
|
79
|
+
sourceKind: OmniDocumentKind.Document,
|
|
80
|
+
targetKind: OmniCollectionKind.Collection,
|
|
81
|
+
relationKind: OmniRelationKind.References,
|
|
82
|
+
}),
|
|
83
|
+
).toBe(true);
|
|
84
|
+
expect(
|
|
85
|
+
isAllowedOmniRelation({
|
|
86
|
+
sourceKind: OmniCollectionKind.Collection,
|
|
87
|
+
targetKind: OmniDocumentKind.Document,
|
|
88
|
+
relationKind: OmniRelationKind.RelatedTo,
|
|
89
|
+
}),
|
|
90
|
+
).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('returns false for unexpected relation values at runtime', () => {
|
|
94
|
+
expect(
|
|
95
|
+
isAllowedOmniRelation({
|
|
96
|
+
sourceKind: OmniCollectionKind.Collection,
|
|
97
|
+
targetKind: OmniDocumentKind.Document,
|
|
98
|
+
relationKind: 'unexpected' as OmniRelationKind,
|
|
99
|
+
}),
|
|
100
|
+
).toBe(false);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { describe, expect, it } from '@jest/globals';
|
|
2
|
-
import { getMetadataArgsStorage } from 'typeorm';
|
|
3
|
-
|
|
4
|
-
import { OmniBaseEntity } from '../base/omni-base.entity.js';
|
|
5
|
-
import { OmniRelationEntity } from '../base/omni-relation.entity.js';
|
|
6
|
-
|
|
7
|
-
describe('OmniRelationEntity', () => {
|
|
8
|
-
it('extends OmniBaseEntity', () => {
|
|
9
|
-
expect(new OmniRelationEntity()).toBeInstanceOf(OmniBaseEntity);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('registers the record linkage columns and relations', () => {
|
|
13
|
-
const metadata = getMetadataArgsStorage();
|
|
14
|
-
const table = metadata.tables.find(
|
|
15
|
-
(item) => item.target === OmniRelationEntity,
|
|
16
|
-
);
|
|
17
|
-
const entityColumns = metadata.columns
|
|
18
|
-
.filter((item) => item.target === OmniRelationEntity)
|
|
19
|
-
.map((item) => item.propertyName);
|
|
20
|
-
const relations = metadata.relations
|
|
21
|
-
.filter((item) => item.target === OmniRelationEntity)
|
|
22
|
-
.map((item) => item.propertyName);
|
|
23
|
-
|
|
24
|
-
expect(table?.name).toBe('omni-relation');
|
|
25
|
-
expect(entityColumns).toEqual(
|
|
26
|
-
expect.arrayContaining([
|
|
27
|
-
'sourceRecordId',
|
|
28
|
-
'targetRecordId',
|
|
29
|
-
'kind',
|
|
30
|
-
'status',
|
|
31
|
-
'payload',
|
|
32
|
-
]),
|
|
33
|
-
);
|
|
34
|
-
expect(relations).toEqual(
|
|
35
|
-
expect.arrayContaining(['sourceRecord', 'targetRecord']),
|
|
36
|
-
);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
1
|
+
import { describe, expect, it } from '@jest/globals';
|
|
2
|
+
import { getMetadataArgsStorage } from 'typeorm';
|
|
3
|
+
|
|
4
|
+
import { OmniBaseEntity } from '../base/omni-base.entity.js';
|
|
5
|
+
import { OmniRelationEntity } from '../base/omni-relation.entity.js';
|
|
6
|
+
|
|
7
|
+
describe('OmniRelationEntity', () => {
|
|
8
|
+
it('extends OmniBaseEntity', () => {
|
|
9
|
+
expect(new OmniRelationEntity()).toBeInstanceOf(OmniBaseEntity);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('registers the record linkage columns and relations', () => {
|
|
13
|
+
const metadata = getMetadataArgsStorage();
|
|
14
|
+
const table = metadata.tables.find(
|
|
15
|
+
(item) => item.target === OmniRelationEntity,
|
|
16
|
+
);
|
|
17
|
+
const entityColumns = metadata.columns
|
|
18
|
+
.filter((item) => item.target === OmniRelationEntity)
|
|
19
|
+
.map((item) => item.propertyName);
|
|
20
|
+
const relations = metadata.relations
|
|
21
|
+
.filter((item) => item.target === OmniRelationEntity)
|
|
22
|
+
.map((item) => item.propertyName);
|
|
23
|
+
|
|
24
|
+
expect(table?.name).toBe('omni-relation');
|
|
25
|
+
expect(entityColumns).toEqual(
|
|
26
|
+
expect.arrayContaining([
|
|
27
|
+
'sourceRecordId',
|
|
28
|
+
'targetRecordId',
|
|
29
|
+
'kind',
|
|
30
|
+
'status',
|
|
31
|
+
'payload',
|
|
32
|
+
]),
|
|
33
|
+
);
|
|
34
|
+
expect(relations).toEqual(
|
|
35
|
+
expect.arrayContaining(['sourceRecord', 'targetRecord']),
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
});
|