@memberjunction/core-entities-server 6.1.0-edge.1 → 6.1.0-edge.3
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 +180 -4
- package/README.md +1 -1
- package/dist/custom/MJActionEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJActionEntityServer.server.js +4 -3
- package/dist/custom/MJActionEntityServer.server.js.map +1 -1
- package/dist/custom/MJCompanyIntegrationEntityServer.server.d.ts +36 -21
- package/dist/custom/MJCompanyIntegrationEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJCompanyIntegrationEntityServer.server.js +37 -51
- package/dist/custom/MJCompanyIntegrationEntityServer.server.js.map +1 -1
- package/dist/custom/MJMaterializedResultEntityServer.server.d.ts +23 -0
- package/dist/custom/MJMaterializedResultEntityServer.server.d.ts.map +1 -0
- package/dist/custom/MJMaterializedResultEntityServer.server.js +64 -0
- package/dist/custom/MJMaterializedResultEntityServer.server.js.map +1 -0
- package/dist/custom/MJRecordProcessEntityServer.server.d.ts +18 -3
- package/dist/custom/MJRecordProcessEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJRecordProcessEntityServer.server.js +53 -12
- package/dist/custom/MJRecordProcessEntityServer.server.js.map +1 -1
- package/dist/custom/MJVectorIndexEntityServer.server.d.ts +9 -2
- package/dist/custom/MJVectorIndexEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJVectorIndexEntityServer.server.js +25 -7
- package/dist/custom/MJVectorIndexEntityServer.server.js.map +1 -1
- package/dist/custom/RecordProcessOnChangeReconciler.d.ts +42 -0
- package/dist/custom/RecordProcessOnChangeReconciler.d.ts.map +1 -0
- package/dist/custom/RecordProcessOnChangeReconciler.js +247 -0
- package/dist/custom/RecordProcessOnChangeReconciler.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +26 -26
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { BaseEntity, BaseEntityResult, LogError, RunView } from '@memberjunction/core';
|
|
8
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
9
|
+
import { MJMaterializedResultEntity } from '@memberjunction/core-entities';
|
|
10
|
+
/**
|
|
11
|
+
* Server-side `MJ: Materialized Results` entity. Removes the `MJ: Materialized Result Queries` join row(s)
|
|
12
|
+
* that reference this materialization BEFORE the row itself is deleted.
|
|
13
|
+
*
|
|
14
|
+
* The join FKs deliberately have NO `ON DELETE CASCADE` (the MaterializedResult↔Query cascade is kept at the
|
|
15
|
+
* application layer so a physical snapshot is never silently dropped by the DB engine). When a *Query* is
|
|
16
|
+
* deleted, the generated `spDeleteQuery` already cascades its join row; this override covers the REVERSE
|
|
17
|
+
* direction — deleting the MaterializedResult directly — which would otherwise surface a raw
|
|
18
|
+
* `FK_MaterializedResultQuery_MaterializedResult` violation. FK-cleanup-before-delete pattern
|
|
19
|
+
* (guides/BASE_ENTITY_SERVER_PATTERNS.md).
|
|
20
|
+
*
|
|
21
|
+
* Out of scope here (tracked as follow-ups): dropping the physical `materialized_vw<…>` snapshot table/view on
|
|
22
|
+
* delete, and whether deleting a source Query should cascade-delete or block on its materialization — both
|
|
23
|
+
* involve DDL on the delete path and a cascade-vs-block semantics decision.
|
|
24
|
+
*/
|
|
25
|
+
let MJMaterializedResultEntityServer = class MJMaterializedResultEntityServer extends MJMaterializedResultEntity {
|
|
26
|
+
async Delete(options) {
|
|
27
|
+
if (this.IsSaved) {
|
|
28
|
+
const md = this.ProviderToUse;
|
|
29
|
+
const rv = RunView.FromMetadataProvider(md);
|
|
30
|
+
const links = await rv.RunView({
|
|
31
|
+
EntityName: 'MJ: Materialized Result Queries',
|
|
32
|
+
ExtraFilter: `MaterializedResultID='${this.ID.replace(/'/g, "''")}'`,
|
|
33
|
+
ResultType: 'entity_object',
|
|
34
|
+
}, this.ContextCurrentUser);
|
|
35
|
+
if (!links.Success) {
|
|
36
|
+
return this.failDelete(`Failed to load linked MaterializedResultQuery rows: ${links.ErrorMessage ?? 'unknown error'}`);
|
|
37
|
+
}
|
|
38
|
+
for (const link of links.Results ?? []) {
|
|
39
|
+
const deleted = await link.Delete();
|
|
40
|
+
if (!deleted) {
|
|
41
|
+
return this.failDelete(`Failed to delete linked MaterializedResultQuery ${link.ID}: ${link.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return super.Delete(options);
|
|
46
|
+
}
|
|
47
|
+
/** Records a delete failure on the result history and returns false (Delete does not throw on a logical failure). */
|
|
48
|
+
failDelete(message) {
|
|
49
|
+
LogError(`MJMaterializedResultEntityServer.Delete: ${message}`);
|
|
50
|
+
const result = new BaseEntityResult();
|
|
51
|
+
result.StartedAt = new Date();
|
|
52
|
+
result.Success = false;
|
|
53
|
+
result.Type = 'delete';
|
|
54
|
+
result.Message = message;
|
|
55
|
+
result.EndedAt = new Date();
|
|
56
|
+
this.RegisterResultHistoryEntry(result);
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
MJMaterializedResultEntityServer = __decorate([
|
|
61
|
+
RegisterClass(BaseEntity, 'MJ: Materialized Results')
|
|
62
|
+
], MJMaterializedResultEntityServer);
|
|
63
|
+
export { MJMaterializedResultEntityServer };
|
|
64
|
+
//# sourceMappingURL=MJMaterializedResultEntityServer.server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MJMaterializedResultEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJMaterializedResultEntityServer.server.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAA0C,QAAQ,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/H,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,0BAA0B,EAAmC,MAAM,+BAA+B,CAAC;AAE5G;;;;;;;;;;;;;;GAcG;AAEI,IAAM,gCAAgC,GAAtC,MAAM,gCAAiC,SAAQ,0BAA0B;IAC5D,KAAK,CAAC,MAAM,CAAC,OAA6B;QACtD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,EAAE,GAAG,IAAI,CAAC,aAA6C,CAAC;YAC9D,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;YAC5C,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,CAC1B;gBACI,UAAU,EAAE,iCAAiC;gBAC7C,WAAW,EAAE,yBAAyB,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG;gBACpE,UAAU,EAAE,eAAe;aAC9B,EACD,IAAI,CAAC,kBAAkB,CAC1B,CAAC;YACF,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO,IAAI,CAAC,UAAU,CAAC,uDAAuD,KAAK,CAAC,YAAY,IAAI,eAAe,EAAE,CAAC,CAAC;YAC3H,CAAC;YACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;gBACrC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;gBACpC,IAAI,CAAC,OAAO,EAAE,CAAC;oBACX,OAAO,IAAI,CAAC,UAAU,CAAC,mDAAmD,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,YAAY,EAAE,eAAe,IAAI,eAAe,EAAE,CAAC,CAAC;gBACnJ,CAAC;YACL,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,qHAAqH;IAC7G,UAAU,CAAC,OAAe;QAC9B,QAAQ,CAAC,4CAA4C,OAAO,EAAE,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACtC,MAAM,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAC9B,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;QACvB,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC;QACvB,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;QACzB,MAAM,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC;QACxC,OAAO,KAAK,CAAC;IACjB,CAAC;CACJ,CAAA;AAtCY,gCAAgC;IAD5C,aAAa,CAAC,UAAU,EAAE,0BAA0B,CAAC;GACzC,gCAAgC,CAsC5C"}
|
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
* definition is the single source of truth — editing it keeps its schedule in sync, no separate
|
|
7
7
|
* Scheduled Job management.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* It also owns the **on-change** trigger the same way: `OnChangeEnabled` reconciles an Entity Action
|
|
10
|
+
* binding on the process's target entity, and `OnChangeFilter` compiles into that binding's Action
|
|
11
|
+
* Filter — which is what those two columns have always claimed to do. The substrate work lives in
|
|
12
|
+
* `RecordProcessOnChangeReconciler` so this class stays a dispatcher rather than growing a second
|
|
13
|
+
* hundred-line reconciler inside `Save()`.
|
|
10
14
|
* @module @memberjunction/core-entities-server
|
|
11
15
|
*/
|
|
12
16
|
import { EntitySaveOptions } from '@memberjunction/core';
|
|
@@ -45,8 +49,19 @@ export declare class MJRecordProcessEntityServer extends MJRecordProcessEntity {
|
|
|
45
49
|
* save — the record itself is valid; a reconciliation error is logged for the operator.
|
|
46
50
|
*/
|
|
47
51
|
Save(options?: EntitySaveOptions): Promise<boolean>;
|
|
48
|
-
/**
|
|
49
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Runs one reconciliation without letting it fail the save.
|
|
54
|
+
*
|
|
55
|
+
* The record itself is valid and already persisted; a substrate error is an operator problem,
|
|
56
|
+
* not a reason to reject the user's edit. Each trigger is wrapped separately so a failure in one
|
|
57
|
+
* cannot skip the other — a process whose schedule reconciliation broke should still get its
|
|
58
|
+
* on-change binding.
|
|
59
|
+
*/
|
|
60
|
+
private reconcileSafely;
|
|
61
|
+
/** True when any of the named fields is dirty (fast-path, read before the save clears them). */
|
|
62
|
+
private anyFieldDirty;
|
|
63
|
+
/** Ensures the owned Entity Action binding matches the process's on-change settings. */
|
|
64
|
+
private reconcileOnChangeBinding;
|
|
50
65
|
/** Ensures the owned Scheduled Job matches the process's current schedule state. */
|
|
51
66
|
private reconcileScheduledJob;
|
|
52
67
|
/** Resolves the "Run Record Process" Scheduled Job Type ID, or throws if the seed is absent. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJRecordProcessEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJRecordProcessEntityServer.server.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"MJRecordProcessEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJRecordProcessEntityServer.server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAEH,iBAAiB,EAKpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAkD,MAAM,+BAA+B,CAAC;AAkBtH,wGAAwG;AACxG,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;AAElD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,cAAc,CAEnI;AAED,kGAAkG;AAClG,wBAAgB,uBAAuB,CAAC,CAAC,EAAE;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CAC3B,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,CASzH;AAED,qBACa,2BAA4B,SAAQ,qBAAqB;IAClE;;;;OAIG;IACmB,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAmBzE;;;;;;;OAOG;YACW,eAAe;IAW7B,gGAAgG;IAChG,OAAO,CAAC,aAAa;IAIrB,wFAAwF;YAC1E,wBAAwB;IAOtC,oFAAoF;YACtE,qBAAqB;IAcnC,gGAAgG;YAClF,gBAAgB;IAa9B,4FAA4F;YAC9E,YAAY;IAgB1B,yFAAyF;YAC3E,eAAe;IA4B7B,iFAAiF;YACnE,mBAAmB;CAUpC"}
|
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
* definition is the single source of truth — editing it keeps its schedule in sync, no separate
|
|
7
7
|
* Scheduled Job management.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* It also owns the **on-change** trigger the same way: `OnChangeEnabled` reconciles an Entity Action
|
|
10
|
+
* binding on the process's target entity, and `OnChangeFilter` compiles into that binding's Action
|
|
11
|
+
* Filter — which is what those two columns have always claimed to do. The substrate work lives in
|
|
12
|
+
* `RecordProcessOnChangeReconciler` so this class stays a dispatcher rather than growing a second
|
|
13
|
+
* hundred-line reconciler inside `Save()`.
|
|
10
14
|
* @module @memberjunction/core-entities-server
|
|
11
15
|
*/
|
|
12
16
|
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
@@ -18,10 +22,19 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
18
22
|
import { RegisterClass, SafeJSONParse, UUIDsEqual } from '@memberjunction/global';
|
|
19
23
|
import { BaseEntity, LogError, RunView, } from '@memberjunction/core';
|
|
20
24
|
import { MJRecordProcessEntity } from '@memberjunction/core-entities';
|
|
25
|
+
import { ReconcileRecordProcessOnChange } from './RecordProcessOnChangeReconciler.js';
|
|
21
26
|
/** The `MJ: Scheduled Job Types.Name` seeded for record-process recurrence (metadata-driven). */
|
|
22
27
|
const RUN_RECORD_PROCESS_JOB_TYPE = 'Run Record Process';
|
|
23
28
|
/** Fields whose change can affect the owned Scheduled Job — reconcile only when one is dirty. */
|
|
24
29
|
const SCHEDULE_RELEVANT_FIELDS = ['ScheduleEnabled', 'CronExpression', 'Timezone', 'Status', 'Name'];
|
|
30
|
+
/**
|
|
31
|
+
* Fields whose change can affect the owned Entity Action binding.
|
|
32
|
+
*
|
|
33
|
+
* `EntityID` is in the list because the binding is anchored to it: repointing a process at a
|
|
34
|
+
* different entity while its old binding still fires would leave the process running against
|
|
35
|
+
* records it no longer describes.
|
|
36
|
+
*/
|
|
37
|
+
const ON_CHANGE_RELEVANT_FIELDS = ['OnChangeEnabled', 'OnChangeInvocationType', 'OnChangeFilter', 'Status', 'EntityID'];
|
|
25
38
|
/**
|
|
26
39
|
* PURE decision (exported for tests): a process owns an *active* recurrence job only when it is
|
|
27
40
|
* `Active`, has `ScheduleEnabled`, and carries a non-empty `CronExpression`; otherwise the owned
|
|
@@ -48,21 +61,49 @@ let MJRecordProcessEntityServer = class MJRecordProcessEntityServer extends MJRe
|
|
|
48
61
|
* save — the record itself is valid; a reconciliation error is logged for the operator.
|
|
49
62
|
*/
|
|
50
63
|
async Save(options) {
|
|
51
|
-
|
|
64
|
+
// Both reads happen BEFORE the save, because saving resets every dirty flag — asking
|
|
65
|
+
// afterwards would report that nothing changed and reconcile nothing, forever.
|
|
66
|
+
const isNew = !this.IsSaved;
|
|
67
|
+
const reconcileSchedule = isNew || this.anyFieldDirty(SCHEDULE_RELEVANT_FIELDS);
|
|
68
|
+
const reconcileOnChange = isNew || this.anyFieldDirty(ON_CHANGE_RELEVANT_FIELDS);
|
|
52
69
|
const saved = await super.Save(options);
|
|
53
|
-
if (saved
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
70
|
+
if (!saved)
|
|
71
|
+
return saved;
|
|
72
|
+
if (reconcileSchedule) {
|
|
73
|
+
await this.reconcileSafely('schedule', () => this.reconcileScheduledJob());
|
|
74
|
+
}
|
|
75
|
+
if (reconcileOnChange) {
|
|
76
|
+
await this.reconcileSafely('on-change', () => this.reconcileOnChangeBinding());
|
|
60
77
|
}
|
|
61
78
|
return saved;
|
|
62
79
|
}
|
|
63
|
-
/**
|
|
64
|
-
|
|
65
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Runs one reconciliation without letting it fail the save.
|
|
82
|
+
*
|
|
83
|
+
* The record itself is valid and already persisted; a substrate error is an operator problem,
|
|
84
|
+
* not a reason to reject the user's edit. Each trigger is wrapped separately so a failure in one
|
|
85
|
+
* cannot skip the other — a process whose schedule reconciliation broke should still get its
|
|
86
|
+
* on-change binding.
|
|
87
|
+
*/
|
|
88
|
+
async reconcileSafely(label, work) {
|
|
89
|
+
try {
|
|
90
|
+
await work();
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
LogError(`MJRecordProcessEntityServer: ${label} reconciliation failed for '${this.Name}' (${this.ID}): ` +
|
|
94
|
+
`${e instanceof Error ? e.message : String(e)}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** True when any of the named fields is dirty (fast-path, read before the save clears them). */
|
|
98
|
+
anyFieldDirty(fields) {
|
|
99
|
+
return fields.some((f) => this.GetFieldByName(f)?.Dirty ?? false);
|
|
100
|
+
}
|
|
101
|
+
/** Ensures the owned Entity Action binding matches the process's on-change settings. */
|
|
102
|
+
async reconcileOnChangeBinding() {
|
|
103
|
+
await ReconcileRecordProcessOnChange(this, {
|
|
104
|
+
Provider: this.ProviderToUse,
|
|
105
|
+
ContextUser: this.ContextCurrentUser,
|
|
106
|
+
});
|
|
66
107
|
}
|
|
67
108
|
/** Ensures the owned Scheduled Job matches the process's current schedule state. */
|
|
68
109
|
async reconcileScheduledJob() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJRecordProcessEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJRecordProcessEntityServer.server.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"MJRecordProcessEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJRecordProcessEntityServer.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,8 +33,15 @@ export declare class MJVectorIndexEntityServer extends MJVectorIndexEntity {
|
|
|
33
33
|
*/
|
|
34
34
|
private getVectorDBInstance;
|
|
35
35
|
/**
|
|
36
|
-
* Resolve embedding dimensions
|
|
37
|
-
*
|
|
36
|
+
* Resolve the embedding dimensions to create the provider index at.
|
|
37
|
+
*
|
|
38
|
+
* Prefers this index's own `Dimensions` column, which is where the operator states it and what the
|
|
39
|
+
* embedding call already honors. Falling straight through to 1536 ignored that column entirely, so
|
|
40
|
+
* an index for any other model was created at the wrong width — harmless with providers that don't
|
|
41
|
+
* enforce it, and fatal with ones that do: a colocated SQL Server index is a `VECTOR(n)` column, and
|
|
42
|
+
* inserting 384-dimension vectors into a `VECTOR(1536)` is rejected outright.
|
|
43
|
+
*
|
|
44
|
+
* 1536 (OpenAI text-embedding-3-small) remains the fallback for records that never set it.
|
|
38
45
|
*/
|
|
39
46
|
private resolveDimensions;
|
|
40
47
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJVectorIndexEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJVectorIndexEntityServer.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAA0B,MAAM,+BAA+B,CAAC;AAI5F;;;;GAIG;AACH,qBACa,yBAA0B,SAAQ,mBAAmB;IAC9D;;OAEG;IACmB,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAa9C;;OAEG;IACmB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAShD;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;OAEG;YACW,qBAAqB;IAuCnC;;OAEG;YACW,uBAAuB;IAkBrC;;;OAGG;YACW,mBAAmB;
|
|
1
|
+
{"version":3,"file":"MJVectorIndexEntityServer.server.d.ts","sourceRoot":"","sources":["../../src/custom/MJVectorIndexEntityServer.server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAA0B,MAAM,+BAA+B,CAAC;AAI5F;;;;GAIG;AACH,qBACa,yBAA0B,SAAQ,mBAAmB;IAC9D;;OAEG;IACmB,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAa9C;;OAEG;IACmB,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAShD;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;OAEG;YACW,qBAAqB;IAuCnC;;OAEG;YACW,uBAAuB;IAkBrC;;;OAGG;YACW,mBAAmB;IAgDjC;;;;;;;;;;OAUG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;OAGG;YACW,oBAAoB;CAiCrC"}
|
|
@@ -143,21 +143,39 @@ let MJVectorIndexEntityServer = class MJVectorIndexEntityServer extends MJVector
|
|
|
143
143
|
LogError(`VectorDatabase "${vectorDB.Name}" has no ClassKey configured`);
|
|
144
144
|
return null;
|
|
145
145
|
}
|
|
146
|
+
// Instantiate BEFORE gating on the key, then wire the host connection. A colocated provider
|
|
147
|
+
// (SQLServerVectorDatabase, pgvector) stores vectors in this same database: it has no
|
|
148
|
+
// credentials to present, and it throws "requires a host connection" unless the active data
|
|
149
|
+
// provider is handed to it. Neither is knowable until the instance exists. Same ordering as
|
|
150
|
+
// the EntityDocument and ContentSource vectorization pipelines.
|
|
151
|
+
// The sentinel is required: `VectorDBBase`'s constructor rejects an empty key and colocated
|
|
152
|
+
// providers do not override it, so '' would throw for the very case this supports.
|
|
146
153
|
const apiKey = GetAIAPIKey(classKey);
|
|
147
|
-
|
|
154
|
+
const instance = MJGlobal.Instance.ClassFactory.CreateInstance(VectorDBBase, classKey, apiKey || 'colocated');
|
|
155
|
+
if (!instance) {
|
|
156
|
+
LogError(`Failed to create vector DB instance for "${classKey}"`);
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
instance.TryWireColocatedHost(this.ProviderToUse);
|
|
160
|
+
if (!instance.SupportsColocatedQuery && instance.RequiresAPIKey && !apiKey) {
|
|
148
161
|
LogError(`No API key found for vector DB provider "${classKey}"`);
|
|
149
162
|
return null;
|
|
150
163
|
}
|
|
151
|
-
return
|
|
164
|
+
return instance;
|
|
152
165
|
}
|
|
153
166
|
/**
|
|
154
|
-
* Resolve embedding dimensions
|
|
155
|
-
*
|
|
167
|
+
* Resolve the embedding dimensions to create the provider index at.
|
|
168
|
+
*
|
|
169
|
+
* Prefers this index's own `Dimensions` column, which is where the operator states it and what the
|
|
170
|
+
* embedding call already honors. Falling straight through to 1536 ignored that column entirely, so
|
|
171
|
+
* an index for any other model was created at the wrong width — harmless with providers that don't
|
|
172
|
+
* enforce it, and fatal with ones that do: a colocated SQL Server index is a `VECTOR(n)` column, and
|
|
173
|
+
* inserting 384-dimension vectors into a `VECTOR(1536)` is rejected outright.
|
|
174
|
+
*
|
|
175
|
+
* 1536 (OpenAI text-embedding-3-small) remains the fallback for records that never set it.
|
|
156
176
|
*/
|
|
157
177
|
resolveDimensions() {
|
|
158
|
-
|
|
159
|
-
// For now, default to 1536 which covers most common embedding models
|
|
160
|
-
return 1536;
|
|
178
|
+
return this.Dimensions ?? 1536;
|
|
161
179
|
}
|
|
162
180
|
/**
|
|
163
181
|
* After provider creates the index, save the returned metadata back to our record.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MJVectorIndexEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJVectorIndexEntityServer.server.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAY,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAA0B,MAAM,+BAA+B,CAAC;AAC5F,OAAO,EAAE,YAAY,EAA2C,MAAM,6BAA6B,CAAC;AACpG,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD;;;;GAIG;AAEI,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,mBAAmB;IAC9D;;OAEG;IACa,KAAK,CAAC,IAAI;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC;QACrC,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QAEtC,IAAI,UAAU,IAAI,KAAK,EAAE,CAAC;YACtB,IAAI,CAAC,qBAAqB,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBACzC,QAAQ,CAAC,2BAA2B,IAAI,CAAC,IAAI,yBAAyB,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;YAC9F,CAAC,CAAC,CAAC;QACP,CAAC;QAED,OAAO,UAAU,CAAC;IACtB,CAAC;IAED;;OAEG;IACa,KAAK,CAAC,MAAM;QACxB,oFAAoF;QACpF,MAAM,IAAI,CAAC,uBAAuB,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACjD,QAAQ,CAAC,2BAA2B,IAAI,CAAC,IAAI,6DAA6D,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAClI,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACK,iBAAiB,CAAC,IAAY;QAClC,iGAAiG;QACjG,IAAI,SAAS,GAAG,IAAI;aACf,WAAW,EAAE;aACb,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;aACvB,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;aAC1B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAO,4BAA4B;aACtD,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAK,gCAAgC;QAEhE,IAAI,SAAS,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YACxB,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,kGAAkG,CAAC,CAAC;QAC3I,CAAC;QAED,OAAO,SAAS,CAAC;IACrB,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,qBAAqB;QAC/B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,QAAQ,CAAC,0DAA0D,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAC5F,OAAO;QACX,CAAC;QAED,0FAA0F;QAC1F,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,aAAa,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;YAC9B,SAAS,CAAC,8BAA8B,IAAI,CAAC,IAAI,SAAS,aAAa,wCAAwC,CAAC,CAAC;QACrH,CAAC;QAED,MAAM,MAAM,GAAsB;YAC9B,EAAE,EAAE,aAAa;YACjB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE;YACnC,MAAM,EAAE,QAAgC;YACxC,gBAAgB,EAAE;gBACd,UAAU,EAAE;oBACR,KAAK,EAAE,KAAK;oBACZ,MAAM,EAAE,WAAW;iBACtB;aACJ;SACJ,CAAC;QAEF,SAAS,CAAC,mBAAmB,aAAa,4BAA4B,CAAC,CAAC;QACxE,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAClD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,SAAS,CAAC,UAAU,aAAa,oCAAoC,CAAC,CAAC;gBACvE,MAAM,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;YACxE,CAAC;iBAAM,CAAC;gBACJ,QAAQ,CAAC,2CAA2C,aAAa,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7F,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,QAAQ,CAAC,mCAAmC,aAAa,yBAAyB,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAC1G,CAAC;IACL,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,uBAAuB;QACjC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,QAAQ,CAAC,0DAA0D,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAC5F,OAAO;QACX,CAAC;QAED,6FAA6F;QAC7F,MAAM,iBAAiB,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/E,SAAS,CAAC,mBAAmB,iBAAiB,8BAA8B,CAAC,CAAC;QAC9E,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC;QACrE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,SAAS,CAAC,UAAU,iBAAiB,yBAAyB,CAAC,CAAC;QACpE,CAAC;aAAM,CAAC;YACJ,QAAQ,CAAC,2CAA2C,iBAAiB,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QACjG,CAAC;IACL,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,mBAAmB;QAC7B,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAyB;YACpD,UAAU,EAAE,sBAAsB;YAClC,WAAW,EAAE,OAAO,IAAI,CAAC,gBAAgB,GAAG;YAC5C,UAAU,EAAE,eAAe;SAC9B,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAE5B,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,QAAQ,CAAC,0BAA0B,IAAI,CAAC,gBAAgB,YAAY,CAAC,CAAC;YACtE,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;QACnC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,QAAQ,CAAC,mBAAmB,QAAQ,CAAC,IAAI,8BAA8B,CAAC,CAAC;YACzE,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;QACrC,
|
|
1
|
+
{"version":3,"file":"MJVectorIndexEntityServer.server.js","sourceRoot":"","sources":["../../src/custom/MJVectorIndexEntityServer.server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
2
|
+
import { MJRecordProcessEntity } from '@memberjunction/core-entities';
|
|
3
|
+
/** The Action an on-change binding dispatches to. Exists already; this only binds to it. */
|
|
4
|
+
export declare const RUN_RECORD_PROCESS_ACTION = "Run Record Process";
|
|
5
|
+
/**
|
|
6
|
+
* Turns the record that changed into the action's `Scope` parameter.
|
|
7
|
+
*
|
|
8
|
+
* Evaluated per-invocation as an `EntityActionParam` of ValueType `Script`, because the whole point
|
|
9
|
+
* of an on-change trigger is that the record differs every time — a Static value would pin the
|
|
10
|
+
* binding to whichever record happened to be open when it was configured.
|
|
11
|
+
*
|
|
12
|
+
* `ToConcatenatedString()` and not `ToString()`: `RecordRef.RecordID` is documented as the primary
|
|
13
|
+
* key "serialized to a composite-key-safe string", which is that format. `ToString()` is a display
|
|
14
|
+
* format and would silently fail to resolve a composite key.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ON_CHANGE_SCOPE_SCRIPT: string;
|
|
17
|
+
/**
|
|
18
|
+
* Whether a process should own an *active* on-change binding.
|
|
19
|
+
*
|
|
20
|
+
* Pure and exported so the decision is testable without a database. An invocation type is required
|
|
21
|
+
* rather than defaulted: guessing `AfterUpdate` would produce a trigger firing on an event the
|
|
22
|
+
* author never chose, and on the wrong one there is no error — only runs nobody expected.
|
|
23
|
+
*/
|
|
24
|
+
export declare function decideOnChangeAction(p: {
|
|
25
|
+
status: string;
|
|
26
|
+
onChangeEnabled: boolean;
|
|
27
|
+
onChangeInvocationType: string | null;
|
|
28
|
+
}): 'upsert' | 'disable';
|
|
29
|
+
/** Everything the reconciler needs from its caller. */
|
|
30
|
+
export type OnChangeReconcileContext = {
|
|
31
|
+
Provider: IMetadataProvider;
|
|
32
|
+
ContextUser: UserInfo;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Brings a Record Process's owned Entity Action binding in line with its on-change settings.
|
|
36
|
+
*
|
|
37
|
+
* Turning the trigger off **disables** the binding rather than deleting it, matching how the
|
|
38
|
+
* schedule reconciler treats its owned job: the row carries the history of what this process used to
|
|
39
|
+
* fire on, and a trigger someone switched off by mistake should be recoverable.
|
|
40
|
+
*/
|
|
41
|
+
export declare function ReconcileRecordProcessOnChange(process: MJRecordProcessEntity, context: OnChangeReconcileContext): Promise<void>;
|
|
42
|
+
//# sourceMappingURL=RecordProcessOnChangeReconciler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RecordProcessOnChangeReconciler.d.ts","sourceRoot":"","sources":["../../src/custom/RecordProcessOnChangeReconciler.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,iBAAiB,EAAqB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACtF,OAAO,EASH,qBAAqB,EACxB,MAAM,+BAA+B,CAAC;AAGvC,4FAA4F;AAC5F,eAAO,MAAM,yBAAyB,uBAAuB,CAAC;AAE9D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,QAEsD,CAAC;AAE1F;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,OAAO,CAAC;IACzB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC,GAAG,QAAQ,GAAG,SAAS,CAEvB;AAED,uDAAuD;AACvD,MAAM,MAAM,wBAAwB,GAAG;IACnC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,WAAW,EAAE,QAAQ,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CAChD,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,wBAAwB,GAClC,OAAO,CAAC,IAAI,CAAC,CA6Cf"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Reconciles a Record Process's **on-change** trigger onto the Entity Action rows the
|
|
3
|
+
* save pipeline already reads.
|
|
4
|
+
*
|
|
5
|
+
* `RecordProcess.OnChangeEnabled` has described this since the column shipped — *"the process runs
|
|
6
|
+
* per-record on save via an owned Entity Action"* — and `OnChangeFilter` promised to *"compile into
|
|
7
|
+
* the owned Entity Action Filter"*. Neither owned anything: the schedule trigger reconciled and the
|
|
8
|
+
* change trigger was a flag that read as configured and did nothing. That is the worst shape for a
|
|
9
|
+
* trigger to be in, because the UI shows it enabled and no run ever appears.
|
|
10
|
+
*
|
|
11
|
+
* Split out of the entity subclass rather than added to it because the schedule reconciliation is
|
|
12
|
+
* already a hundred lines of the same shape and a single `Save()` override owning both would be the
|
|
13
|
+
* kind of method nobody can safely change. Both call sites stay in the subclass; the substrate work
|
|
14
|
+
* lives here.
|
|
15
|
+
*
|
|
16
|
+
* **Nothing here is new machinery.** `HandleEntityActions` has fired entity actions from the save
|
|
17
|
+
* pipeline all along, `Run Record Process` is an existing action, and `ActionFilter` evaluation with
|
|
18
|
+
* the change context landed with transition filters. What was missing was rows.
|
|
19
|
+
*
|
|
20
|
+
* @module @memberjunction/core-entities-server
|
|
21
|
+
*/
|
|
22
|
+
import { BuildChangeFilterCode } from '@memberjunction/actions-base';
|
|
23
|
+
import { LogError, RunView } from '@memberjunction/core';
|
|
24
|
+
import { UUIDsEqual } from '@memberjunction/global';
|
|
25
|
+
/** The Action an on-change binding dispatches to. Exists already; this only binds to it. */
|
|
26
|
+
export const RUN_RECORD_PROCESS_ACTION = 'Run Record Process';
|
|
27
|
+
/**
|
|
28
|
+
* Turns the record that changed into the action's `Scope` parameter.
|
|
29
|
+
*
|
|
30
|
+
* Evaluated per-invocation as an `EntityActionParam` of ValueType `Script`, because the whole point
|
|
31
|
+
* of an on-change trigger is that the record differs every time — a Static value would pin the
|
|
32
|
+
* binding to whichever record happened to be open when it was configured.
|
|
33
|
+
*
|
|
34
|
+
* `ToConcatenatedString()` and not `ToString()`: `RecordRef.RecordID` is documented as the primary
|
|
35
|
+
* key "serialized to a composite-key-safe string", which is that format. `ToString()` is a display
|
|
36
|
+
* format and would silently fail to resolve a composite key.
|
|
37
|
+
*/
|
|
38
|
+
export const ON_CHANGE_SCOPE_SCRIPT = "EntityActionContext.result = JSON.stringify({ Kind: 'records', " +
|
|
39
|
+
'RecordIDs: [EntityActionContext.entityObject.PrimaryKey.ToConcatenatedString()] });';
|
|
40
|
+
/**
|
|
41
|
+
* Whether a process should own an *active* on-change binding.
|
|
42
|
+
*
|
|
43
|
+
* Pure and exported so the decision is testable without a database. An invocation type is required
|
|
44
|
+
* rather than defaulted: guessing `AfterUpdate` would produce a trigger firing on an event the
|
|
45
|
+
* author never chose, and on the wrong one there is no error — only runs nobody expected.
|
|
46
|
+
*/
|
|
47
|
+
export function decideOnChangeAction(p) {
|
|
48
|
+
return p.status === 'Active' && p.onChangeEnabled && !!p.onChangeInvocationType ? 'upsert' : 'disable';
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Brings a Record Process's owned Entity Action binding in line with its on-change settings.
|
|
52
|
+
*
|
|
53
|
+
* Turning the trigger off **disables** the binding rather than deleting it, matching how the
|
|
54
|
+
* schedule reconciler treats its owned job: the row carries the history of what this process used to
|
|
55
|
+
* fire on, and a trigger someone switched off by mistake should be recoverable.
|
|
56
|
+
*/
|
|
57
|
+
export async function ReconcileRecordProcessOnChange(process, context) {
|
|
58
|
+
const action = decideOnChangeAction({
|
|
59
|
+
status: process.Status,
|
|
60
|
+
onChangeEnabled: process.OnChangeEnabled,
|
|
61
|
+
onChangeInvocationType: process.OnChangeInvocationType,
|
|
62
|
+
});
|
|
63
|
+
const existing = await findOwnedEntityAction(process, context);
|
|
64
|
+
if (action === 'disable') {
|
|
65
|
+
if (existing && existing.Status !== 'Disabled') {
|
|
66
|
+
existing.Status = 'Disabled';
|
|
67
|
+
if (!(await existing.Save())) {
|
|
68
|
+
throw new Error(`failed disabling the on-change binding: ${existing.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const actionRow = await resolveAction(context);
|
|
74
|
+
const invocationTypeID = await resolveInvocationTypeID(process.OnChangeInvocationType, context);
|
|
75
|
+
const binding = existing ?? await context.Provider.GetEntityObject('MJ: Entity Actions', context.ContextUser);
|
|
76
|
+
if (!existing) {
|
|
77
|
+
binding.NewRecord();
|
|
78
|
+
binding.EntityID = process.EntityID;
|
|
79
|
+
binding.ActionID = actionRow.ID;
|
|
80
|
+
}
|
|
81
|
+
binding.Status = 'Active';
|
|
82
|
+
if (!(await binding.Save())) {
|
|
83
|
+
throw new Error(`failed saving the on-change binding: ${binding.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
84
|
+
}
|
|
85
|
+
// The invocation type is reconciled as a set, not edited in place: switching from AfterUpdate to
|
|
86
|
+
// AfterCreate must leave the process firing on exactly one event. Editing the existing row would
|
|
87
|
+
// work; leaving the old one Active alongside a new one would double-fire, which is the failure
|
|
88
|
+
// this replaces rather than risks.
|
|
89
|
+
await reconcileInvocation(binding.ID, invocationTypeID, context);
|
|
90
|
+
await upsertActionParam(binding.ID, actionRow.ID, 'RecordProcessID', 'Static', process.ID, context);
|
|
91
|
+
await upsertActionParam(binding.ID, actionRow.ID, 'Scope', 'Script', ON_CHANGE_SCOPE_SCRIPT, context);
|
|
92
|
+
await reconcileFilter(binding.ID, process.OnChangeFilter, context);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The binding this process owns, if it has one.
|
|
96
|
+
*
|
|
97
|
+
* Matched on the `RecordProcessID` param rather than on entity + action, because `Run Record Process`
|
|
98
|
+
* is one shared action: every process watching a given entity would otherwise collide on the same
|
|
99
|
+
* pair, and reusing that row means rewriting its `RecordProcessID` — silently repointing the first
|
|
100
|
+
* process's trigger at the second process's definition, with the first still looking configured.
|
|
101
|
+
*/
|
|
102
|
+
async function findOwnedEntityAction(process, context) {
|
|
103
|
+
const rv = RunView.FromMetadataProvider(context.Provider);
|
|
104
|
+
const candidates = await rv.RunView({
|
|
105
|
+
EntityName: 'MJ: Entity Actions',
|
|
106
|
+
ExtraFilter: `EntityID='${process.EntityID}'`,
|
|
107
|
+
ResultType: 'entity_object',
|
|
108
|
+
}, context.ContextUser);
|
|
109
|
+
const rows = candidates.Results ?? [];
|
|
110
|
+
if (rows.length === 0)
|
|
111
|
+
return null;
|
|
112
|
+
const params = await rv.RunView({
|
|
113
|
+
EntityName: 'MJ: Entity Action Params',
|
|
114
|
+
ExtraFilter: `ActionParam='RecordProcessID' AND EntityActionID IN (${rows.map((r) => `'${r.ID}'`).join(',')})`,
|
|
115
|
+
ResultType: 'entity_object',
|
|
116
|
+
}, context.ContextUser);
|
|
117
|
+
const mine = (params.Results ?? []).find((p) => p.Value != null && UUIDsEqual(p.Value, process.ID));
|
|
118
|
+
return mine ? rows.find((r) => UUIDsEqual(r.ID, mine.EntityActionID)) ?? null : null;
|
|
119
|
+
}
|
|
120
|
+
/** Resolves the `Run Record Process` action, or says plainly that the seed is missing. */
|
|
121
|
+
async function resolveAction(context) {
|
|
122
|
+
const result = await RunView.FromMetadataProvider(context.Provider).RunView({ EntityName: 'MJ: Actions', ExtraFilter: `Name='${RUN_RECORD_PROCESS_ACTION}'`, ResultType: 'entity_object' }, context.ContextUser);
|
|
123
|
+
const action = result.Results?.[0];
|
|
124
|
+
if (!action) {
|
|
125
|
+
throw new Error(`the '${RUN_RECORD_PROCESS_ACTION}' action is not present — has the metadata seed been pushed?`);
|
|
126
|
+
}
|
|
127
|
+
return action;
|
|
128
|
+
}
|
|
129
|
+
/** Resolves the invocation type the process named. */
|
|
130
|
+
async function resolveInvocationTypeID(name, context) {
|
|
131
|
+
const result = await RunView.FromMetadataProvider(context.Provider).RunView({ EntityName: 'MJ: Entity Action Invocation Types', ExtraFilter: `Name='${name}'`, ResultType: 'simple' }, context.ContextUser);
|
|
132
|
+
const row = result.Results?.[0];
|
|
133
|
+
if (!row)
|
|
134
|
+
throw new Error(`entity action invocation type '${name}' is not seeded`);
|
|
135
|
+
return row.ID;
|
|
136
|
+
}
|
|
137
|
+
/** Makes the named invocation the only active one on this binding. */
|
|
138
|
+
async function reconcileInvocation(entityActionID, invocationTypeID, context) {
|
|
139
|
+
const result = await RunView.FromMetadataProvider(context.Provider).RunView({
|
|
140
|
+
EntityName: 'MJ: Entity Action Invocations',
|
|
141
|
+
ExtraFilter: `EntityActionID='${entityActionID}'`,
|
|
142
|
+
ResultType: 'entity_object',
|
|
143
|
+
}, context.ContextUser);
|
|
144
|
+
let found = false;
|
|
145
|
+
for (const row of result.Results ?? []) {
|
|
146
|
+
const wanted = UUIDsEqual(row.InvocationTypeID, invocationTypeID);
|
|
147
|
+
found ||= wanted;
|
|
148
|
+
const status = wanted ? 'Active' : 'Disabled';
|
|
149
|
+
if (row.Status !== status) {
|
|
150
|
+
row.Status = status;
|
|
151
|
+
if (!(await row.Save())) {
|
|
152
|
+
LogError(`RecordProcess on-change: could not set invocation ${row.ID} to ${status}: ` +
|
|
153
|
+
`${row.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (found)
|
|
158
|
+
return;
|
|
159
|
+
const row = await context.Provider.GetEntityObject('MJ: Entity Action Invocations', context.ContextUser);
|
|
160
|
+
row.NewRecord();
|
|
161
|
+
row.EntityActionID = entityActionID;
|
|
162
|
+
row.InvocationTypeID = invocationTypeID;
|
|
163
|
+
row.Status = 'Active';
|
|
164
|
+
if (!(await row.Save())) {
|
|
165
|
+
throw new Error(`failed creating the on-change invocation: ${row.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/** Finds or creates one Entity Action Param binding for the on-change trigger. */
|
|
169
|
+
async function upsertActionParam(entityActionID, actionID, paramName, valueType, value, context) {
|
|
170
|
+
const rv = RunView.FromMetadataProvider(context.Provider);
|
|
171
|
+
const paramResult = await rv.RunView({
|
|
172
|
+
EntityName: 'MJ: Action Params',
|
|
173
|
+
ExtraFilter: `ActionID='${actionID}' AND Name='${paramName}'`,
|
|
174
|
+
ResultType: 'entity_object',
|
|
175
|
+
}, context.ContextUser);
|
|
176
|
+
const actionParam = paramResult.Results?.[0];
|
|
177
|
+
if (!actionParam) {
|
|
178
|
+
throw new Error(`the '${RUN_RECORD_PROCESS_ACTION}' action has no ${paramName} parameter to bind`);
|
|
179
|
+
}
|
|
180
|
+
const existingResult = await rv.RunView({
|
|
181
|
+
EntityName: 'MJ: Entity Action Params',
|
|
182
|
+
ExtraFilter: `EntityActionID='${entityActionID}' AND ActionParamID='${actionParam.ID}'`,
|
|
183
|
+
ResultType: 'entity_object',
|
|
184
|
+
}, context.ContextUser);
|
|
185
|
+
const existing = existingResult.Results?.[0];
|
|
186
|
+
const row = existing ?? await context.Provider.GetEntityObject('MJ: Entity Action Params', context.ContextUser);
|
|
187
|
+
if (!existing)
|
|
188
|
+
row.NewRecord();
|
|
189
|
+
row.EntityActionID = entityActionID;
|
|
190
|
+
row.ActionParamID = actionParam.ID;
|
|
191
|
+
row.ValueType = valueType;
|
|
192
|
+
row.Value = value;
|
|
193
|
+
if (!(await row.Save())) {
|
|
194
|
+
throw new Error(`failed binding ${paramName} to the on-change trigger: ${row.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Compiles `OnChangeFilter` into the owned Action Filter, exactly as the column documents.
|
|
199
|
+
*
|
|
200
|
+
* Shares `BuildChangeFilterCode` with the workflow trigger, so `DidFieldChangeToValue('Status',
|
|
201
|
+
* 'Approved')` means the same thing in both places — a user who learned one surface has learned the
|
|
202
|
+
* other. Clearing the filter disables the binding rather than deleting the row, so the expression
|
|
203
|
+
* survives a mis-click.
|
|
204
|
+
*/
|
|
205
|
+
async function reconcileFilter(entityActionID, filter, context) {
|
|
206
|
+
const rv = RunView.FromMetadataProvider(context.Provider);
|
|
207
|
+
const bindingResult = await rv.RunView({
|
|
208
|
+
EntityName: 'MJ: Entity Action Filters',
|
|
209
|
+
ExtraFilter: `EntityActionID='${entityActionID}'`,
|
|
210
|
+
OrderBy: 'Sequence ASC',
|
|
211
|
+
ResultType: 'entity_object',
|
|
212
|
+
}, context.ContextUser);
|
|
213
|
+
const binding = bindingResult.Results?.[0] ?? null;
|
|
214
|
+
const expression = filter?.trim() ?? '';
|
|
215
|
+
if (!expression) {
|
|
216
|
+
if (binding && binding.Status !== 'Disabled') {
|
|
217
|
+
binding.Status = 'Disabled';
|
|
218
|
+
if (!(await binding.Save())) {
|
|
219
|
+
throw new Error(`failed clearing the on-change filter: ${binding.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const filterRow = await context.Provider.GetEntityObject('MJ: Action Filters', context.ContextUser);
|
|
225
|
+
if (!binding?.ActionFilterID || !(await filterRow.Load(binding.ActionFilterID))) {
|
|
226
|
+
filterRow.NewRecord();
|
|
227
|
+
}
|
|
228
|
+
filterRow.Code = BuildChangeFilterCode(expression);
|
|
229
|
+
filterRow.UserDescription = expression;
|
|
230
|
+
filterRow.CodeExplanation =
|
|
231
|
+
"Generated from a Record Process's OnChangeFilter. Evaluated against the record change that fired the " +
|
|
232
|
+
'trigger; the process runs for that record only when it is true.';
|
|
233
|
+
if (!(await filterRow.Save())) {
|
|
234
|
+
throw new Error(`failed saving the on-change filter: ${filterRow.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
235
|
+
}
|
|
236
|
+
const row = binding ?? await context.Provider.GetEntityObject('MJ: Entity Action Filters', context.ContextUser);
|
|
237
|
+
if (!binding)
|
|
238
|
+
row.NewRecord();
|
|
239
|
+
row.EntityActionID = entityActionID;
|
|
240
|
+
row.ActionFilterID = filterRow.ID;
|
|
241
|
+
row.Sequence = 1;
|
|
242
|
+
row.Status = 'Active';
|
|
243
|
+
if (!(await row.Save())) {
|
|
244
|
+
throw new Error(`failed binding the on-change filter: ${row.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=RecordProcessOnChangeReconciler.js.map
|