@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,40 @@
|
|
|
1
|
+
import type { DatabasePlatform, IRunViewProvider, QueryDependencySpec, UserInfo } from "@memberjunction/core";
|
|
2
|
+
import type { MJQueryDependencyEntity, MJQueryParameterEntity, MJSQLDialectEntity } from "@memberjunction/core-entities";
|
|
3
|
+
/** A composed query's parameter, as extraction reads it. */
|
|
4
|
+
export type CompositionCandidateParameter = Pick<MJQueryParameterEntity, 'Name' | 'Type' | 'IsRequired' | 'IsServerSet' | 'SampleValue' | 'Description' | 'Query'>;
|
|
5
|
+
/**
|
|
6
|
+
* A query a composition may name, as extraction reads it: identity and path, whether it may be
|
|
7
|
+
* composed, its parameters and the queries it composes in turn. A cached `MJQueryEntityExtended`
|
|
8
|
+
* is one; so is a query read from the database during a save.
|
|
9
|
+
*/
|
|
10
|
+
export interface CompositionCandidate {
|
|
11
|
+
readonly ID: string;
|
|
12
|
+
readonly Name: string;
|
|
13
|
+
readonly CategoryPath: string;
|
|
14
|
+
readonly Reusable: boolean;
|
|
15
|
+
readonly QueryParameters: readonly CompositionCandidateParameter[];
|
|
16
|
+
readonly QueryDependencies: readonly Pick<MJQueryDependencyEntity, 'DependsOnQueryID'>[];
|
|
17
|
+
}
|
|
18
|
+
/** The composed queries a save read from its own provider. */
|
|
19
|
+
export interface CompositionTargetRead {
|
|
20
|
+
/** Every query named by a composition in the SQL, as stored now (in the save's transaction). */
|
|
21
|
+
readonly Candidates: readonly CompositionCandidate[];
|
|
22
|
+
/**
|
|
23
|
+
* Render specs for the candidates the given cache does not hold yet (saved earlier in the same
|
|
24
|
+
* transaction), so the describe renders can compose them before the cache hears of them.
|
|
25
|
+
*/
|
|
26
|
+
readonly InlineDependencies: readonly QueryDependencySpec[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Reads the queries the compositions in `sql` name from `provider`, bypassing every cache, so a
|
|
30
|
+
* query saved earlier in the same transaction (a metadata push that creates a query and one that
|
|
31
|
+
* composes it) is found. Queries are matched by name; the caller matches category paths.
|
|
32
|
+
* @param cachedIDs - IDs of the queries the shared cache already holds; the others get render specs.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ReadCompositionTargetsAsync(sql: string, platform: DatabasePlatform, provider: Pick<IRunViewProvider, 'RunViews'>, user: UserInfo, cachedIDs: ReadonlySet<string>, dialects: readonly MJSQLDialectEntity[]): Promise<CompositionTargetRead>;
|
|
35
|
+
/**
|
|
36
|
+
* The candidates extraction resolves against: the ones read from the database, then every cached
|
|
37
|
+
* query the read did not return (a query read from the database replaces its cached copy).
|
|
38
|
+
*/
|
|
39
|
+
export declare function MergeCompositionCandidates(read: readonly CompositionCandidate[], cached: readonly CompositionCandidate[]): CompositionCandidate[];
|
|
40
|
+
//# sourceMappingURL=compositionTargets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compositionTargets.d.ts","sourceRoot":"","sources":["../../../src/custom/query-extraction/compositionTargets.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,mBAAmB,EAAiB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7H,OAAO,KAAK,EAER,uBAAuB,EAEvB,sBAAsB,EAEtB,kBAAkB,EACrB,MAAM,+BAA+B,CAAC;AAKvC,4DAA4D;AAC5D,MAAM,MAAM,6BAA6B,GAAG,IAAI,CAAC,sBAAsB,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,OAAO,CAAC,CAAC;AAEnK;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,SAAS,6BAA6B,EAAE,CAAC;IACnE,QAAQ,CAAC,iBAAiB,EAAE,SAAS,IAAI,CAAC,uBAAuB,EAAE,kBAAkB,CAAC,EAAE,CAAC;CAC5F;AAED,8DAA8D;AAC9D,MAAM,WAAW,qBAAqB;IAClC,gGAAgG;IAChG,QAAQ,CAAC,UAAU,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACrD;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,EAAE,SAAS,mBAAmB,EAAE,CAAC;CAC/D;AAaD;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAC7C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,EAC5C,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,EAC9B,QAAQ,EAAE,SAAS,kBAAkB,EAAE,GACxC,OAAO,CAAC,qBAAqB,CAAC,CAWhC;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,SAAS,oBAAoB,EAAE,EAAE,MAAM,EAAE,SAAS,oBAAoB,EAAE,GAAG,oBAAoB,EAAE,CAGjJ"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { QueryParameterInfo } from "@memberjunction/core";
|
|
2
|
+
import { GetQueryDialect } from "@memberjunction/sql-dialect";
|
|
3
|
+
import { QueryTemplate } from "@memberjunction/sql-parser";
|
|
4
|
+
import { EscapeSQLString, IndexByUUID, UUIDsEqual } from "@memberjunction/global";
|
|
5
|
+
const EMPTY_READ = { Candidates: [], InlineDependencies: [] };
|
|
6
|
+
/**
|
|
7
|
+
* Reads the queries the compositions in `sql` name from `provider`, bypassing every cache, so a
|
|
8
|
+
* query saved earlier in the same transaction (a metadata push that creates a query and one that
|
|
9
|
+
* composes it) is found. Queries are matched by name; the caller matches category paths.
|
|
10
|
+
* @param cachedIDs - IDs of the queries the shared cache already holds; the others get render specs.
|
|
11
|
+
*/
|
|
12
|
+
export async function ReadCompositionTargetsAsync(sql, platform, provider, user, cachedIDs, dialects) {
|
|
13
|
+
const names = [...new Set(QueryTemplate.Parse(sql, GetQueryDialect(platform)).CompositionReferences().Value.map(r => r.Name.trim().toLowerCase()))];
|
|
14
|
+
if (names.length === 0)
|
|
15
|
+
return EMPTY_READ;
|
|
16
|
+
const rows = await readTargetRows(names, provider, user);
|
|
17
|
+
if (!rows)
|
|
18
|
+
return EMPTY_READ;
|
|
19
|
+
const candidates = rows.Queries.map(q => candidateOf(q, rows));
|
|
20
|
+
const dialectID = dialects.find(d => d.PlatformKey === platform)?.ID ?? null;
|
|
21
|
+
const inline = rows.Queries
|
|
22
|
+
.filter(q => !cachedIDs.has(q.ID.toLowerCase()))
|
|
23
|
+
.map(q => inlineSpecOf(q, rows, dialectID));
|
|
24
|
+
return { Candidates: candidates, InlineDependencies: inline };
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The candidates extraction resolves against: the ones read from the database, then every cached
|
|
28
|
+
* query the read did not return (a query read from the database replaces its cached copy).
|
|
29
|
+
*/
|
|
30
|
+
export function MergeCompositionCandidates(read, cached) {
|
|
31
|
+
const readIDs = new Set(read.map(q => q.ID.toLowerCase()));
|
|
32
|
+
return [...read, ...cached.filter(q => !readIDs.has(q.ID.toLowerCase()))];
|
|
33
|
+
}
|
|
34
|
+
async function readTargetRows(names, provider, user) {
|
|
35
|
+
const nameList = names.map(n => `'${EscapeSQLString(n)}'`).join(', ');
|
|
36
|
+
const [queries, categories] = await provider.RunViews([
|
|
37
|
+
bypassing('MJ: Queries', `LOWER(Name) IN (${nameList})`),
|
|
38
|
+
bypassing('MJ: Query Categories', ''),
|
|
39
|
+
], user);
|
|
40
|
+
if (!queries.Success || !categories.Success || queries.Results.length === 0)
|
|
41
|
+
return null;
|
|
42
|
+
const queryRows = queries.Results;
|
|
43
|
+
const idList = queryRows.map(q => `'${EscapeSQLString(q.ID)}'`).join(', ');
|
|
44
|
+
const [parameters, dependencies, sqls] = await provider.RunViews([
|
|
45
|
+
bypassing('MJ: Query Parameters', `QueryID IN (${idList})`),
|
|
46
|
+
bypassing('MJ: Query Dependencies', `QueryID IN (${idList})`),
|
|
47
|
+
bypassing('MJ: Query SQLs', `QueryID IN (${idList})`),
|
|
48
|
+
], user);
|
|
49
|
+
if (!parameters.Success || !dependencies.Success || !sqls.Success)
|
|
50
|
+
return null;
|
|
51
|
+
return {
|
|
52
|
+
Queries: queryRows,
|
|
53
|
+
Categories: categories.Results,
|
|
54
|
+
Parameters: parameters.Results,
|
|
55
|
+
Dependencies: dependencies.Results,
|
|
56
|
+
SQLs: sqls.Results,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function bypassing(entityName, filter) {
|
|
60
|
+
return { EntityName: entityName, ExtraFilter: filter, ResultType: 'entity_object', BypassCache: true, IgnoreMaxRows: true };
|
|
61
|
+
}
|
|
62
|
+
function candidateOf(query, rows) {
|
|
63
|
+
return {
|
|
64
|
+
ID: query.ID,
|
|
65
|
+
Name: query.Name,
|
|
66
|
+
CategoryPath: categoryPathOf(query.CategoryID, rows.Categories),
|
|
67
|
+
Reusable: query.Reusable,
|
|
68
|
+
QueryParameters: rows.Parameters.filter(p => UUIDsEqual(p.QueryID, query.ID)),
|
|
69
|
+
QueryDependencies: rows.Dependencies.filter(d => UUIDsEqual(d.QueryID, query.ID)),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/** The `/`-joined names from the root category down to `categoryID`; `''` for no category. */
|
|
73
|
+
function categoryPathOf(categoryID, categories) {
|
|
74
|
+
const byID = IndexByUUID(categories);
|
|
75
|
+
const segments = [];
|
|
76
|
+
const seen = new Set();
|
|
77
|
+
let current = categoryID;
|
|
78
|
+
while (current && !seen.has(current.toLowerCase())) {
|
|
79
|
+
seen.add(current.toLowerCase());
|
|
80
|
+
const category = byID.Get(current);
|
|
81
|
+
if (!category)
|
|
82
|
+
break;
|
|
83
|
+
segments.unshift(category.Name);
|
|
84
|
+
current = category.ParentID;
|
|
85
|
+
}
|
|
86
|
+
return segments.join('/');
|
|
87
|
+
}
|
|
88
|
+
/** A render spec for a query the cache does not hold: its SQL for the platform and its parameter definitions. */
|
|
89
|
+
function inlineSpecOf(query, rows, dialectID) {
|
|
90
|
+
const variant = dialectID ? rows.SQLs.find(s => UUIDsEqual(s.QueryID, query.ID) && UUIDsEqual(s.SQLDialectID, dialectID)) : undefined;
|
|
91
|
+
return {
|
|
92
|
+
Name: query.Name,
|
|
93
|
+
CategoryPath: categoryPathOf(query.CategoryID, rows.Categories),
|
|
94
|
+
SQL: variant?.SQL ?? query.SQL ?? '',
|
|
95
|
+
UsesTemplate: query.UsesTemplate,
|
|
96
|
+
ParameterDefinitions: rows.Parameters.filter(p => UUIDsEqual(p.QueryID, query.ID)).map(p => new QueryParameterInfo(p.GetAll())),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=compositionTargets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compositionTargets.js","sourceRoot":"","sources":["../../../src/custom/query-extraction/compositionTargets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { BaseEntity, RelatedRecordCollection } from "@memberjunction/core";
|
|
2
|
+
import type { MJQueryEntityEntity, MJQueryFieldEntity, MJQueryParameterEntity } from "@memberjunction/core-entities";
|
|
3
|
+
/**
|
|
4
|
+
* The child rows a query save declares, as the keys extraction matches rows by.
|
|
5
|
+
*
|
|
6
|
+
* A row is *declared* when the save writes it from one of the query's declared collections
|
|
7
|
+
* (`Parameters`, `Fields`, `Entities` on `MJQueryEntityExtended`): it is new, or it was edited.
|
|
8
|
+
* Keys are lower-cased so they compare the way the database does.
|
|
9
|
+
*
|
|
10
|
+
* Extraction treats a declared row as the caller's decision and leaves it alone: it does not add a
|
|
11
|
+
* row with the same key, update it, or delete it, even when the SQL no longer mentions it. That is
|
|
12
|
+
* how a declared row "wins" over what extraction would have written for the same key in the same
|
|
13
|
+
* save. Any later extraction (an extraction service, a refresh) that replaces the current one must
|
|
14
|
+
* honour these sets the same way; the facts it would compute for a declared row can be reported, but
|
|
15
|
+
* not written.
|
|
16
|
+
*/
|
|
17
|
+
export interface DeclaredQueryChildren {
|
|
18
|
+
/** Declared parameter names. */
|
|
19
|
+
ParameterNames: ReadonlySet<string>;
|
|
20
|
+
/** Declared output field names. */
|
|
21
|
+
FieldNames: ReadonlySet<string>;
|
|
22
|
+
/** Declared entity links, keyed by {@link QueryEntityKey} (the entity ID). */
|
|
23
|
+
EntityKeys: ReadonlySet<string>;
|
|
24
|
+
}
|
|
25
|
+
/** A declared set with nothing in it, for saves that declare no children. */
|
|
26
|
+
export declare const NO_DECLARED_QUERY_CHILDREN: DeclaredQueryChildren;
|
|
27
|
+
/** The three declared collections of a query, as `MJQueryEntityExtended` exposes them. */
|
|
28
|
+
export interface DeclaredQueryCollections {
|
|
29
|
+
Parameters: RelatedRecordCollection<MJQueryParameterEntity>;
|
|
30
|
+
Fields: RelatedRecordCollection<MJQueryFieldEntity>;
|
|
31
|
+
Entities: RelatedRecordCollection<MJQueryEntityEntity>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The key a Query Entity row is matched by: the entity it links. Extraction keeps at most one row
|
|
35
|
+
* per entity (it updates the alternate base view on that row), so a declared row for an entity
|
|
36
|
+
* stands for every link to it.
|
|
37
|
+
*/
|
|
38
|
+
export declare function QueryEntityKey(row: Pick<MJQueryEntityEntity, 'EntityID'>): string;
|
|
39
|
+
/** The key a parameter or field row is matched by: its name, trimmed and lower-cased. */
|
|
40
|
+
export declare function QueryChildNameKey(name: string | null | undefined): string;
|
|
41
|
+
/**
|
|
42
|
+
* The child rows a save of the query declares, read from its declared collections before the save.
|
|
43
|
+
*
|
|
44
|
+
* @param collections - The query's declared collections.
|
|
45
|
+
* @returns The declared keys; empty sets when the collections hold nothing to write.
|
|
46
|
+
*/
|
|
47
|
+
export declare function CollectDeclaredQueryChildren(collections: DeclaredQueryCollections): DeclaredQueryChildren;
|
|
48
|
+
/** True when the declared set holds at least one row. */
|
|
49
|
+
export declare function HasDeclaredQueryChildren(declared: DeclaredQueryChildren): boolean;
|
|
50
|
+
/** A stored row and its detection method, as conflict detection reads it. */
|
|
51
|
+
type DetectedRow = BaseEntity & {
|
|
52
|
+
ID: string;
|
|
53
|
+
DetectionMethod: string;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* The stored rows a declared collection item replaces: rows with the same key as a NEW item but a
|
|
57
|
+
* different ID, that extraction (not a person) created. A row whose `DetectionMethod` is `Manual`
|
|
58
|
+
* was authored and is never selected, so authored rows are never touched.
|
|
59
|
+
*
|
|
60
|
+
* @param newItems - The collection's unsaved items.
|
|
61
|
+
* @param stored - The rows stored for the query, read from the database.
|
|
62
|
+
* @param key - How rows are matched.
|
|
63
|
+
* @returns The stored rows to delete in the same save, before the new items are inserted.
|
|
64
|
+
*/
|
|
65
|
+
export declare function FindReplacedRows<T extends DetectedRow>(newItems: readonly T[], stored: readonly T[], key: (row: T) => string): T[];
|
|
66
|
+
/**
|
|
67
|
+
* Queues a stored row for deletion through the collection, so the delete runs inside the query's
|
|
68
|
+
* graph save, before the collection's inserts (a collection's removals run first). The row is
|
|
69
|
+
* removed from the collection when the collection already holds it; otherwise it is attached and
|
|
70
|
+
* removed, which queues the same delete.
|
|
71
|
+
*
|
|
72
|
+
* @param collection - The declared collection.
|
|
73
|
+
* @param row - The stored row to delete.
|
|
74
|
+
*/
|
|
75
|
+
export declare function QueueReplacedRowDeletion<T extends BaseEntity & {
|
|
76
|
+
ID: string;
|
|
77
|
+
}>(collection: RelatedRecordCollection<T>, row: T): void;
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=declared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declared.d.ts","sourceRoot":"","sources":["../../../src/custom/query-extraction/declared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAGrH;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,qBAAqB;IAClC,gCAAgC;IAChC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,mCAAmC;IACnC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAChC,8EAA8E;IAC9E,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACnC;AAED,6EAA6E;AAC7E,eAAO,MAAM,0BAA0B,EAAE,qBAIxC,CAAC;AAEF,0FAA0F;AAC1F,MAAM,WAAW,wBAAwB;IACrC,UAAU,EAAE,uBAAuB,CAAC,sBAAsB,CAAC,CAAC;IAC5D,MAAM,EAAE,uBAAuB,CAAC,kBAAkB,CAAC,CAAC;IACpD,QAAQ,EAAE,uBAAuB,CAAC,mBAAmB,CAAC,CAAC;CAC1D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,mBAAmB,EAAE,UAAU,CAAC,GAAG,MAAM,CAEjF;AAED,yFAAyF;AACzF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAEzE;AAkBD;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,wBAAwB,GAAG,qBAAqB,CAMzG;AAED,yDAAyD;AACzD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,OAAO,CAEjF;AAED,6EAA6E;AAC7E,KAAK,WAAW,GAAG,UAAU,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,WAAW,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,GAAG,CAAC,EAAE,CAWlI;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,UAAU,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,UAAU,EAAE,uBAAuB,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAQpI"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { NormalizeUUID, UUIDsEqual } from "@memberjunction/global";
|
|
2
|
+
/** A declared set with nothing in it, for saves that declare no children. */
|
|
3
|
+
export const NO_DECLARED_QUERY_CHILDREN = {
|
|
4
|
+
ParameterNames: new Set(),
|
|
5
|
+
FieldNames: new Set(),
|
|
6
|
+
EntityKeys: new Set(),
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The key a Query Entity row is matched by: the entity it links. Extraction keeps at most one row
|
|
10
|
+
* per entity (it updates the alternate base view on that row), so a declared row for an entity
|
|
11
|
+
* stands for every link to it.
|
|
12
|
+
*/
|
|
13
|
+
export function QueryEntityKey(row) {
|
|
14
|
+
return row.EntityID ? NormalizeUUID(row.EntityID) : '';
|
|
15
|
+
}
|
|
16
|
+
/** The key a parameter or field row is matched by: its name, trimmed and lower-cased. */
|
|
17
|
+
export function QueryChildNameKey(name) {
|
|
18
|
+
return (name ?? '').trim().toLowerCase();
|
|
19
|
+
}
|
|
20
|
+
/** True when the save will write this collection item: it is new, or it has unsaved edits. */
|
|
21
|
+
function isWrittenBySave(item) {
|
|
22
|
+
return !item.IsSaved || item.Dirty;
|
|
23
|
+
}
|
|
24
|
+
/** The keys of the items a save writes from one collection. */
|
|
25
|
+
function writtenKeys(items, key) {
|
|
26
|
+
const keys = new Set();
|
|
27
|
+
for (const item of items) {
|
|
28
|
+
if (isWrittenBySave(item)) {
|
|
29
|
+
keys.add(key(item));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return keys;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The child rows a save of the query declares, read from its declared collections before the save.
|
|
36
|
+
*
|
|
37
|
+
* @param collections - The query's declared collections.
|
|
38
|
+
* @returns The declared keys; empty sets when the collections hold nothing to write.
|
|
39
|
+
*/
|
|
40
|
+
export function CollectDeclaredQueryChildren(collections) {
|
|
41
|
+
return {
|
|
42
|
+
ParameterNames: writtenKeys(collections.Parameters.Items, p => QueryChildNameKey(p.Name)),
|
|
43
|
+
FieldNames: writtenKeys(collections.Fields.Items, f => QueryChildNameKey(f.Name)),
|
|
44
|
+
EntityKeys: writtenKeys(collections.Entities.Items, QueryEntityKey),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** True when the declared set holds at least one row. */
|
|
48
|
+
export function HasDeclaredQueryChildren(declared) {
|
|
49
|
+
return declared.ParameterNames.size > 0 || declared.FieldNames.size > 0 || declared.EntityKeys.size > 0;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The stored rows a declared collection item replaces: rows with the same key as a NEW item but a
|
|
53
|
+
* different ID, that extraction (not a person) created. A row whose `DetectionMethod` is `Manual`
|
|
54
|
+
* was authored and is never selected, so authored rows are never touched.
|
|
55
|
+
*
|
|
56
|
+
* @param newItems - The collection's unsaved items.
|
|
57
|
+
* @param stored - The rows stored for the query, read from the database.
|
|
58
|
+
* @param key - How rows are matched.
|
|
59
|
+
* @returns The stored rows to delete in the same save, before the new items are inserted.
|
|
60
|
+
*/
|
|
61
|
+
export function FindReplacedRows(newItems, stored, key) {
|
|
62
|
+
const newByKey = new Map();
|
|
63
|
+
for (const item of newItems) {
|
|
64
|
+
newByKey.set(key(item), item);
|
|
65
|
+
}
|
|
66
|
+
return stored.filter(row => {
|
|
67
|
+
const declared = newByKey.get(key(row));
|
|
68
|
+
return declared !== undefined
|
|
69
|
+
&& !UUIDsEqual(row.ID, declared.ID)
|
|
70
|
+
&& row.DetectionMethod !== 'Manual';
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Queues a stored row for deletion through the collection, so the delete runs inside the query's
|
|
75
|
+
* graph save, before the collection's inserts (a collection's removals run first). The row is
|
|
76
|
+
* removed from the collection when the collection already holds it; otherwise it is attached and
|
|
77
|
+
* removed, which queues the same delete.
|
|
78
|
+
*
|
|
79
|
+
* @param collection - The declared collection.
|
|
80
|
+
* @param row - The stored row to delete.
|
|
81
|
+
*/
|
|
82
|
+
export function QueueReplacedRowDeletion(collection, row) {
|
|
83
|
+
const held = collection.Items.find(item => item.IsSaved && UUIDsEqual(item.ID, row.ID));
|
|
84
|
+
if (held) {
|
|
85
|
+
collection.Remove(held);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
collection.Add(row);
|
|
89
|
+
collection.Remove(row);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=declared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declared.js","sourceRoot":"","sources":["../../../src/custom/query-extraction/declared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { DescribedColumn } from "@memberjunction/generic-database-provider";
|
|
2
|
+
import type { QueryTemplate } from "@memberjunction/sql-parser";
|
|
3
|
+
import type { QueryExtractionInput, QueryParameterFact, QueryParameterType } from "./extractionTypes.js";
|
|
4
|
+
/** The output of every render of the query, as the database server described it. */
|
|
5
|
+
export interface DescribedOutput {
|
|
6
|
+
/** The union of the renders' columns by name (case-insensitive): the base render's first, in order. */
|
|
7
|
+
readonly Columns: readonly DescribedColumn[];
|
|
8
|
+
/** Columns only some renders produce: the render that first produced each, or one that did not return it. */
|
|
9
|
+
readonly BranchOnlyColumns: readonly string[];
|
|
10
|
+
/** Output names a single render returns more than once (case-insensitive). */
|
|
11
|
+
readonly DuplicateNames: readonly string[];
|
|
12
|
+
/** Why the output could not be described (a render or the server failed); `null` on success. */
|
|
13
|
+
readonly Failure: string | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Renders the query with sample values, once for the base assignment and once per `{% if %}`
|
|
17
|
+
* toggled on its own (`QueryTemplate.BranchVariants`), and describes each render on the database
|
|
18
|
+
* server. Renders whose SQL repeats an earlier one are not described again. Plain SQL is
|
|
19
|
+
* described once, as written.
|
|
20
|
+
*/
|
|
21
|
+
export declare function DescribeQueryOutput(input: QueryExtractionInput, template: QueryTemplate, parameters: readonly QueryParameterFact[]): Promise<DescribedOutput>;
|
|
22
|
+
/**
|
|
23
|
+
* The statement without the semicolons before and after it (`;SELECT …;`): a statement described on
|
|
24
|
+
* its own (PostgreSQL prepares it) cannot carry them, though the query runs with them.
|
|
25
|
+
*/
|
|
26
|
+
export declare function WithoutStatementSemicolons(sql: string, input: Pick<QueryExtractionInput, 'Platform'>): string;
|
|
27
|
+
/**
|
|
28
|
+
* Why a render of the query may not run, as the run would refuse it: the first render (the base,
|
|
29
|
+
* then each `{% if %}` toggled) that is not a single read query or calls a function a query may not
|
|
30
|
+
* call. `null` when every render passes; a render that fails for another reason is left to
|
|
31
|
+
* {@link DescribeQueryOutput}, which reports it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function FindUnsafeRender(input: QueryExtractionInput, template: QueryTemplate, parameters: readonly QueryParameterFact[]): string | null;
|
|
34
|
+
/**
|
|
35
|
+
* A truthy sample value of `type`, as a render takes it: the row's sample when it fits the type,
|
|
36
|
+
* otherwise a fixed value (`Sample`, `1`, `2024-01-01`, `true`, `["1"]`). An array's fixed element is
|
|
37
|
+
* a numeric string, so a loop over it can feed a string hole or a number argument alike.
|
|
38
|
+
*/
|
|
39
|
+
export declare function SampleValueFor(type: QueryParameterType, sample: string | null): string;
|
|
40
|
+
//# sourceMappingURL=describeFacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describeFacts.d.ts","sourceRoot":"","sources":["../../../src/custom/query-extraction/describeFacts.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE7E,OAAO,KAAK,EAAuB,oBAAoB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE3H,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC5B,uGAAuG;IACvG,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;IAC7C,6GAA6G;IAC7G,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,gGAAgG;IAChG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAYD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,kBAAkB,EAAE,GAAG,OAAO,CAAC,eAAe,CAAC,CAoBnK;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC,GAAG,MAAM,CAS7G;AA6DD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,GAAG,IAAI,CAQ/I;AAyFD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAStF"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { IsQuerySafetyError, RenderPipeline, SafetyGate } from "@memberjunction/generic-database-provider";
|
|
2
|
+
import { GetDialect } from "@memberjunction/sql-dialect";
|
|
3
|
+
import { BranchVariantValues, LexSQL, SignificantTokens } from "@memberjunction/sql-parser";
|
|
4
|
+
import { NormalizeDefaultForType } from "./enrich.js";
|
|
5
|
+
/** The most branch renders described beyond the base, so a template with many blocks stays bounded. */
|
|
6
|
+
const MAX_VARIANT_RENDERS = 32;
|
|
7
|
+
/**
|
|
8
|
+
* Renders the query with sample values, once for the base assignment and once per `{% if %}`
|
|
9
|
+
* toggled on its own (`QueryTemplate.BranchVariants`), and describes each render on the database
|
|
10
|
+
* server. Renders whose SQL repeats an earlier one are not described again. Plain SQL is
|
|
11
|
+
* described once, as written.
|
|
12
|
+
*/
|
|
13
|
+
export async function DescribeQueryOutput(input, template, parameters) {
|
|
14
|
+
if (!input.Describe)
|
|
15
|
+
return failure('The database provider cannot describe a statement, so the output fields were not checked.');
|
|
16
|
+
const definitions = renderDefinitions(parameters, input.KnownParameters);
|
|
17
|
+
const renders = template.Tokens.HasTemplate ? renderAssignments(template) : [null];
|
|
18
|
+
const columns = [];
|
|
19
|
+
const branchOnly = [];
|
|
20
|
+
const duplicates = new Set();
|
|
21
|
+
const seenSQL = new Set();
|
|
22
|
+
for (const [index, values] of renders.entries()) {
|
|
23
|
+
const rendered = renderVariant(input, definitions, values);
|
|
24
|
+
if (rendered.Error !== null)
|
|
25
|
+
return failure(`Render ${index} could not be made: ${rendered.Error}`);
|
|
26
|
+
if (seenSQL.has(rendered.SQL))
|
|
27
|
+
continue;
|
|
28
|
+
seenSQL.add(rendered.SQL);
|
|
29
|
+
const described = await input.Describe(WithoutStatementSemicolons(rendered.SQL, input));
|
|
30
|
+
if (!described.Success)
|
|
31
|
+
return failure(`The database server could not describe the query: ${described.Diagnostics.join('; ') || 'no reason given'}`);
|
|
32
|
+
for (const name of duplicateNames(described.Columns))
|
|
33
|
+
duplicates.add(name);
|
|
34
|
+
if (index > 0)
|
|
35
|
+
noteMissingColumns(columns, described.Columns, index, branchOnly);
|
|
36
|
+
mergeColumns(columns, described.Columns, index, branchOnly);
|
|
37
|
+
}
|
|
38
|
+
return { Columns: columns, BranchOnlyColumns: branchOnly, DuplicateNames: [...duplicates], Failure: null };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The statement without the semicolons before and after it (`;SELECT …;`): a statement described on
|
|
42
|
+
* its own (PostgreSQL prepares it) cannot carry them, though the query runs with them.
|
|
43
|
+
*/
|
|
44
|
+
export function WithoutStatementSemicolons(sql, input) {
|
|
45
|
+
const tokens = SignificantTokens(LexSQL(sql, GetDialect(input.Platform)));
|
|
46
|
+
let first = 0;
|
|
47
|
+
while (first < tokens.length && tokens[first].Kind === 'semicolon')
|
|
48
|
+
first++;
|
|
49
|
+
let last = tokens.length - 1;
|
|
50
|
+
while (last >= first && tokens[last].Kind === 'semicolon')
|
|
51
|
+
last--;
|
|
52
|
+
if (first > last)
|
|
53
|
+
return sql;
|
|
54
|
+
if (first === 0 && last === tokens.length - 1)
|
|
55
|
+
return sql;
|
|
56
|
+
return sql.substring(0, tokens[0].Start) + sql.substring(tokens[first].Start, tokens[last].End);
|
|
57
|
+
}
|
|
58
|
+
function failure(message) {
|
|
59
|
+
return { Columns: [], BranchOnlyColumns: [], DuplicateNames: [], Failure: message };
|
|
60
|
+
}
|
|
61
|
+
/** Appends the columns of render `index` not yet in the union. */
|
|
62
|
+
function mergeColumns(union, columns, index, branchOnly) {
|
|
63
|
+
const known = new Set(union.map(c => c.Name.toLowerCase()));
|
|
64
|
+
for (const column of columns) {
|
|
65
|
+
if (known.has(column.Name.toLowerCase()))
|
|
66
|
+
continue;
|
|
67
|
+
known.add(column.Name.toLowerCase());
|
|
68
|
+
union.push(column);
|
|
69
|
+
if (index > 0)
|
|
70
|
+
branchOnly.push(`${column.Name} (render ${index})`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Notes the columns of the union so far that render `index` does not return (a column only the base branch returns). */
|
|
74
|
+
function noteMissingColumns(union, columns, index, branchOnly) {
|
|
75
|
+
const returned = new Set(columns.map(c => c.Name.toLowerCase()));
|
|
76
|
+
for (const column of union) {
|
|
77
|
+
if (!returned.has(column.Name.toLowerCase()))
|
|
78
|
+
branchOnly.push(`${column.Name} (not in render ${index})`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function duplicateNames(columns) {
|
|
82
|
+
const seen = new Set();
|
|
83
|
+
const repeated = new Set();
|
|
84
|
+
for (const column of columns) {
|
|
85
|
+
const key = column.Name.toLowerCase();
|
|
86
|
+
if (seen.has(key))
|
|
87
|
+
repeated.add(column.Name);
|
|
88
|
+
seen.add(key);
|
|
89
|
+
}
|
|
90
|
+
return [...repeated];
|
|
91
|
+
}
|
|
92
|
+
/** The base assignment, then one per `{% if %}` that parameter values can move to another branch. */
|
|
93
|
+
function renderAssignments(template) {
|
|
94
|
+
const set = template.BranchVariants().Value;
|
|
95
|
+
const toggles = set.Variants.filter(v => v.Toggle !== null && v.Satisfiable && v.Toggle.ToBranch !== null);
|
|
96
|
+
return [set.Base, ...toggles.slice(0, MAX_VARIANT_RENDERS).map(v => BranchVariantValues(set, v))];
|
|
97
|
+
}
|
|
98
|
+
/** Every parameter a render may be given: the template's, typed from the known rows where they say more. */
|
|
99
|
+
function renderDefinitions(parameters, known) {
|
|
100
|
+
const byName = new Map(known.map(k => [k.Name.toLowerCase(), k]));
|
|
101
|
+
const definitions = parameters.map(p => {
|
|
102
|
+
const row = byName.get(p.Name.toLowerCase());
|
|
103
|
+
return {
|
|
104
|
+
Name: p.Name,
|
|
105
|
+
Type: row?.Type ?? p.Type ?? 'string',
|
|
106
|
+
TypeKnown: row?.Type !== undefined || p.Type !== null,
|
|
107
|
+
IsRequired: p.IsRequired,
|
|
108
|
+
IsServerSet: row?.IsServerSet ?? false,
|
|
109
|
+
ValidationFilters: row?.ValidationFilters ?? null,
|
|
110
|
+
SampleValue: p.SampleValue ?? row?.SampleValue ?? null,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
return definitions;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Why a render of the query may not run, as the run would refuse it: the first render (the base,
|
|
117
|
+
* then each `{% if %}` toggled) that is not a single read query or calls a function a query may not
|
|
118
|
+
* call. `null` when every render passes; a render that fails for another reason is left to
|
|
119
|
+
* {@link DescribeQueryOutput}, which reports it.
|
|
120
|
+
*/
|
|
121
|
+
export function FindUnsafeRender(input, template, parameters) {
|
|
122
|
+
const definitions = renderDefinitions(parameters, input.KnownParameters);
|
|
123
|
+
const renders = template.Tokens.HasTemplate ? renderAssignments(template) : [null];
|
|
124
|
+
for (const values of renders) {
|
|
125
|
+
const rendered = renderVariant(input, definitions, values);
|
|
126
|
+
if (rendered.Unsafe)
|
|
127
|
+
return rendered.Error;
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* A failed render. It is unsafe when the safety stage found a write or a forbidden call; SQL it
|
|
133
|
+
* refused only because it could not read it (a WITH clause written for another platform, whose own
|
|
134
|
+
* variant is saved later) is left to the describe and to the run-time gate, which fails closed.
|
|
135
|
+
*/
|
|
136
|
+
function renderFailure(e) {
|
|
137
|
+
return { SQL: '', Error: e instanceof Error ? e.message : String(e), Unsafe: IsQuerySafetyError(e) && !e.Unreadable };
|
|
138
|
+
}
|
|
139
|
+
/** Plain SQL, as written, once it passes the safety stage every rendered statement passes. */
|
|
140
|
+
function plainVariant(input) {
|
|
141
|
+
try {
|
|
142
|
+
SafetyGate.AssertSafeToExecute(input.SQL, GetDialect(input.Platform), false);
|
|
143
|
+
return { SQL: input.SQL, Error: null, Unsafe: false };
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
return renderFailure(e);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/** One render's SQL for `values` (`null`: plain SQL, rendered as written), or why it failed. */
|
|
150
|
+
function renderVariant(input, definitions, values) {
|
|
151
|
+
if (values === null)
|
|
152
|
+
return plainVariant(input);
|
|
153
|
+
const callerValues = {};
|
|
154
|
+
const serverValues = {};
|
|
155
|
+
for (const definition of definitions) {
|
|
156
|
+
const value = renderValue(values[definition.Name], definition);
|
|
157
|
+
if (value === undefined)
|
|
158
|
+
continue;
|
|
159
|
+
(definition.IsServerSet ? serverValues : callerValues)[definition.Name] = value;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const result = RenderPipeline.Run(input.SQL, {
|
|
163
|
+
Platform: input.Platform,
|
|
164
|
+
QueryID: input.QueryID ?? undefined,
|
|
165
|
+
ContextUser: input.ContextUser,
|
|
166
|
+
Parameters: callerValues,
|
|
167
|
+
ServerParameters: serverValues,
|
|
168
|
+
QueryInfo: { SQL: input.SQL, UsesTemplate: true, Parameters: definitions },
|
|
169
|
+
UsesTemplate: true,
|
|
170
|
+
OriginalSQL: input.SQL,
|
|
171
|
+
Dependencies: input.CompositionDependencies && input.CompositionDependencies.length > 0 ? [...input.CompositionDependencies] : undefined,
|
|
172
|
+
});
|
|
173
|
+
return { SQL: result.FinalSQL, Error: null, Unsafe: false };
|
|
174
|
+
}
|
|
175
|
+
catch (e) {
|
|
176
|
+
return renderFailure(e);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The value a branch value gives a parameter in a render; `undefined` leaves it out. A compared
|
|
181
|
+
* literal that is not a value of the parameter's known type (text compared with a date) would fail
|
|
182
|
+
* the parameter's validation, so the type's sample stands in for it.
|
|
183
|
+
*/
|
|
184
|
+
function renderValue(branch, definition) {
|
|
185
|
+
if (!branch || branch.Kind === 'Absent')
|
|
186
|
+
return undefined;
|
|
187
|
+
if (branch.Kind === 'Literal') {
|
|
188
|
+
if (branch.Value === null)
|
|
189
|
+
return undefined;
|
|
190
|
+
const text = String(branch.Value);
|
|
191
|
+
if (!definition.TypeKnown || literalFitsType(text, definition.Type))
|
|
192
|
+
return text;
|
|
193
|
+
}
|
|
194
|
+
return definition.TypeKnown ? SampleValueFor(definition.Type, definition.SampleValue) : definition.SampleValue?.trim() || UNTYPED_SAMPLE;
|
|
195
|
+
}
|
|
196
|
+
/** Whether a compared literal, as text, is a value of `type`: a number, a date or a boolean; any text for the other types. */
|
|
197
|
+
function literalFitsType(text, type) {
|
|
198
|
+
switch (type) {
|
|
199
|
+
case 'number': return text.trim() !== '' && Number.isFinite(Number(text));
|
|
200
|
+
case 'date': return !isNaN(new Date(text).getTime());
|
|
201
|
+
case 'boolean': return text === 'true' || text === 'false';
|
|
202
|
+
default: return true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* The sample of a parameter whose type nothing establishes: a numeric string, valid wherever such
|
|
207
|
+
* a value can go (a string, a number in arithmetic or a comparison, a composed number argument).
|
|
208
|
+
*/
|
|
209
|
+
const UNTYPED_SAMPLE = '1';
|
|
210
|
+
/**
|
|
211
|
+
* A truthy sample value of `type`, as a render takes it: the row's sample when it fits the type,
|
|
212
|
+
* otherwise a fixed value (`Sample`, `1`, `2024-01-01`, `true`, `["1"]`). An array's fixed element is
|
|
213
|
+
* a numeric string, so a loop over it can feed a string hole or a number argument alike.
|
|
214
|
+
*/
|
|
215
|
+
export function SampleValueFor(type, sample) {
|
|
216
|
+
const given = sample?.trim() ? sample : null;
|
|
217
|
+
switch (type) {
|
|
218
|
+
case 'number': return given !== null && !isNaN(Number(given)) && Number(given) !== 0 ? given : '1';
|
|
219
|
+
case 'date': return given !== null && !isNaN(new Date(given).getTime()) ? given : '2024-01-01';
|
|
220
|
+
case 'boolean': return 'true';
|
|
221
|
+
case 'array': return given !== null ? NormalizeDefaultForType(given, 'array') : '["1"]';
|
|
222
|
+
default: return given ?? 'Sample';
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=describeFacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describeFacts.js","sourceRoot":"","sources":["../../../src/custom/query-extraction/describeFacts.ts"],"names":[],"mappings":"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"}
|