@memberjunction/core-entities-server 6.2.0-edge.6 → 6.2.0-edge.8
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/README.md +155 -100
- package/dist/custom/AnchoredConversationReadSecurityHook.d.ts +22 -0
- package/dist/custom/AnchoredConversationReadSecurityHook.d.ts.map +1 -0
- package/dist/custom/AnchoredConversationReadSecurityHook.js +293 -0
- package/dist/custom/AnchoredConversationReadSecurityHook.js.map +1 -0
- package/dist/custom/MJAIAgentExampleEntityServer.server.d.ts +2 -0
- package/dist/custom/MJAIAgentExampleEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJAIAgentExampleEntityServer.server.js +8 -5
- package/dist/custom/MJAIAgentExampleEntityServer.server.js.map +1 -1
- package/dist/custom/MJAIAgentNoteEntityServer.server.d.ts +2 -0
- package/dist/custom/MJAIAgentNoteEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJAIAgentNoteEntityServer.server.js +8 -5
- package/dist/custom/MJAIAgentNoteEntityServer.server.js.map +1 -1
- package/dist/custom/MJAIAgentRelationshipEntityServer.server.d.ts +17 -0
- package/dist/custom/MJAIAgentRelationshipEntityServer.server.d.ts.map +1 -0
- package/dist/custom/MJAIAgentRelationshipEntityServer.server.js +71 -0
- package/dist/custom/MJAIAgentRelationshipEntityServer.server.js.map +1 -0
- package/dist/custom/MJAIAgentSessionEntityServer.server.d.ts +8 -22
- package/dist/custom/MJAIAgentSessionEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJAIAgentSessionEntityServer.server.js +24 -1
- package/dist/custom/MJAIAgentSessionEntityServer.server.js.map +1 -1
- package/dist/custom/MJAIAgentUserPolicyEntityServer.server.d.ts +23 -0
- package/dist/custom/MJAIAgentUserPolicyEntityServer.server.d.ts.map +1 -0
- package/dist/custom/MJAIAgentUserPolicyEntityServer.server.js +53 -0
- package/dist/custom/MJAIAgentUserPolicyEntityServer.server.js.map +1 -0
- package/dist/custom/MJAIPromptEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJAIPromptEntityServer.server.js +2 -1
- package/dist/custom/MJAIPromptEntityServer.server.js.map +1 -1
- package/dist/custom/MJBrandKitEntityServer.server.d.ts +14 -0
- package/dist/custom/MJBrandKitEntityServer.server.d.ts.map +1 -0
- package/dist/custom/MJBrandKitEntityServer.server.js +75 -0
- package/dist/custom/MJBrandKitEntityServer.server.js.map +1 -0
- package/dist/custom/MJCompanyIntegrationEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJCompanyIntegrationEntityServer.server.js +1 -0
- package/dist/custom/MJCompanyIntegrationEntityServer.server.js.map +1 -1
- package/dist/custom/MJComponentEntityServer.server.d.ts +2 -0
- package/dist/custom/MJComponentEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJComponentEntityServer.server.js +5 -1
- package/dist/custom/MJComponentEntityServer.server.js.map +1 -1
- package/dist/custom/MJConversationDetailEntityServer.server.d.ts +20 -30
- package/dist/custom/MJConversationDetailEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJConversationDetailEntityServer.server.js +89 -35
- package/dist/custom/MJConversationDetailEntityServer.server.js.map +1 -1
- package/dist/custom/MJConversationEntityServer.server.d.ts +19 -4
- package/dist/custom/MJConversationEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJConversationEntityServer.server.js +169 -11
- package/dist/custom/MJConversationEntityServer.server.js.map +1 -1
- package/dist/custom/MJEntityDocumentEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJEntityDocumentEntityServer.server.js +1 -0
- package/dist/custom/MJEntityDocumentEntityServer.server.js.map +1 -1
- package/dist/custom/MJListDetailEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJListDetailEntityServer.server.js +1 -0
- package/dist/custom/MJListDetailEntityServer.server.js.map +1 -1
- package/dist/custom/MJProjectEntityServer.server.d.ts +21 -0
- package/dist/custom/MJProjectEntityServer.server.d.ts.map +1 -0
- package/dist/custom/MJProjectEntityServer.server.js +106 -0
- package/dist/custom/MJProjectEntityServer.server.js.map +1 -0
- package/dist/custom/MJQueryEntityServer.server.d.ts +177 -47
- package/dist/custom/MJQueryEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJQueryEntityServer.server.js +479 -164
- package/dist/custom/MJQueryEntityServer.server.js.map +1 -1
- package/dist/custom/MJQuerySQLEntityServer.server.d.ts +15 -18
- package/dist/custom/MJQuerySQLEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJQuerySQLEntityServer.server.js +34 -42
- package/dist/custom/MJQuerySQLEntityServer.server.js.map +1 -1
- package/dist/custom/MJTagEntityServer.server.d.ts +2 -0
- package/dist/custom/MJTagEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJTagEntityServer.server.js +13 -7
- package/dist/custom/MJTagEntityServer.server.js.map +1 -1
- package/dist/custom/MJUserRoutineEntityServer.server.d.ts.map +1 -1
- package/dist/custom/MJUserRoutineEntityServer.server.js +8 -1
- package/dist/custom/MJUserRoutineEntityServer.server.js.map +1 -1
- package/dist/custom/RestrictedFieldCommentClassifier.d.ts +73 -0
- package/dist/custom/RestrictedFieldCommentClassifier.d.ts.map +1 -0
- package/dist/custom/RestrictedFieldCommentClassifier.js +240 -0
- package/dist/custom/RestrictedFieldCommentClassifier.js.map +1 -0
- package/dist/custom/query-extraction/childRowWriter.d.ts +77 -0
- package/dist/custom/query-extraction/childRowWriter.d.ts.map +1 -0
- package/dist/custom/query-extraction/childRowWriter.js +277 -0
- package/dist/custom/query-extraction/childRowWriter.js.map +1 -0
- package/dist/custom/query-extraction/compositionTargets.d.ts +40 -0
- package/dist/custom/query-extraction/compositionTargets.d.ts.map +1 -0
- package/dist/custom/query-extraction/compositionTargets.js +99 -0
- package/dist/custom/query-extraction/compositionTargets.js.map +1 -0
- package/dist/custom/query-extraction/declared.d.ts +79 -0
- package/dist/custom/query-extraction/declared.d.ts.map +1 -0
- package/dist/custom/query-extraction/declared.js +91 -0
- package/dist/custom/query-extraction/declared.js.map +1 -0
- package/dist/custom/query-extraction/describeFacts.d.ts +40 -0
- package/dist/custom/query-extraction/describeFacts.d.ts.map +1 -0
- package/dist/custom/query-extraction/describeFacts.js +225 -0
- package/dist/custom/query-extraction/describeFacts.js.map +1 -0
- package/dist/custom/query-extraction/descriptionPass.d.ts +23 -0
- package/dist/custom/query-extraction/descriptionPass.d.ts.map +1 -0
- package/dist/custom/query-extraction/descriptionPass.js +95 -0
- package/dist/custom/query-extraction/descriptionPass.js.map +1 -0
- package/dist/custom/query-extraction/extractQuery.d.ts +25 -0
- package/dist/custom/query-extraction/extractQuery.d.ts.map +1 -0
- package/dist/custom/query-extraction/extractQuery.js +146 -0
- package/dist/custom/query-extraction/extractQuery.js.map +1 -0
- package/dist/custom/query-extraction/extractionTypes.d.ts +133 -0
- package/dist/custom/query-extraction/extractionTypes.d.ts.map +1 -0
- package/dist/custom/query-extraction/extractionTypes.js +2 -0
- package/dist/custom/query-extraction/extractionTypes.js.map +1 -0
- package/dist/custom/query-extraction/index.d.ts +16 -0
- package/dist/custom/query-extraction/index.d.ts.map +1 -1
- package/dist/custom/query-extraction/index.js +11 -1
- package/dist/custom/query-extraction/index.js.map +1 -1
- package/dist/custom/query-extraction/pipeline.d.ts +6 -2
- package/dist/custom/query-extraction/pipeline.d.ts.map +1 -1
- package/dist/custom/query-extraction/pipeline.js +21 -14
- package/dist/custom/query-extraction/pipeline.js.map +1 -1
- package/dist/custom/query-extraction/resolve.d.ts +7 -2
- package/dist/custom/query-extraction/resolve.d.ts.map +1 -1
- package/dist/custom/query-extraction/resolve.js +17 -14
- package/dist/custom/query-extraction/resolve.js.map +1 -1
- package/dist/custom/query-extraction/sourceBinding.d.ts +57 -0
- package/dist/custom/query-extraction/sourceBinding.d.ts.map +1 -0
- package/dist/custom/query-extraction/sourceBinding.js +104 -0
- package/dist/custom/query-extraction/sourceBinding.js.map +1 -0
- package/dist/custom/query-extraction/sync.d.ts +27 -3
- package/dist/custom/query-extraction/sync.d.ts.map +1 -1
- package/dist/custom/query-extraction/sync.js +69 -44
- package/dist/custom/query-extraction/sync.js.map +1 -1
- package/dist/custom/query-extraction/templateFacts.d.ts +62 -0
- package/dist/custom/query-extraction/templateFacts.d.ts.map +1 -0
- package/dist/custom/query-extraction/templateFacts.js +229 -0
- package/dist/custom/query-extraction/templateFacts.js.map +1 -0
- package/dist/custom/query-extraction/types.d.ts +4 -0
- package/dist/custom/query-extraction/types.d.ts.map +1 -1
- package/dist/custom/query-refresh/QueryExtractionService.d.ts +54 -0
- package/dist/custom/query-refresh/QueryExtractionService.d.ts.map +1 -0
- package/dist/custom/query-refresh/QueryExtractionService.js +207 -0
- package/dist/custom/query-refresh/QueryExtractionService.js.map +1 -0
- package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.d.ts +28 -0
- package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.d.ts.map +1 -0
- package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.js +106 -0
- package/dist/custom/query-refresh/QueryRefreshExtractionServerOperation.js.map +1 -0
- package/dist/custom/query-refresh/index.d.ts +14 -0
- package/dist/custom/query-refresh/index.d.ts.map +1 -0
- package/dist/custom/query-refresh/index.js +10 -0
- package/dist/custom/query-refresh/index.js.map +1 -0
- package/dist/custom/query-refresh/queryRebind.d.ts +33 -0
- package/dist/custom/query-refresh/queryRebind.d.ts.map +1 -0
- package/dist/custom/query-refresh/queryRebind.js +85 -0
- package/dist/custom/query-refresh/queryRebind.js.map +1 -0
- package/dist/custom/query-refresh/refreshAuthorization.d.ts +29 -0
- package/dist/custom/query-refresh/refreshAuthorization.d.ts.map +1 -0
- package/dist/custom/query-refresh/refreshAuthorization.js +66 -0
- package/dist/custom/query-refresh/refreshAuthorization.js.map +1 -0
- package/dist/custom/query-refresh/refreshFormat.d.ts +16 -0
- package/dist/custom/query-refresh/refreshFormat.d.ts.map +1 -0
- package/dist/custom/query-refresh/refreshFormat.js +67 -0
- package/dist/custom/query-refresh/refreshFormat.js.map +1 -0
- package/dist/custom/query-refresh/refreshOrder.d.ts +25 -0
- package/dist/custom/query-refresh/refreshOrder.d.ts.map +1 -0
- package/dist/custom/query-refresh/refreshOrder.js +95 -0
- package/dist/custom/query-refresh/refreshOrder.js.map +1 -0
- package/dist/custom/query-refresh/refreshSelection.d.ts +15 -0
- package/dist/custom/query-refresh/refreshSelection.d.ts.map +1 -0
- package/dist/custom/query-refresh/refreshSelection.js +99 -0
- package/dist/custom/query-refresh/refreshSelection.js.map +1 -0
- package/dist/custom/query-refresh/refreshTypes.d.ts +81 -0
- package/dist/custom/query-refresh/refreshTypes.d.ts.map +1 -0
- package/dist/custom/query-refresh/refreshTypes.js +5 -0
- package/dist/custom/query-refresh/refreshTypes.js.map +1 -0
- package/dist/custom/util.d.ts +8 -0
- package/dist/custom/util.d.ts.map +1 -1
- package/dist/custom/util.js +18 -1
- package/dist/custom/util.js.map +1 -1
- package/dist/engines/QueryEngineServer.d.ts +8 -5
- package/dist/engines/QueryEngineServer.d.ts.map +1 -1
- package/dist/engines/QueryEngineServer.js +16 -23
- package/dist/engines/QueryEngineServer.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/package.json +30 -30
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { QueryRefreshContext, QueryRefreshFilter, QueryRefreshOptions, QueryRefreshReport, QueryRefreshRunReport } from "./refreshTypes.js";
|
|
2
|
+
/**
|
|
3
|
+
* Re-establishes saved queries' facts from their SQL and the database server, on demand: the
|
|
4
|
+
* same extraction a save of a changed query runs, without changing the SQL. Every entry point
|
|
5
|
+
* (the `Query.RefreshExtraction` remote operation, `mj query refresh`, CodeGen's re-bind pass)
|
|
6
|
+
* goes through this service, so the same authorization applies to all of them:
|
|
7
|
+
*
|
|
8
|
+
* - the caller needs Update on `MJ: Queries` and Create, Update and Delete on its derived child
|
|
9
|
+
* entities, for a dry run too;
|
|
10
|
+
* - the caller must be able to read every entity the query reads, with no field denied on any of
|
|
11
|
+
* them, because the report and the written rows expose their columns;
|
|
12
|
+
* - a refusal of a single query reads exactly like "not found"; a bulk run reports such a query
|
|
13
|
+
* as `NotPermitted`, with no reason.
|
|
14
|
+
*
|
|
15
|
+
* Each query is refreshed in its own transaction on the caller's provider, and the child rows are
|
|
16
|
+
* written as the caller, so each write's own permission check also applies. A bulk run refreshes
|
|
17
|
+
* the queries a composition depends on before the queries that compose them.
|
|
18
|
+
*/
|
|
19
|
+
export declare class QueryExtractionService {
|
|
20
|
+
private readonly context;
|
|
21
|
+
constructor(context: QueryRefreshContext);
|
|
22
|
+
/**
|
|
23
|
+
* Refreshes one saved query.
|
|
24
|
+
*
|
|
25
|
+
* @param queryID - The query's ID; echoed, and nothing else, when the query is unavailable.
|
|
26
|
+
*/
|
|
27
|
+
RefreshQuery(queryID: string, options?: QueryRefreshOptions): Promise<QueryRefreshReport>;
|
|
28
|
+
/**
|
|
29
|
+
* Refreshes every query `filter` selects that the caller can read, dependencies first. An ID
|
|
30
|
+
* or name that selects nothing is reported as `Unavailable`; a selected query the caller may
|
|
31
|
+
* not refresh is reported as `NotPermitted`.
|
|
32
|
+
*/
|
|
33
|
+
RefreshQueries(filter: QueryRefreshFilter, options?: QueryRefreshOptions): Promise<QueryRefreshRunReport>;
|
|
34
|
+
/**
|
|
35
|
+
* The queries `filter` selects; `null` when a caller who may not refresh queries cannot read
|
|
36
|
+
* them either, so the selection cannot be made (a caller who may refresh and still cannot read
|
|
37
|
+
* them meets the read's error).
|
|
38
|
+
*/
|
|
39
|
+
private select;
|
|
40
|
+
private get userCanRefresh();
|
|
41
|
+
private refreshSelected;
|
|
42
|
+
/** The query as the caller can load it; `null` when it does not exist or the caller cannot read it. */
|
|
43
|
+
private loadQuery;
|
|
44
|
+
private refreshLoaded;
|
|
45
|
+
/** Writes the refresh in its own transaction on the caller's provider; any failure rolls it back. */
|
|
46
|
+
private applyInTransaction;
|
|
47
|
+
/**
|
|
48
|
+
* The non-disclosure guard: whether the caller can see every entity the query reads, by its
|
|
49
|
+
* stored links and field sources and by the facts the refresh found.
|
|
50
|
+
*/
|
|
51
|
+
private userCanSeeSources;
|
|
52
|
+
private entityName;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=QueryExtractionService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryExtractionService.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/QueryExtractionService.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACR,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACxB,MAAM,gBAAgB,CAAC;AAKxB;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAsB;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,mBAAmB;IAEzD;;;;OAIG;IACU,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAO1G;;;;OAIG;IACU,cAAc,CAAC,MAAM,EAAE,kBAAkB,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAe1H;;;;OAIG;YACW,MAAM;IASpB,OAAO,KAAK,cAAc,GAEzB;YAEa,eAAe;IAO7B,uGAAuG;YACzF,SAAS;YAUT,aAAa;IAuB3B,qGAAqG;YACvF,kBAAkB;IAMhC;;;OAGG;YACW,iBAAiB;IAY/B,OAAO,CAAC,UAAU;CAIrB"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { DatabaseProviderBase, LogError, RunInEntityTransaction } from "@memberjunction/core";
|
|
2
|
+
import { EscapeSQLString, NormalizeUUID } from "@memberjunction/global";
|
|
3
|
+
import { EntityIDsOfExtraction, QueryRefreshUnavailableMessage, UserCanRefreshQueries, UserCanSeeQuerySources, } from "./refreshAuthorization.js";
|
|
4
|
+
import { OrderForRefresh } from "./refreshOrder.js";
|
|
5
|
+
import { SelectQueriesForRefresh } from "./refreshSelection.js";
|
|
6
|
+
/**
|
|
7
|
+
* Re-establishes saved queries' facts from their SQL and the database server, on demand: the
|
|
8
|
+
* same extraction a save of a changed query runs, without changing the SQL. Every entry point
|
|
9
|
+
* (the `Query.RefreshExtraction` remote operation, `mj query refresh`, CodeGen's re-bind pass)
|
|
10
|
+
* goes through this service, so the same authorization applies to all of them:
|
|
11
|
+
*
|
|
12
|
+
* - the caller needs Update on `MJ: Queries` and Create, Update and Delete on its derived child
|
|
13
|
+
* entities, for a dry run too;
|
|
14
|
+
* - the caller must be able to read every entity the query reads, with no field denied on any of
|
|
15
|
+
* them, because the report and the written rows expose their columns;
|
|
16
|
+
* - a refusal of a single query reads exactly like "not found"; a bulk run reports such a query
|
|
17
|
+
* as `NotPermitted`, with no reason.
|
|
18
|
+
*
|
|
19
|
+
* Each query is refreshed in its own transaction on the caller's provider, and the child rows are
|
|
20
|
+
* written as the caller, so each write's own permission check also applies. A bulk run refreshes
|
|
21
|
+
* the queries a composition depends on before the queries that compose them.
|
|
22
|
+
*/
|
|
23
|
+
export class QueryExtractionService {
|
|
24
|
+
constructor(context) {
|
|
25
|
+
this.context = context;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Refreshes one saved query.
|
|
29
|
+
*
|
|
30
|
+
* @param queryID - The query's ID; echoed, and nothing else, when the query is unavailable.
|
|
31
|
+
*/
|
|
32
|
+
async RefreshQuery(queryID, options = {}) {
|
|
33
|
+
if (!this.userCanRefresh)
|
|
34
|
+
return unavailableReport(queryID, options);
|
|
35
|
+
const query = await this.loadQuery(queryID);
|
|
36
|
+
if (!query)
|
|
37
|
+
return unavailableReport(queryID, options);
|
|
38
|
+
return this.refreshLoaded(query, options, 'Unavailable', queryID);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Refreshes every query `filter` selects that the caller can read, dependencies first. An ID
|
|
42
|
+
* or name that selects nothing is reported as `Unavailable`; a selected query the caller may
|
|
43
|
+
* not refresh is reported as `NotPermitted`.
|
|
44
|
+
*/
|
|
45
|
+
async RefreshQueries(filter, options = {}) {
|
|
46
|
+
const dryRun = options.DryRun === true;
|
|
47
|
+
const selection = await this.select(filter);
|
|
48
|
+
if (!selection)
|
|
49
|
+
return unselectableRun(filter, options);
|
|
50
|
+
const order = OrderForRefresh(selection.Queries, selection.Edges);
|
|
51
|
+
const reports = selection.Unmatched.map(label => unavailableReport(label, options));
|
|
52
|
+
const total = order.Order.length;
|
|
53
|
+
for (const [index, query] of order.Order.entries()) {
|
|
54
|
+
const report = await this.refreshSelected(query, options);
|
|
55
|
+
reports.push(report);
|
|
56
|
+
options.OnProgress?.({ Processed: index + 1, Total: total, Report: report });
|
|
57
|
+
}
|
|
58
|
+
return { DryRun: dryRun, Reports: reports, Cycles: order.Cycles };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The queries `filter` selects; `null` when a caller who may not refresh queries cannot read
|
|
62
|
+
* them either, so the selection cannot be made (a caller who may refresh and still cannot read
|
|
63
|
+
* them meets the read's error).
|
|
64
|
+
*/
|
|
65
|
+
async select(filter) {
|
|
66
|
+
try {
|
|
67
|
+
return await SelectQueriesForRefresh(this.context, filter);
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
if (this.userCanRefresh)
|
|
71
|
+
throw e;
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
get userCanRefresh() {
|
|
76
|
+
return UserCanRefreshQueries(this.context.User, this.context.Provider.Entities);
|
|
77
|
+
}
|
|
78
|
+
async refreshSelected(selected, options) {
|
|
79
|
+
if (!this.userCanRefresh)
|
|
80
|
+
return notPermittedReport(selected.ID, selected.Name, options);
|
|
81
|
+
const query = await this.loadQuery(selected.ID);
|
|
82
|
+
if (!query)
|
|
83
|
+
return notPermittedReport(selected.ID, selected.Name, options);
|
|
84
|
+
return this.refreshLoaded(query, options, 'NotPermitted', selected.ID);
|
|
85
|
+
}
|
|
86
|
+
/** The query as the caller can load it; `null` when it does not exist or the caller cannot read it. */
|
|
87
|
+
async loadQuery(queryID) {
|
|
88
|
+
try {
|
|
89
|
+
const query = await this.context.Provider.GetEntityObject('MJ: Queries', this.context.User);
|
|
90
|
+
return await query.Load(queryID) ? query : null;
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
LogError(`[QueryExtractionService] query ${queryID} could not be loaded: ${e instanceof Error ? e.message : String(e)}`);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async refreshLoaded(query, options, refusal, label) {
|
|
98
|
+
const dryRun = options.DryRun === true;
|
|
99
|
+
try {
|
|
100
|
+
if (!query.SQL || query.SQL.trim().length === 0) {
|
|
101
|
+
return { ...emptyReport(query.ID, query.Name, 'Unchanged', dryRun), Diagnostics: ['The query has no SQL, so there is nothing to refresh.'] };
|
|
102
|
+
}
|
|
103
|
+
const extraction = await query.ComputeRefreshExtractionAsync();
|
|
104
|
+
if (!await this.userCanSeeSources(query.ID, extraction)) {
|
|
105
|
+
return refusal === 'Unavailable' ? unavailableReport(label, options) : notPermittedReport(query.ID, query.Name, options);
|
|
106
|
+
}
|
|
107
|
+
const rowChanges = queryRowChanges(query, extraction);
|
|
108
|
+
const preview = await query.PreviewRefreshAsync(extraction, id => this.entityName(id));
|
|
109
|
+
const summary = dryRun || !needsWrite(preview, rowChanges, options)
|
|
110
|
+
? preview
|
|
111
|
+
: await this.applyInTransaction(query, extraction, options.WithAI === true);
|
|
112
|
+
return reportOf(query, extraction, summary, rowChanges, dryRun);
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
const reason = e instanceof Error ? e.message : String(e);
|
|
116
|
+
LogError(`[QueryExtractionService] refresh of query "${query.Name}" failed: ${reason}`);
|
|
117
|
+
return { ...emptyReport(query.ID, query.Name, 'Failed', dryRun), Diagnostics: [`The refresh was not completed and nothing was written: ${reason}`] };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Writes the refresh in its own transaction on the caller's provider; any failure rolls it back. */
|
|
121
|
+
async applyInTransaction(query, extraction, withAI) {
|
|
122
|
+
const provider = this.context.Provider;
|
|
123
|
+
const work = () => query.ApplyRefreshAsync(extraction, withAI);
|
|
124
|
+
return provider instanceof DatabaseProviderBase ? RunInEntityTransaction(provider, work) : work();
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* The non-disclosure guard: whether the caller can see every entity the query reads, by its
|
|
128
|
+
* stored links and field sources and by the facts the refresh found.
|
|
129
|
+
*/
|
|
130
|
+
async userCanSeeSources(queryID, extraction) {
|
|
131
|
+
const filter = `QueryID='${EscapeSQLString(queryID)}'`;
|
|
132
|
+
const [links, fields] = await this.context.Provider.RunViews([
|
|
133
|
+
{ EntityName: 'MJ: Query Entities', ExtraFilter: filter, Fields: ['EntityID'], ResultType: 'simple', BypassCache: true, IgnoreMaxRows: true },
|
|
134
|
+
{ EntityName: 'MJ: Query Fields', ExtraFilter: filter, Fields: ['SourceEntityID'], ResultType: 'simple', BypassCache: true, IgnoreMaxRows: true },
|
|
135
|
+
], this.context.User);
|
|
136
|
+
if (!links?.Success || !fields?.Success)
|
|
137
|
+
return false;
|
|
138
|
+
const stored = [...links.Results.map(r => r.EntityID), ...fields.Results.map(r => r.SourceEntityID)]
|
|
139
|
+
.filter((id) => typeof id === 'string' && id.length > 0);
|
|
140
|
+
return UserCanSeeQuerySources(this.context.User, [...stored, ...EntityIDsOfExtraction(extraction)], this.context.Provider.Entities);
|
|
141
|
+
}
|
|
142
|
+
entityName(entityID) {
|
|
143
|
+
const wanted = NormalizeUUID(entityID);
|
|
144
|
+
return this.context.Provider.Entities.find(e => NormalizeUUID(e.ID) === wanted)?.Name ?? entityID;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Whether a refresh has anything to write: a child row or a query-row column changes, or the
|
|
149
|
+
* description pass was asked for and some row has no description. An unchanged query is not saved
|
|
150
|
+
* at all, so its timestamps and embedding stay as they are.
|
|
151
|
+
*/
|
|
152
|
+
function needsWrite(preview, rowChanges, options) {
|
|
153
|
+
if (preview.Changes.length > 0 || rowChanges.length > 0)
|
|
154
|
+
return true;
|
|
155
|
+
return options.WithAI === true && preview.FieldsWithoutDescription.length + preview.ParametersWithoutDescription.length > 0;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The run for a caller who may neither refresh nor read queries:
|
|
159
|
+
* each ID or name it gave is reported unavailable, and nothing else is selected or disclosed.
|
|
160
|
+
*/
|
|
161
|
+
function unselectableRun(filter, options) {
|
|
162
|
+
const labels = [...(filter.QueryIDs ?? []), ...(filter.QueryNames ?? [])];
|
|
163
|
+
return { DryRun: options.DryRun === true, Reports: labels.map(label => unavailableReport(label, options)), Cycles: [] };
|
|
164
|
+
}
|
|
165
|
+
/** The columns of the query row the refresh changes (`UsesTemplate` and the Extraction columns). */
|
|
166
|
+
function queryRowChanges(query, extraction) {
|
|
167
|
+
const message = extraction.Messages.length > 0 ? extraction.Messages.join('\n') : null;
|
|
168
|
+
const changes = [];
|
|
169
|
+
if (query.UsesTemplate !== extraction.UsesTemplate)
|
|
170
|
+
changes.push('UsesTemplate');
|
|
171
|
+
if (query.ExtractedSQLHash !== extraction.Hash)
|
|
172
|
+
changes.push('ExtractedSQLHash');
|
|
173
|
+
if (query.ExtractionStatus !== extraction.Status)
|
|
174
|
+
changes.push('ExtractionStatus');
|
|
175
|
+
if ((query.ExtractionMessage ?? null) !== message)
|
|
176
|
+
changes.push('ExtractionMessage');
|
|
177
|
+
return changes;
|
|
178
|
+
}
|
|
179
|
+
function reportOf(query, extraction, summary, rowChanges, dryRun) {
|
|
180
|
+
const changes = summary?.Changes ?? [];
|
|
181
|
+
const pick = (action) => changes.filter(c => c.Action === action);
|
|
182
|
+
return {
|
|
183
|
+
QueryID: query.ID,
|
|
184
|
+
QueryName: query.Name,
|
|
185
|
+
Outcome: changes.length > 0 || rowChanges.length > 0 ? 'Refreshed' : 'Unchanged',
|
|
186
|
+
DryRun: dryRun,
|
|
187
|
+
ExtractionStatus: extraction.Status,
|
|
188
|
+
QueryColumns: [...rowChanges],
|
|
189
|
+
Added: pick('Added'),
|
|
190
|
+
Updated: pick('Updated'),
|
|
191
|
+
Removed: pick('Removed'),
|
|
192
|
+
Flagged: summary?.FlaggedParameters ?? [],
|
|
193
|
+
Diagnostics: [...extraction.Messages],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function emptyReport(queryID, queryName, outcome, dryRun) {
|
|
197
|
+
return { QueryID: queryID, QueryName: queryName, Outcome: outcome, DryRun: dryRun, ExtractionStatus: null, QueryColumns: [], Added: [], Updated: [], Removed: [], Flagged: [], Diagnostics: [] };
|
|
198
|
+
}
|
|
199
|
+
/** A query that does not exist or that the caller may not refresh: the two read alike, echoing only `label`. */
|
|
200
|
+
function unavailableReport(label, options) {
|
|
201
|
+
return { ...emptyReport(label, '', 'Unavailable', options.DryRun === true), Diagnostics: [QueryRefreshUnavailableMessage(label)] };
|
|
202
|
+
}
|
|
203
|
+
/** A selected query a bulk run skips because the caller may not refresh it; no reason is given. */
|
|
204
|
+
function notPermittedReport(queryID, queryName, options) {
|
|
205
|
+
return { ...emptyReport(queryID, queryName, 'NotPermitted', options.DryRun === true), Diagnostics: ['Skipped: not permitted.'] };
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=QueryExtractionService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryExtractionService.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/QueryExtractionService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { IMetadataProvider, RemoteOpServerContext, UserInfo } from "@memberjunction/core";
|
|
2
|
+
import { QueryRefreshExtractionOperation } from "@memberjunction/core-entities";
|
|
3
|
+
import type { QueryRefreshExtractionInput, QueryRefreshExtractionOutput } from "@memberjunction/core-entities";
|
|
4
|
+
import type { QueryRefreshFilter, QueryRefreshRunReport } from "./refreshTypes.js";
|
|
5
|
+
/**
|
|
6
|
+
* Server implementation of the `Query.RefreshExtraction` remote operation: refreshes one saved
|
|
7
|
+
* query, or a selection, through {@link QueryExtractionService}, reporting each query as a
|
|
8
|
+
* progress event as it finishes.
|
|
9
|
+
*
|
|
10
|
+
* `Authorize` refuses a caller without Update on `MJ: Queries` and Create, Update and Delete on
|
|
11
|
+
* its child entities; the service applies the same check and the per-query non-disclosure guard
|
|
12
|
+
* for every entry point. An API-key caller also needs the operation's `query:refresh` scope.
|
|
13
|
+
* A request for exactly one query ID, and nothing else, reports a query that does not exist and
|
|
14
|
+
* one the caller may not refresh with the same message.
|
|
15
|
+
*/
|
|
16
|
+
export declare class QueryRefreshExtractionServerOperation extends QueryRefreshExtractionOperation {
|
|
17
|
+
protected Authorize(_input: QueryRefreshExtractionInput, user: UserInfo): Promise<boolean>;
|
|
18
|
+
protected InternalExecute(input: QueryRefreshExtractionInput, provider: IMetadataProvider, user: UserInfo, context: RemoteOpServerContext): Promise<QueryRefreshExtractionOutput>;
|
|
19
|
+
}
|
|
20
|
+
/** The service filter for an operation input; only the selectors the input gives. */
|
|
21
|
+
export declare function RefreshFilterOf(input: QueryRefreshExtractionInput): QueryRefreshFilter;
|
|
22
|
+
/** Whether a filter selects anything at all. */
|
|
23
|
+
export declare function HasRefreshSelector(filter: QueryRefreshFilter): boolean;
|
|
24
|
+
/** A service run as the operation's output. */
|
|
25
|
+
export declare function RefreshOutputOf(run: QueryRefreshRunReport): QueryRefreshExtractionOutput;
|
|
26
|
+
/** Keeps the operation in the bundle: import and call it where the class must be registered. */
|
|
27
|
+
export declare function LoadQueryRefreshExtractionServerOperation(): void;
|
|
28
|
+
//# sourceMappingURL=QueryRefreshExtractionServerOperation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryRefreshExtractionServerOperation.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/QueryRefreshExtractionServerOperation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC/F,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,KAAK,EACR,2BAA2B,EAC3B,4BAA4B,EAG/B,MAAM,+BAA+B,CAAC;AAOvC,OAAO,KAAK,EAAE,kBAAkB,EAA2C,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEzH;;;;;;;;;;GAUG;AACH,qBACa,qCAAsC,SAAQ,+BAA+B;cAC7D,SAAS,CAAC,MAAM,EAAE,2BAA2B,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;cAIzF,eAAe,CAAC,KAAK,EAAE,2BAA2B,EAAE,QAAQ,EAAE,iBAAiB,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,4BAA4B,CAAC;CAoB1L;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,KAAK,EAAE,2BAA2B,GAAG,kBAAkB,CAQtF;AAED,gDAAgD;AAChD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAGtE;AAED,+CAA+C;AAC/C,wBAAgB,eAAe,CAAC,GAAG,EAAE,qBAAqB,GAAG,4BAA4B,CAOxF;AAqBD,gGAAgG;AAChG,wBAAgB,yCAAyC,IAAI,IAAI,CAEhE"}
|
|
@@ -0,0 +1,106 @@
|
|
|
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 { BaseRemotableOperation, Metadata } from "@memberjunction/core";
|
|
8
|
+
import { QueryRefreshExtractionOperation } from "@memberjunction/core-entities";
|
|
9
|
+
import { RegisterClass } from "@memberjunction/global";
|
|
10
|
+
import { QueryExtractionService } from "./QueryExtractionService.js";
|
|
11
|
+
import { UserCanRefreshQueries } from "./refreshAuthorization.js";
|
|
12
|
+
import { FormatQueryRefreshSummary } from "./refreshFormat.js";
|
|
13
|
+
import { IsQueryRefreshProvider } from "./refreshTypes.js";
|
|
14
|
+
/**
|
|
15
|
+
* Server implementation of the `Query.RefreshExtraction` remote operation: refreshes one saved
|
|
16
|
+
* query, or a selection, through {@link QueryExtractionService}, reporting each query as a
|
|
17
|
+
* progress event as it finishes.
|
|
18
|
+
*
|
|
19
|
+
* `Authorize` refuses a caller without Update on `MJ: Queries` and Create, Update and Delete on
|
|
20
|
+
* its child entities; the service applies the same check and the per-query non-disclosure guard
|
|
21
|
+
* for every entry point. An API-key caller also needs the operation's `query:refresh` scope.
|
|
22
|
+
* A request for exactly one query ID, and nothing else, reports a query that does not exist and
|
|
23
|
+
* one the caller may not refresh with the same message.
|
|
24
|
+
*/
|
|
25
|
+
let QueryRefreshExtractionServerOperation = class QueryRefreshExtractionServerOperation extends QueryRefreshExtractionOperation {
|
|
26
|
+
async Authorize(_input, user) {
|
|
27
|
+
return UserCanRefreshQueries(user, Metadata.Provider.Entities); // global-provider-ok: Authorize receives no provider; entity permissions are process-global metadata
|
|
28
|
+
}
|
|
29
|
+
async InternalExecute(input, provider, user, context) {
|
|
30
|
+
if (!IsQueryRefreshProvider(provider))
|
|
31
|
+
throw new Error('Query.RefreshExtraction needs a database provider');
|
|
32
|
+
const filter = RefreshFilterOf(input);
|
|
33
|
+
if (!HasRefreshSelector(filter))
|
|
34
|
+
throw new Error('Give at least one selector: queryIDs, queryNames, categoryPath, entityNames or all.');
|
|
35
|
+
const service = new QueryExtractionService({ Provider: provider, User: user });
|
|
36
|
+
const options = {
|
|
37
|
+
DryRun: input.dryRun === true,
|
|
38
|
+
WithAI: input.withAI === true,
|
|
39
|
+
OnProgress: p => context.emitProgress({
|
|
40
|
+
OperationKey: this.OperationKey, Processed: p.Processed, Total: p.Total, Status: 'Running',
|
|
41
|
+
Message: `${p.Report.Outcome}: ${p.Report.QueryName || p.Report.QueryID}`,
|
|
42
|
+
Payload: { queryID: p.Report.QueryID, outcome: p.Report.Outcome },
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
const single = filter.QueryIDs?.length === 1 && Object.keys(filter).length === 1 ? filter.QueryIDs[0] : null;
|
|
46
|
+
const run = single
|
|
47
|
+
? { DryRun: options.DryRun === true, Reports: [await service.RefreshQuery(single, options)], Cycles: [] }
|
|
48
|
+
: await service.RefreshQueries(filter, options);
|
|
49
|
+
return RefreshOutputOf(run);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
QueryRefreshExtractionServerOperation = __decorate([
|
|
53
|
+
RegisterClass(BaseRemotableOperation, 'Query.RefreshExtraction')
|
|
54
|
+
], QueryRefreshExtractionServerOperation);
|
|
55
|
+
export { QueryRefreshExtractionServerOperation };
|
|
56
|
+
/** The service filter for an operation input; only the selectors the input gives. */
|
|
57
|
+
export function RefreshFilterOf(input) {
|
|
58
|
+
const filter = {};
|
|
59
|
+
if (input.queryIDs?.length)
|
|
60
|
+
filter.QueryIDs = input.queryIDs;
|
|
61
|
+
if (input.queryNames?.length)
|
|
62
|
+
filter.QueryNames = input.queryNames;
|
|
63
|
+
if (input.categoryPath?.trim())
|
|
64
|
+
filter.CategoryPath = input.categoryPath;
|
|
65
|
+
if (input.entityNames?.length)
|
|
66
|
+
filter.EntityNames = input.entityNames;
|
|
67
|
+
if (input.all === true)
|
|
68
|
+
filter.All = true;
|
|
69
|
+
return filter;
|
|
70
|
+
}
|
|
71
|
+
/** Whether a filter selects anything at all. */
|
|
72
|
+
export function HasRefreshSelector(filter) {
|
|
73
|
+
return filter.All === true || !!filter.QueryIDs?.length || !!filter.QueryNames?.length || !!filter.CategoryPath
|
|
74
|
+
|| !!filter.EntityNames?.length || !!filter.EntityIDs?.length;
|
|
75
|
+
}
|
|
76
|
+
/** A service run as the operation's output. */
|
|
77
|
+
export function RefreshOutputOf(run) {
|
|
78
|
+
return {
|
|
79
|
+
dryRun: run.DryRun,
|
|
80
|
+
reports: run.Reports.map(reportOutputOf),
|
|
81
|
+
cycles: run.Cycles.map(c => [...c]),
|
|
82
|
+
summary: FormatQueryRefreshSummary(run),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function reportOutputOf(report) {
|
|
86
|
+
return {
|
|
87
|
+
queryID: report.QueryID,
|
|
88
|
+
queryName: report.QueryName,
|
|
89
|
+
outcome: report.Outcome,
|
|
90
|
+
...(report.ExtractionStatus ? { extractionStatus: report.ExtractionStatus } : {}),
|
|
91
|
+
queryColumns: [...report.QueryColumns],
|
|
92
|
+
added: report.Added.map(changeOutputOf),
|
|
93
|
+
updated: report.Updated.map(changeOutputOf),
|
|
94
|
+
removed: report.Removed.map(changeOutputOf),
|
|
95
|
+
flagged: [...report.Flagged],
|
|
96
|
+
diagnostics: [...report.Diagnostics],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function changeOutputOf(change) {
|
|
100
|
+
return { collection: change.Collection, name: change.Name, changedColumns: [...change.ChangedColumns] };
|
|
101
|
+
}
|
|
102
|
+
/** Keeps the operation in the bundle: import and call it where the class must be registered. */
|
|
103
|
+
export function LoadQueryRefreshExtractionServerOperation() {
|
|
104
|
+
// The import is what registers the class.
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=QueryRefreshExtractionServerOperation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryRefreshExtractionServerOperation.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/QueryRefreshExtractionServerOperation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { QueryExtractionService } from "./QueryExtractionService.js";
|
|
2
|
+
export { UserCanRefreshQueries, UserCanSeeQuerySources, EntityIDsOfExtraction, QueryRefreshUnavailableMessage, QUERY_REFRESH_CHILD_ENTITIES, } from "./refreshAuthorization.js";
|
|
3
|
+
export { OrderForRefresh } from "./refreshOrder.js";
|
|
4
|
+
export type { OrderableQuery, CompositionEdge, RefreshOrder } from "./refreshOrder.js";
|
|
5
|
+
export { SelectQueriesForRefresh } from "./refreshSelection.js";
|
|
6
|
+
export type { RefreshSelection } from "./refreshSelection.js";
|
|
7
|
+
export type { QueryRefreshProvider, QueryRefreshFilter, QueryRefreshOptions, QueryRefreshProgress, QueryRefreshOutcome, QueryRefreshReport, QueryRefreshRunReport, QueryRefreshContext, } from "./refreshTypes.js";
|
|
8
|
+
export { RebindQueriesForChangedEntities, DefinerRightsDriftMessage } from "./queryRebind.js";
|
|
9
|
+
export type { QueryRebindResult, QueryDefinerRightsDrift } from "./queryRebind.js";
|
|
10
|
+
export { FormatQueryRefreshRun, FormatQueryRefreshReport, FormatQueryRefreshSummary, QueryRefreshTotalsOf } from "./refreshFormat.js";
|
|
11
|
+
export type { QueryRefreshTotals } from "./refreshFormat.js";
|
|
12
|
+
export { IsQueryRefreshProvider } from "./refreshTypes.js";
|
|
13
|
+
export { QueryRefreshExtractionServerOperation, LoadQueryRefreshExtractionServerOperation, RefreshFilterOf, HasRefreshSelector, RefreshOutputOf, } from "./QueryRefreshExtractionServerOperation.js";
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,8BAA8B,EAC9B,4BAA4B,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EACR,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,+BAA+B,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC3F,YAAY,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACnI,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EACH,qCAAqC,EACrC,yCAAyC,EACzC,eAAe,EACf,kBAAkB,EAClB,eAAe,GAClB,MAAM,yCAAyC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Query refresh — re-establishing saved queries' facts on demand, and its authorization
|
|
2
|
+
export { QueryExtractionService } from "./QueryExtractionService.js";
|
|
3
|
+
export { UserCanRefreshQueries, UserCanSeeQuerySources, EntityIDsOfExtraction, QueryRefreshUnavailableMessage, QUERY_REFRESH_CHILD_ENTITIES, } from "./refreshAuthorization.js";
|
|
4
|
+
export { OrderForRefresh } from "./refreshOrder.js";
|
|
5
|
+
export { SelectQueriesForRefresh } from "./refreshSelection.js";
|
|
6
|
+
export { RebindQueriesForChangedEntities, DefinerRightsDriftMessage } from "./queryRebind.js";
|
|
7
|
+
export { FormatQueryRefreshRun, FormatQueryRefreshReport, FormatQueryRefreshSummary, QueryRefreshTotalsOf } from "./refreshFormat.js";
|
|
8
|
+
export { IsQueryRefreshProvider } from "./refreshTypes.js";
|
|
9
|
+
export { QueryRefreshExtractionServerOperation, LoadQueryRefreshExtractionServerOperation, RefreshFilterOf, HasRefreshSelector, RefreshOutputOf, } from "./QueryRefreshExtractionServerOperation.js";
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/index.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EACH,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,8BAA8B,EAC9B,4BAA4B,GAC/B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAY7D,OAAO,EAAE,+BAA+B,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAE3F,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEnI,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EACH,qCAAqC,EACrC,yCAAyC,EACzC,eAAe,EACf,kBAAkB,EAClB,eAAe,GAClB,MAAM,yCAAyC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { QueryRefreshContext, QueryRefreshRunReport } from "./refreshTypes.js";
|
|
2
|
+
/** A query that runs with definer's rights and gained a column field-level security restricts. */
|
|
3
|
+
export interface QueryDefinerRightsDrift {
|
|
4
|
+
readonly QueryID: string;
|
|
5
|
+
readonly QueryName: string;
|
|
6
|
+
/** The added output columns, each sourced from a field that has field permissions. */
|
|
7
|
+
readonly Fields: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
/** What a re-bind pass did. */
|
|
10
|
+
export interface QueryRebindResult {
|
|
11
|
+
/** The changed entities the pass was given. */
|
|
12
|
+
readonly EntityCount: number;
|
|
13
|
+
readonly Run: QueryRefreshRunReport;
|
|
14
|
+
readonly Drift: readonly QueryDefinerRightsDrift[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Re-binds the saved queries that read entities whose fields changed (a column added, dropped, or
|
|
18
|
+
* changed in type or nullability): each query that reads one of them (its `MJ: Query Entities`
|
|
19
|
+
* rows) is refreshed, with no description pass, so its fields follow the schema again. The SQL is
|
|
20
|
+
* never edited: a query the change broke is recorded with status `Error` and the database
|
|
21
|
+
* server's message.
|
|
22
|
+
*
|
|
23
|
+
* A query with `MJ: Query Permissions` rows runs with definer's rights: its role list alone
|
|
24
|
+
* authorizes a run, whatever the SQL reads. When such a query gains an output column (a `*` over
|
|
25
|
+
* a view that gained one) sourced from a field that has field permissions, the column now reaches
|
|
26
|
+
* every role on the list. The pass records that on the query as a `Warning` and returns it.
|
|
27
|
+
*
|
|
28
|
+
* @param entityIDs - The entities whose fields changed.
|
|
29
|
+
*/
|
|
30
|
+
export declare function RebindQueriesForChangedEntities(context: QueryRefreshContext, entityIDs: readonly string[]): Promise<QueryRebindResult>;
|
|
31
|
+
/** The `ExtractionMessage` line for a definer's-rights query that gained restricted columns. */
|
|
32
|
+
export declare function DefinerRightsDriftMessage(fields: readonly string[]): string;
|
|
33
|
+
//# sourceMappingURL=queryRebind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryRebind.d.ts","sourceRoot":"","sources":["../../../src/custom/query-refresh/queryRebind.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAsB,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAErG,kGAAkG;AAClG,MAAM,WAAW,uBAAuB;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,+BAA+B;AAC/B,MAAM,WAAW,iBAAiB;IAC9B,+CAA+C;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,qBAAqB,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,uBAAuB,EAAE,CAAC;CACtD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,+BAA+B,CAAC,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAO5I;AAkDD,gGAAgG;AAChG,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAI3E"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { LogError } from "@memberjunction/core";
|
|
2
|
+
import { EscapeSQLString, NormalizeUUID } from "@memberjunction/global";
|
|
3
|
+
import { QueryExtractionService } from "./QueryExtractionService.js";
|
|
4
|
+
/**
|
|
5
|
+
* Re-binds the saved queries that read entities whose fields changed (a column added, dropped, or
|
|
6
|
+
* changed in type or nullability): each query that reads one of them (its `MJ: Query Entities`
|
|
7
|
+
* rows) is refreshed, with no description pass, so its fields follow the schema again. The SQL is
|
|
8
|
+
* never edited: a query the change broke is recorded with status `Error` and the database
|
|
9
|
+
* server's message.
|
|
10
|
+
*
|
|
11
|
+
* A query with `MJ: Query Permissions` rows runs with definer's rights: its role list alone
|
|
12
|
+
* authorizes a run, whatever the SQL reads. When such a query gains an output column (a `*` over
|
|
13
|
+
* a view that gained one) sourced from a field that has field permissions, the column now reaches
|
|
14
|
+
* every role on the list. The pass records that on the query as a `Warning` and returns it.
|
|
15
|
+
*
|
|
16
|
+
* @param entityIDs - The entities whose fields changed.
|
|
17
|
+
*/
|
|
18
|
+
export async function RebindQueriesForChangedEntities(context, entityIDs) {
|
|
19
|
+
const unique = [...new Set(entityIDs.map(NormalizeUUID))];
|
|
20
|
+
if (unique.length === 0)
|
|
21
|
+
return { EntityCount: 0, Run: { DryRun: false, Reports: [], Cycles: [] }, Drift: [] };
|
|
22
|
+
const run = await new QueryExtractionService(context).RefreshQueries({ EntityIDs: unique }, { WithAI: false });
|
|
23
|
+
const drift = await findDefinerRightsDrift(context, run.Reports);
|
|
24
|
+
for (const item of drift)
|
|
25
|
+
await recordDrift(context, item);
|
|
26
|
+
return { EntityCount: unique.length, Run: run, Drift: drift };
|
|
27
|
+
}
|
|
28
|
+
/** The refreshed queries that run with definer's rights and gained a column sourced from a field with field permissions. */
|
|
29
|
+
async function findDefinerRightsDrift(context, reports) {
|
|
30
|
+
const restricted = restrictedFieldIDs(context.Provider.Entities);
|
|
31
|
+
const candidates = reports
|
|
32
|
+
.map(r => ({ Report: r, Fields: r.Added.filter(c => c.Collection === 'Fields' && c.SourceEntityFieldID && restricted.has(NormalizeUUID(c.SourceEntityFieldID))) }))
|
|
33
|
+
.filter(c => c.Fields.length > 0);
|
|
34
|
+
if (candidates.length === 0)
|
|
35
|
+
return [];
|
|
36
|
+
const definerRights = await queriesWithPermissions(context, candidates.map(c => c.Report.QueryID));
|
|
37
|
+
return candidates
|
|
38
|
+
.filter(c => definerRights.has(NormalizeUUID(c.Report.QueryID)))
|
|
39
|
+
.map(c => ({ QueryID: c.Report.QueryID, QueryName: c.Report.QueryName, Fields: c.Fields.map(f => f.Name) }));
|
|
40
|
+
}
|
|
41
|
+
/** The IDs of fields that have field permissions, or that belong to an entity field-level security applies to. */
|
|
42
|
+
function restrictedFieldIDs(entities) {
|
|
43
|
+
const ids = new Set();
|
|
44
|
+
for (const entity of entities) {
|
|
45
|
+
for (const field of entity.Fields) {
|
|
46
|
+
if (field.HasFieldPermissions || entity.FieldLevelSecurityApplies)
|
|
47
|
+
ids.add(NormalizeUUID(field.ID));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return ids;
|
|
51
|
+
}
|
|
52
|
+
async function queriesWithPermissions(context, queryIDs) {
|
|
53
|
+
const list = queryIDs.map(id => `'${EscapeSQLString(id)}'`).join(',');
|
|
54
|
+
const result = await context.Provider.RunView({
|
|
55
|
+
EntityName: 'MJ: Query Permissions', ExtraFilter: `QueryID IN (${list})`, Fields: ['QueryID'], ResultType: 'simple', BypassCache: true, IgnoreMaxRows: true,
|
|
56
|
+
}, context.User);
|
|
57
|
+
if (!result.Success)
|
|
58
|
+
throw new Error(`the query permissions could not be read: ${result.ErrorMessage}`);
|
|
59
|
+
return new Set(result.Results.map(r => NormalizeUUID(r.QueryID)));
|
|
60
|
+
}
|
|
61
|
+
/** Records the drift on the query: status `Warning` (unless it is already `Error`) and a message line. */
|
|
62
|
+
async function recordDrift(context, drift) {
|
|
63
|
+
const message = DefinerRightsDriftMessage(drift.Fields);
|
|
64
|
+
try {
|
|
65
|
+
const query = await context.Provider.GetEntityObject('MJ: Queries', context.User);
|
|
66
|
+
if (!await query.Load(drift.QueryID))
|
|
67
|
+
throw new Error('the query could not be loaded');
|
|
68
|
+
if (query.ExtractionStatus !== 'Error')
|
|
69
|
+
query.ExtractionStatus = 'Warning';
|
|
70
|
+
query.ExtractionMessage = query.ExtractionMessage ? `${query.ExtractionMessage}\n${message}` : message;
|
|
71
|
+
query.ExtractionOverride = 'Skip';
|
|
72
|
+
if (!await query.Save())
|
|
73
|
+
throw new Error(query.LatestResult?.CompleteMessage ?? 'the save failed');
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
LogError(`[RebindQueriesForChangedEntities] the definer's-rights warning for query "${drift.QueryName}" could not be recorded: ${e instanceof Error ? e.message : String(e)}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** The `ExtractionMessage` line for a definer's-rights query that gained restricted columns. */
|
|
80
|
+
export function DefinerRightsDriftMessage(fields) {
|
|
81
|
+
return `The query's output gained ${fields.map(f => `"${f}"`).join(', ')}, sourced from fields restricted by field-level security. ` +
|
|
82
|
+
'The query is authorized by its Query Permissions role list alone, so every role on that list can now read these columns. ' +
|
|
83
|
+
'Review the role list, or name the columns the query returns instead of using *.';
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=queryRebind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryRebind.js","sourceRoot":"","sources":["../../../src/custom/query-refresh/queryRebind.ts"],"names":[],"mappings":"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"}
|