@cellaware/utils 8.2.2 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chatwms/cosmos.d.ts +24 -0
- package/dist/chatwms/cosmos.js +508 -0
- package/dist/chatwms/datagrid.d.ts +1 -1
- package/dist/chatwms/datagrid.js +40 -18
- package/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { DatagridCondition } from "./datagrid.js";
|
|
2
|
+
import { SqlCacheContext } from "./developer.js";
|
|
3
|
+
export interface CosmosVariable {
|
|
4
|
+
key: string;
|
|
5
|
+
value: any;
|
|
6
|
+
}
|
|
7
|
+
export declare function createCosmosVariables(userId: string): CosmosVariable[];
|
|
8
|
+
export declare function loadCosmosDeveloperCache(userId: string): SqlCacheContext;
|
|
9
|
+
export interface CosmosQuery {
|
|
10
|
+
table: string;
|
|
11
|
+
query: string;
|
|
12
|
+
}
|
|
13
|
+
export interface CosmosQueryContext {
|
|
14
|
+
customer?: string;
|
|
15
|
+
organization?: string;
|
|
16
|
+
warehouse?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Extracts the first word after the `FROM` and replaces it with the necessary contents based on the context.
|
|
20
|
+
*
|
|
21
|
+
* Returns the adjusted query and the extracted lowercase table name.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createCosmosQuery(query: string, variables: CosmosVariable[], context?: CosmosQueryContext): CosmosQuery;
|
|
24
|
+
export declare function executeCosmosQuery(cosmosQuery: CosmosQuery, parameters: DatagridCondition[], rowLimit?: number): Promise<any[]>;
|
|
@@ -0,0 +1,508 @@
|
|
|
1
|
+
import { getQueryMatches } from "../util.js";
|
|
2
|
+
import { chatwmsCosmosSelect } from "./azure/cosmos.js";
|
|
3
|
+
import { COSMOS_CONTEXT_NAME, chatwmsGetClientId } from "./client.js";
|
|
4
|
+
import { codifyCondition } from "./datagrid.js";
|
|
5
|
+
const COSMOS_SQL_ACTION_WORDS_REGEX = /\b(insert|update|delete|create|alter|drop|commit|rollback)\b/gmi;
|
|
6
|
+
const COSMOS_SQL_SELECT_REGEX = /\b(select)\b/gmi;
|
|
7
|
+
const COSMOS_SQL_FROM_REGEX = /\b(from)\b/gmi;
|
|
8
|
+
const COSMOS_SQL_WHERE_REGEX = /\b(where)\b/gmi;
|
|
9
|
+
const COSMOS_SQL_APPROVED_TABLES_REGEX = /\b(alert_executions|alert_subscriptions|alerts|client_configs|conversation_details|conversation_feedback|conversation_headers|conversation_metadata|conversation_removed_details|conversation_sampled_details|conversation_sampled_metadata|dashboard_usage|dashboard_widgets|dashboards|notifications|report_lines|report_usage|reports|user_roles)\b/gmi;
|
|
10
|
+
const _SUBQUERY_QUERY_PLACEHOLDER_UNWRAPPED = '{{query}}';
|
|
11
|
+
const SUBQUERY_QUERY_PLACEHOLDER = `(${_SUBQUERY_QUERY_PLACEHOLDER_UNWRAPPED})`;
|
|
12
|
+
const VARIABLE_COSMOS_USER_ID = '__USER_ID__';
|
|
13
|
+
const VARIABLE_COSMOS_CURRENT_DAY = '__CURRENT_DAY__';
|
|
14
|
+
const VARIABLE_COSMOS_CURRENT_MONTH = '__CURRENT_MONTH__';
|
|
15
|
+
const VARIABLE_COSMOS_CURRENT_YEAR = '__CURRENT_YEAR__';
|
|
16
|
+
const VARIABLE_COSMOS_CURRENT_DAY_NAME = '__CURRENT_DAY_NAME__';
|
|
17
|
+
const VARIABLE_COSMOS_CURRENT_DAY_FULL_NAME = '__CURRENT_DAY_FULL_NAME__';
|
|
18
|
+
const VARIABLE_COSMOS_CURRENT_MONTH_NAME = '__CURRENT_MONTH_NAME__';
|
|
19
|
+
const VARIABLE_COSMOS_CURRENT_MONTH_FULL_NAME = '__CURRENT_MONTH_FULL_NAME__';
|
|
20
|
+
const VARIABLE_COSMOS_TIMESTAMP_DAY = '__TIMESTAMP_DAY__';
|
|
21
|
+
const VARIABLE_COSMOS_TIMESTAMP_MONTH = '__TIMESTAMP_MONTH__';
|
|
22
|
+
const VARIABLE_COSMOS_TIMESTAMP_YEAR = '__TIMESTAMP_YEAR__';
|
|
23
|
+
const VARIABLE_COSMOS_TIMESTAMP_DAY_NAME = '__TIMESTAMP_DAY_NAME__';
|
|
24
|
+
const VARIABLE_COSMOS_TIMESTAMP_DAY_FULL_NAME = '__TIMESTAMP_DAY_FULL_NAME__';
|
|
25
|
+
const VARIABLE_COSMOS_TIMESTAMP_MONTH_NAME = '__TIMESTAMP_MONTH_NAME__';
|
|
26
|
+
const VARIABLE_COSMOS_TIMESTAMP_MONTH_FULL_NAME = '__TIMESTAMP_MONTH_FULL_NAME__';
|
|
27
|
+
const VARIABLE_COSMOS_LAST_14_DAYS_CLAUSE = '__LAST_14_DAYS_CLAUSE__';
|
|
28
|
+
const VARIABLE_COSMOS_LAST_30_DAYS_CLAUSE = '__LAST_30_DAYS_CLAUSE__';
|
|
29
|
+
const VARIABLE_COSMOS_LAST_90_DAYS_CLAUSE = '__LAST_90_DAYS_CLAUSE__';
|
|
30
|
+
const VARIABLE_COSMOS_LAST_180_DAYS_CLAUSE = '__LAST_180_DAYS_CLAUSE__';
|
|
31
|
+
const VARIABLE_COSMOS_LAST_365_DAYS_CLAUSE = '__LAST_365_DAYS_CLAUSE__';
|
|
32
|
+
const VARIABLE_COSMOS_CURRENT_DAY_CLAUSE = '__CURRENT_DAY_CLAUSE__';
|
|
33
|
+
const VARIABLE_COSMOS_CURRENT_MONTH_CLAUSE = '__CURRENT_MONTH_CLAUSE__';
|
|
34
|
+
const VARIABLE_COSMOS_CURRENT_YEAR_CLAUSE = '__CURRENT_YEAR_CLAUSE__';
|
|
35
|
+
const COSMOS_DATE_VARIABLES = [
|
|
36
|
+
// CURRENT:
|
|
37
|
+
{ key: VARIABLE_COSMOS_CURRENT_DAY, value: 'DateTimePart("day", GetCurrentDateTime())' },
|
|
38
|
+
{ key: VARIABLE_COSMOS_CURRENT_MONTH, value: 'DateTimePart("month", GetCurrentDateTime())' },
|
|
39
|
+
{ key: VARIABLE_COSMOS_CURRENT_YEAR, value: 'DateTimePart("year", GetCurrentDateTime())' },
|
|
40
|
+
{ key: VARIABLE_COSMOS_CURRENT_DAY_NAME, value: 'IIF(DateTimePart("weekday", GetCurrentDateTime()) = 0, "Sun", IIF(DateTimePart("weekday", GetCurrentDateTime()) = 1, "Mon", IIF(DateTimePart("weekday", GetCurrentDateTime()) = 2, "Tue", IIF(DateTimePart("weekday", GetCurrentDateTime()) = 3, "Wed", IIF(DateTimePart("weekday", GetCurrentDateTime()) = 4, "Thu", IIF(DateTimePart("weekday", GetCurrentDateTime()) = 5, "Fri", "Sat"))))))' },
|
|
41
|
+
{ key: VARIABLE_COSMOS_CURRENT_DAY_FULL_NAME, value: 'IIF(DateTimePart("weekday", GetCurrentDateTime()) = 0, "Sunday", IIF(DateTimePart("weekday", GetCurrentDateTime()) = 1, "Monday", IIF(DateTimePart("weekday", GetCurrentDateTime()) = 2, "Tuesday", IIF(DateTimePart("weekday", GetCurrentDateTime()) = 3, "Wednesday", IIF(DateTimePart("weekday", GetCurrentDateTime()) = 4, "Thursday", IIF(DateTimePart("weekday", GetCurrentDateTime()) = 5, "Friday", "Saturday"))))))' },
|
|
42
|
+
{ key: VARIABLE_COSMOS_CURRENT_MONTH_NAME, value: 'IIF(DateTimePart("month", GetCurrentDateTime()) = 1, "Jan", IIF(DateTimePart("month", GetCurrentDateTime()) = 2, "Feb", IIF(DateTimePart("month", GetCurrentDateTime()) = 3, "Mar", IIF(DateTimePart("month", GetCurrentDateTime()) = 4, "Apr", IIF(DateTimePart("month", GetCurrentDateTime()) = 5, "May", IIF(DateTimePart("month", GetCurrentDateTime()) = 6, "Jun", IIF(DateTimePart("month", GetCurrentDateTime()) = 7, "Jul", IIF(DateTimePart("month", GetCurrentDateTime()) = 8, "Aug", IIF(DateTimePart("month", GetCurrentDateTime()) = 9, "Sep", IIF(DateTimePart("month", GetCurrentDateTime()) = 10, "Oct", IIF(DateTimePart("month", GetCurrentDateTime()) = 11, "Nov", IIF(DateTimePart("month", GetCurrentDateTime()) = 12, "Dec", "N/A"))))))))))))' },
|
|
43
|
+
{ key: VARIABLE_COSMOS_CURRENT_MONTH_FULL_NAME, value: 'IIF(DateTimePart("month", GetCurrentDateTime()) = 1, "January", IIF(DateTimePart("month", GetCurrentDateTime()) = 2, "February", IIF(DateTimePart("month", GetCurrentDateTime()) = 3, "March", IIF(DateTimePart("month", GetCurrentDateTime()) = 4, "April", IIF(DateTimePart("month", GetCurrentDateTime()) = 5, "May", IIF(DateTimePart("month", GetCurrentDateTime()) = 6, "June", IIF(DateTimePart("month", GetCurrentDateTime()) = 7, "July", IIF(DateTimePart("month", GetCurrentDateTime()) = 8, "August", IIF(DateTimePart("month", GetCurrentDateTime()) = 9, "September", IIF(DateTimePart("month", GetCurrentDateTime()) = 10, "October", IIF(DateTimePart("month", GetCurrentDateTime()) = 11, "November", IIF(DateTimePart("month", GetCurrentDateTime()) = 12, "December", "N/A"))))))))))))' },
|
|
44
|
+
// TIMESTAMP:
|
|
45
|
+
{ key: VARIABLE_COSMOS_TIMESTAMP_DAY, value: 'DateTimePart("day", TimestampToDateTime(c._ts * 1000))' },
|
|
46
|
+
{ key: VARIABLE_COSMOS_TIMESTAMP_MONTH, value: 'DateTimePart("month", TimestampToDateTime(c._ts * 1000))' },
|
|
47
|
+
{ key: VARIABLE_COSMOS_TIMESTAMP_YEAR, value: 'DateTimePart("year", TimestampToDateTime(c._ts * 1000))' },
|
|
48
|
+
{ key: VARIABLE_COSMOS_TIMESTAMP_DAY_NAME, value: 'IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 0, "Sun", IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 1, "Mon", IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 2, "Tue", IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 3, "Wed", IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 4, "Thu", IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 5, "Fri", "Sat"))))))' },
|
|
49
|
+
{ key: VARIABLE_COSMOS_TIMESTAMP_DAY_FULL_NAME, value: 'IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 0, "Sunday", IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 1, "Monday", IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 2, "Tuesday", IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 3, "Wednesday", IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 4, "Thursday", IIF(DateTimePart("weekday", TimestampToDateTime(c._ts * 1000)) = 5, "Friday", "Saturday"))))))' },
|
|
50
|
+
{ key: VARIABLE_COSMOS_TIMESTAMP_MONTH_NAME, value: 'IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 1, "Jan", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 2, "Feb", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 3, "Mar", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 4, "Apr", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 5, "May", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 6, "Jun", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 7, "Jul", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 8, "Aug", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 9, "Sep", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 10, "Oct", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 11, "Nov", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 12, "Dec", "N/A"))))))))))))' },
|
|
51
|
+
{ key: VARIABLE_COSMOS_TIMESTAMP_MONTH_FULL_NAME, value: 'IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 1, "January", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 2, "February", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 3, "March", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 4, "April", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 5, "May", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 6, "June", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 7, "July", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 8, "August", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 9, "September", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 10, "October", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 11, "November", IIF(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = 12, "December", "N/A"))))))))))))' },
|
|
52
|
+
// CLAUSE:
|
|
53
|
+
{ key: VARIABLE_COSMOS_LAST_14_DAYS_CLAUSE, value: 'c._ts >= ((GetCurrentTimestamp() / 1000) - 14 * 24 * 60 * 60)' },
|
|
54
|
+
{ key: VARIABLE_COSMOS_LAST_30_DAYS_CLAUSE, value: 'c._ts >= ((GetCurrentTimestamp() / 1000) - 30 * 24 * 60 * 60)' },
|
|
55
|
+
{ key: VARIABLE_COSMOS_LAST_90_DAYS_CLAUSE, value: 'c._ts >= ((GetCurrentTimestamp() / 1000) - 90 * 24 * 60 * 60)' },
|
|
56
|
+
{ key: VARIABLE_COSMOS_LAST_180_DAYS_CLAUSE, value: 'c._ts >= ((GetCurrentTimestamp() / 1000) - 180 * 24 * 60 * 60)' },
|
|
57
|
+
{ key: VARIABLE_COSMOS_LAST_365_DAYS_CLAUSE, value: 'c._ts >= ((GetCurrentTimestamp() / 1000) - 365 * 24 * 60 * 60)' },
|
|
58
|
+
{ key: VARIABLE_COSMOS_CURRENT_DAY_CLAUSE, value: '(DateTimePart("day", TimestampToDateTime(c._ts * 1000)) = DateTimePart("day", GetCurrentDateTime()) AND DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = DateTimePart("month", GetCurrentDateTime()) AND DateTimePart("year", TimestampToDateTime(c._ts * 1000)) = DateTimePart("year", GetCurrentDateTime()))' },
|
|
59
|
+
{ key: VARIABLE_COSMOS_CURRENT_MONTH_CLAUSE, value: '(DateTimePart("month", TimestampToDateTime(c._ts * 1000)) = DateTimePart("month", GetCurrentDateTime()) AND DateTimePart("year", TimestampToDateTime(c._ts * 1000)) = DateTimePart("year", GetCurrentDateTime()))' },
|
|
60
|
+
{ key: VARIABLE_COSMOS_CURRENT_YEAR_CLAUSE, value: 'DateTimePart("year", TimestampToDateTime(c._ts * 1000)) = DateTimePart("year", GetCurrentDateTime())' }
|
|
61
|
+
];
|
|
62
|
+
const COSMOS_TABLES = [
|
|
63
|
+
{
|
|
64
|
+
table_name: 'alert_executions',
|
|
65
|
+
table_description: 'Alert Executions'
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
table_name: 'alert_subscriptions',
|
|
69
|
+
table_description: 'Alert Subscriptions'
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
table_name: 'alerts',
|
|
73
|
+
table_description: 'Alerts'
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
table_name: 'client_configs',
|
|
77
|
+
table_description: 'Client Configurations'
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
table_name: 'conversation_details',
|
|
81
|
+
table_description: 'Conversation Details'
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
table_name: 'conversation_feedback',
|
|
85
|
+
table_description: 'Conversation Feedback'
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
table_name: 'conversation_headers',
|
|
89
|
+
table_description: 'Conversation Headers'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
table_name: 'conversation_metadata',
|
|
93
|
+
table_description: 'Conversation Metadata'
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
table_name: 'conversation_removed_details',
|
|
97
|
+
table_description: 'Conversation Removed Details'
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
table_name: 'conversation_sampled_details',
|
|
101
|
+
table_description: 'Conversation Sampled Details'
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
table_name: 'conversation_sampled_metadata',
|
|
105
|
+
table_description: 'Conversation Sampled Metadata'
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
table_name: 'dashboard_usage',
|
|
109
|
+
table_description: 'Dashboard Usage'
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
table_name: 'dashboard_widgets',
|
|
113
|
+
table_description: 'Dashboard Widgets'
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
table_name: 'dashboards',
|
|
117
|
+
table_description: 'Dashboards'
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
table_name: 'notifications',
|
|
121
|
+
table_description: 'Notifications'
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
table_name: 'report_lines',
|
|
125
|
+
table_description: 'Report Lines'
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
table_name: 'report_usage',
|
|
129
|
+
table_description: 'Report Usage'
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
table_name: 'reports',
|
|
133
|
+
table_description: 'Reports'
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
table_name: 'user_roles',
|
|
137
|
+
table_description: 'User Roles'
|
|
138
|
+
}
|
|
139
|
+
];
|
|
140
|
+
const COSMOS_FUNCTIONS = initCosmosFunctions();
|
|
141
|
+
function initCosmosFunctions() {
|
|
142
|
+
const functions = [];
|
|
143
|
+
const initFn = (name, type, args, description) => {
|
|
144
|
+
return {
|
|
145
|
+
name,
|
|
146
|
+
type,
|
|
147
|
+
args,
|
|
148
|
+
description
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
// https://learn.microsoft.com/en-us/cosmos-db/query/functions
|
|
152
|
+
// MATHEMATICAL FUNCTIONS:
|
|
153
|
+
functions.push(initFn('abs', 'math', ['value'], 'Returns the absolute value of a numeric expression.'));
|
|
154
|
+
functions.push(initFn('acos', 'math', ['value'], 'Returns the arccosine of a numeric value, in radians.'));
|
|
155
|
+
functions.push(initFn('asin', 'math', ['value'], 'Returns the arcsine of a numeric value, in radians.'));
|
|
156
|
+
functions.push(initFn('atan', 'math', ['value'], 'Returns the arctangent of a numeric value, in radians.'));
|
|
157
|
+
functions.push(initFn('atn2', 'math', ['y', 'x'], 'Returns the arctangent of y/x, in radians.'));
|
|
158
|
+
functions.push(initFn('ceiling', 'math', ['value'], 'Returns the smallest integer greater than or equal to the value.'));
|
|
159
|
+
functions.push(initFn('cos', 'math', ['radians'], 'Returns the cosine of an angle in radians.'));
|
|
160
|
+
functions.push(initFn('cot', 'math', ['radians'], 'Returns the cotangent of an angle in radians.'));
|
|
161
|
+
functions.push(initFn('degrees', 'math', ['radians'], 'Converts an angle from radians to degrees.'));
|
|
162
|
+
functions.push(initFn('exp', 'math', ['value'], 'Returns e raised to the given numeric value.'));
|
|
163
|
+
functions.push(initFn('floor', 'math', ['value'], 'Returns the largest integer less than or equal to the value.'));
|
|
164
|
+
functions.push(initFn('intadd', 'math', ['a', 'b'], 'Adds two integer values.'));
|
|
165
|
+
functions.push(initFn('intbitand', 'math', ['a', 'b'], 'Performs a bitwise AND on two integer values.'));
|
|
166
|
+
functions.push(initFn('intbitleftshift', 'math', ['value', 'shift'], 'Performs a bitwise left shift on an integer value.'));
|
|
167
|
+
functions.push(initFn('intbitnot', 'math', ['value'], 'Performs a bitwise NOT on an integer value.'));
|
|
168
|
+
functions.push(initFn('intbitor', 'math', ['a', 'b'], 'Performs a bitwise OR on two integer values.'));
|
|
169
|
+
functions.push(initFn('intbitrightshift', 'math', ['value', 'shift'], 'Performs a bitwise right shift on an integer value.'));
|
|
170
|
+
functions.push(initFn('intbitxor', 'math', ['a', 'b'], 'Performs a bitwise XOR on two integer values.'));
|
|
171
|
+
functions.push(initFn('intdiv', 'math', ['a', 'b'], 'Divides one integer by another and returns the integer result.'));
|
|
172
|
+
functions.push(initFn('intmod', 'math', ['a', 'b'], 'Returns the remainder from integer division.'));
|
|
173
|
+
functions.push(initFn('intmul', 'math', ['a', 'b'], 'Multiplies two integer values.'));
|
|
174
|
+
functions.push(initFn('intsub', 'math', ['a', 'b'], 'Subtracts one integer value from another.'));
|
|
175
|
+
functions.push(initFn('log', 'math', ['value'], 'Returns the natural logarithm of a numeric expression.'));
|
|
176
|
+
functions.push(initFn('log10', 'math', ['value'], 'Returns the base-10 logarithm of a numeric expression.'));
|
|
177
|
+
functions.push(initFn('numberbin', 'math', ['value', 'size'], 'Bins or rounds a number to a multiple of the given size.'));
|
|
178
|
+
functions.push(initFn('pi', 'math', [], 'Returns the constant value of π.'));
|
|
179
|
+
functions.push(initFn('power', 'math', ['value', 'exponent'], 'Returns a value raised to the specified power.'));
|
|
180
|
+
functions.push(initFn('radians', 'math', ['degrees'], 'Converts an angle from degrees to radians.'));
|
|
181
|
+
functions.push(initFn('rand', 'math', [], 'Returns a random float between 0 and 1.'));
|
|
182
|
+
functions.push(initFn('round', 'math', ['value'], 'Rounds a numeric value to the nearest integer.'));
|
|
183
|
+
functions.push(initFn('sign', 'math', ['value'], 'Returns -1, 0, or 1 depending on the sign of the value.'));
|
|
184
|
+
functions.push(initFn('sin', 'math', ['radians'], 'Returns the sine of an angle in radians.'));
|
|
185
|
+
functions.push(initFn('sqrt', 'math', ['value'], 'Returns the square root of a numeric value.'));
|
|
186
|
+
functions.push(initFn('square', 'math', ['value'], 'Returns a numeric value squared.'));
|
|
187
|
+
functions.push(initFn('tan', 'math', ['radians'], 'Returns the tangent of an angle in radians.'));
|
|
188
|
+
functions.push(initFn('trunc', 'math', ['value'], 'Truncates a numeric value to its integer part.'));
|
|
189
|
+
// ARRAY FUNCTIONS:
|
|
190
|
+
functions.push(initFn('array_concat', 'array', ['...arrays'], 'Concatenates two or more arrays into a single array.'));
|
|
191
|
+
functions.push(initFn('array_contains_all', 'array', ['array', 'values'], 'Returns true if the array contains all specified values.'));
|
|
192
|
+
functions.push(initFn('array_contains_any', 'array', ['array', 'values'], 'Returns true if the array contains any of the specified values.'));
|
|
193
|
+
functions.push(initFn('array_contains', 'array', ['array', 'value'], 'Returns true if the array contains the specified value.'));
|
|
194
|
+
functions.push(initFn('array_length', 'array', ['array'], 'Returns the number of elements in an array.'));
|
|
195
|
+
functions.push(initFn('array_slice', 'array', ['array', 'start', 'length'], 'Returns a subset of an array.'));
|
|
196
|
+
functions.push(initFn('choose', 'array', ['index', '...values'], 'Returns the expression at the specified index from a list.'));
|
|
197
|
+
functions.push(initFn('objecttoarray', 'array', ['object'], 'Converts a JSON object’s fields to an array of key/value pairs.'));
|
|
198
|
+
functions.push(initFn('setintersect', 'array', ['array1', 'array2'], 'Returns the set of values present in both arrays (no duplicates).'));
|
|
199
|
+
functions.push(initFn('setunion', 'array', ['array1', 'array2'], 'Returns the union of values from two arrays (no duplicates).'));
|
|
200
|
+
// AGGREGATION FUNCTIONS:
|
|
201
|
+
functions.push(initFn('avg', 'aggregate', ['expression'], 'Returns the average of the values in an expression.'));
|
|
202
|
+
functions.push(initFn('count', 'aggregate', ['expression'], 'Returns the number of values in an expression.'));
|
|
203
|
+
functions.push(initFn('max', 'aggregate', ['expression'], 'Returns the maximum value of an expression.'));
|
|
204
|
+
functions.push(initFn('min', 'aggregate', ['expression'], 'Returns the minimum value of an expression.'));
|
|
205
|
+
functions.push(initFn('sum', 'aggregate', ['expression'], 'Returns the sum of the values in an expression.'));
|
|
206
|
+
// STRING FUNCTIONS:
|
|
207
|
+
functions.push(initFn('concat', 'string', ['...strings'], 'Concatenates multiple string expressions.'));
|
|
208
|
+
functions.push(initFn('contains', 'string', ['source', 'value', 'caseSensitive?'], 'Returns true if the first string contains the second.'));
|
|
209
|
+
functions.push(initFn('endswith', 'string', ['source', 'suffix', 'caseSensitive?'], 'Returns true if a string ends with the specified suffix.'));
|
|
210
|
+
functions.push(initFn('index_of', 'string', ['source', 'search', 'start?'], 'Returns the index of the first occurrence of a substring.'));
|
|
211
|
+
functions.push(initFn('left', 'string', ['source', 'length'], 'Returns the leftmost characters of a string.'));
|
|
212
|
+
functions.push(initFn('length', 'string', ['source'], 'Returns the number of characters in a string.'));
|
|
213
|
+
functions.push(initFn('lower', 'string', ['source'], 'Converts a string to lowercase.'));
|
|
214
|
+
functions.push(initFn('ltrim', 'string', ['source', 'trimChars?'], 'Trims leading whitespace or specified characters from a string.'));
|
|
215
|
+
functions.push(initFn('regexmatch', 'string', ['source', 'pattern'], 'Returns true if the string matches the given regular expression.'));
|
|
216
|
+
functions.push(initFn('replace', 'string', ['source', 'search', 'replace'], 'Replaces all occurrences of a substring with another string.'));
|
|
217
|
+
functions.push(initFn('replicate', 'string', ['source', 'count'], 'Repeats a string a given number of times.'));
|
|
218
|
+
functions.push(initFn('reverse', 'string', ['source'], 'Returns the characters of a string in reverse order.'));
|
|
219
|
+
functions.push(initFn('right', 'string', ['source', 'length'], 'Returns the rightmost characters of a string.'));
|
|
220
|
+
functions.push(initFn('rtrim', 'string', ['source', 'trimChars?'], 'Trims trailing whitespace or specified characters from a string.'));
|
|
221
|
+
functions.push(initFn('startswith', 'string', ['source', 'prefix', 'caseSensitive?'], 'Returns true if the string starts with the specified prefix.'));
|
|
222
|
+
functions.push(initFn('stringequals', 'string', ['a', 'b', 'caseSensitive?'], 'Returns true if two strings are equal.'));
|
|
223
|
+
functions.push(initFn('stringjoin', 'string', ['separator', 'array'], 'Joins an array of strings with a separator.'));
|
|
224
|
+
functions.push(initFn('stringsplit', 'string', ['source', 'delimiter'], 'Splits a string into an array using the delimiter.'));
|
|
225
|
+
functions.push(initFn('stringtoarray', 'string', ['source'], 'Converts a string to an array.'));
|
|
226
|
+
functions.push(initFn('stringtoboolean', 'string', ['source'], 'Converts a string to a boolean.'));
|
|
227
|
+
functions.push(initFn('substring', 'string', ['source', 'start', 'length?'], 'Returns a substring starting at the given position.'));
|
|
228
|
+
functions.push(initFn('tostring', 'string', ['value'], 'Converts a value to its string representation.'));
|
|
229
|
+
functions.push(initFn('trim', 'string', ['source', 'trimChars?'], 'Trims leading and trailing whitespace or characters.'));
|
|
230
|
+
functions.push(initFn('upper', 'string', ['source'], 'Converts a string to uppercase.'));
|
|
231
|
+
// DATE AND TIME FUNCTIONS:
|
|
232
|
+
functions.push(initFn('datetimeadd', 'date', ['dateTime', 'part', 'amount'], 'Adds an interval to a date and time string.'));
|
|
233
|
+
functions.push(initFn('datetimebin', 'date', ['dateTime', 'part', 'size'], 'Bins or rounds a date and time to the given granularity.'));
|
|
234
|
+
functions.push(initFn('datetimediff', 'date', ['part', 'start', 'end'], 'Returns the difference between two dates for the specified part.'));
|
|
235
|
+
functions.push(initFn('datetimefromparts', 'date', ['year', 'month', 'day', 'hour', 'minute', 'second', 'fraction?'], 'Builds a date and time string from individual parts.'));
|
|
236
|
+
functions.push(initFn('datetimepart', 'date', ['part', 'dateTime'], 'Returns the value of the specified date/time part.'));
|
|
237
|
+
functions.push(initFn('datetimetoticks', 'date', ['dateTime'], 'Converts a date/time string to ticks.'));
|
|
238
|
+
functions.push(initFn('datetimetotimestamp', 'date', ['dateTime'], 'Converts a date/time string to a Unix timestamp (ms).'));
|
|
239
|
+
functions.push(initFn('getcurrentdatetime', 'date', [], 'Returns the current UTC date and time as an ISO 8601 string.'));
|
|
240
|
+
functions.push(initFn('getcurrentdatetimestatic', 'date', [], 'Returns a fixed UTC date and time for all items in the query.'));
|
|
241
|
+
functions.push(initFn('getcurrentticks', 'date', [], 'Returns the current UTC time in ticks.'));
|
|
242
|
+
functions.push(initFn('getcurrentticksstatic', 'date', [], 'Returns a static tick value for all items in the same partition.'));
|
|
243
|
+
functions.push(initFn('getcurrenttimestamp', 'date', [], 'Returns the current Unix timestamp in milliseconds.'));
|
|
244
|
+
functions.push(initFn('getcurrenttimestampstatic', 'date', [], 'Returns a static Unix timestamp for all items in the same partition.'));
|
|
245
|
+
functions.push(initFn('tickstodatetime', 'date', ['ticks'], 'Converts ticks to a date and time string.'));
|
|
246
|
+
functions.push(initFn('timestamptodatetime', 'date', ['timestamp'], 'Converts a Unix timestamp to a date and time string.'));
|
|
247
|
+
// ITEM FUNCTIONS:
|
|
248
|
+
functions.push(initFn('documentid', 'item', ['item'], 'Returns the unique document ID for an item.'));
|
|
249
|
+
// FULL TEXT SEARCH FUNCTIONS:
|
|
250
|
+
functions.push(initFn('fulltextcontains', 'fulltext', ['path', 'keyword'], 'Returns true if the keyword is contained in the specified property path.'));
|
|
251
|
+
functions.push(initFn('fulltextcontainsall', 'fulltext', ['path', '...keywords'], 'Returns true if all keywords are contained in the property path.'));
|
|
252
|
+
functions.push(initFn('fulltextcontainsany', 'fulltext', ['path', '...keywords'], 'Returns true if any keywords are contained in the property path.'));
|
|
253
|
+
functions.push(initFn('fulltextscore', 'fulltext', ['path', 'keyword'], 'Returns a relevance score that can be used with ORDER BY RANK.'));
|
|
254
|
+
functions.push(initFn('rrf', 'fulltext', ['...scores'], 'Combines multiple scores into a fused ranking value.'));
|
|
255
|
+
// CONDITIONAL FUNCTIONS:
|
|
256
|
+
functions.push(initFn('iif', 'conditional', ['condition', 'trueValue', 'falseValue'], 'Returns one of two values depending on a boolean expression.'));
|
|
257
|
+
// TYPE CHECKING / CONVERSION FUNCTIONS:
|
|
258
|
+
functions.push(initFn('is_array', 'type', ['expression'], 'Returns true if the expression is an array.'));
|
|
259
|
+
functions.push(initFn('is_bool', 'type', ['expression'], 'Returns true if the expression is a boolean.'));
|
|
260
|
+
functions.push(initFn('is_defined', 'type', ['expression'], 'Returns true if the property has a defined value.'));
|
|
261
|
+
functions.push(initFn('is_finite_number', 'type', ['expression'], 'Returns true if the expression is a finite number.'));
|
|
262
|
+
functions.push(initFn('is_integer', 'type', ['expression'], 'Returns true if the expression is a 64-bit signed integer.'));
|
|
263
|
+
functions.push(initFn('is_null', 'type', ['expression'], 'Returns true if the expression is null.'));
|
|
264
|
+
functions.push(initFn('is_number', 'type', ['expression'], 'Returns true if the expression is a number.'));
|
|
265
|
+
functions.push(initFn('is_object', 'type', ['expression'], 'Returns true if the expression is a JSON object.'));
|
|
266
|
+
functions.push(initFn('is_primitive', 'type', ['expression'], 'Returns true if the expression is a primitive value.'));
|
|
267
|
+
functions.push(initFn('is_string', 'type', ['expression'], 'Returns true if the expression is a string.'));
|
|
268
|
+
functions.push(initFn('stringtonull', 'type', ['source'], 'Converts a string expression to null.'));
|
|
269
|
+
functions.push(initFn('stringtonumber', 'type', ['source'], 'Converts a string expression to a number.'));
|
|
270
|
+
functions.push(initFn('stringtoobject', 'type', ['source'], 'Converts a string expression to an object.'));
|
|
271
|
+
// SPATIAL / VECTOR FUNCTIONS:
|
|
272
|
+
functions.push(initFn('st_area', 'spatial', ['geometry'], 'Returns the area of a GeoJSON Polygon or MultiPolygon.'));
|
|
273
|
+
functions.push(initFn('st_distance', 'spatial', ['geometry1', 'geometry2'], 'Returns the distance between two GeoJSON geometries.'));
|
|
274
|
+
functions.push(initFn('st_intersects', 'spatial', ['geometry1', 'geometry2'], 'Returns true if two GeoJSON geometries intersect.'));
|
|
275
|
+
functions.push(initFn('st_isvalid', 'spatial', ['geometry'], 'Returns true if the GeoJSON geometry is valid.'));
|
|
276
|
+
functions.push(initFn('st_isvaliddetailed', 'spatial', ['geometry'], 'Returns validity information and reason for an invalid geometry.'));
|
|
277
|
+
functions.push(initFn('st_within', 'spatial', ['geometry1', 'geometry2'], 'Returns true if the first GeoJSON geometry is within the second.'));
|
|
278
|
+
functions.push(initFn('vectordistance', 'spatial', ['vector1', 'vector2'], 'Returns a similarity or distance score between two vectors.'));
|
|
279
|
+
return functions;
|
|
280
|
+
}
|
|
281
|
+
export function createCosmosVariables(userId) {
|
|
282
|
+
return [
|
|
283
|
+
{ key: VARIABLE_COSMOS_USER_ID, value: `'${userId}'` },
|
|
284
|
+
...COSMOS_DATE_VARIABLES
|
|
285
|
+
];
|
|
286
|
+
}
|
|
287
|
+
export function loadCosmosDeveloperCache(userId) {
|
|
288
|
+
return {
|
|
289
|
+
contextName: COSMOS_CONTEXT_NAME,
|
|
290
|
+
variables: createCosmosVariables(userId),
|
|
291
|
+
tables: COSMOS_TABLES,
|
|
292
|
+
columns: [],
|
|
293
|
+
functions: COSMOS_FUNCTIONS,
|
|
294
|
+
tableMappings: [],
|
|
295
|
+
columnMappings: []
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* The `subquery` **must** contain `({{query}})` placeholder inside of it.
|
|
300
|
+
*
|
|
301
|
+
* The transformed query will be injected in the place of the **first** `{{query}}`.
|
|
302
|
+
*/
|
|
303
|
+
function injectSubquery(query, subquery) {
|
|
304
|
+
// NOTE: we do not need to worry about semicolons or common table expressions -- these are not allowed in Cosmos.
|
|
305
|
+
if (!subquery.includes(SUBQUERY_QUERY_PLACEHOLDER)) {
|
|
306
|
+
throw new Error(`Subquery must contain '${SUBQUERY_QUERY_PLACEHOLDER}' placeholder.`);
|
|
307
|
+
}
|
|
308
|
+
let queryMut = query.trim();
|
|
309
|
+
queryMut = subquery.replace(_SUBQUERY_QUERY_PLACEHOLDER_UNWRAPPED, queryMut);
|
|
310
|
+
return queryMut;
|
|
311
|
+
}
|
|
312
|
+
function injectParameters(query, parameters) {
|
|
313
|
+
// NOTE: we do not need to worry about semicolons or common table expressions -- these are not allowed in Cosmos.
|
|
314
|
+
let queryMut = query.trim();
|
|
315
|
+
if (parameters.length > 0) {
|
|
316
|
+
let whereBuf = '1 = 1';
|
|
317
|
+
for (const parameter of parameters) {
|
|
318
|
+
whereBuf += ` AND ${codifyCondition(parameter)}`;
|
|
319
|
+
}
|
|
320
|
+
const subquery = `SELECT * FROM ${SUBQUERY_QUERY_PLACEHOLDER} param_sq WHERE ${whereBuf}`;
|
|
321
|
+
queryMut = injectSubquery(queryMut, subquery);
|
|
322
|
+
}
|
|
323
|
+
return queryMut;
|
|
324
|
+
}
|
|
325
|
+
/** Substitutes instances of Cosmos variables with their respective values. */
|
|
326
|
+
function injectCosmosVariables(query, variables) {
|
|
327
|
+
let queryMut = query;
|
|
328
|
+
if (!!variables) {
|
|
329
|
+
for (const variable of variables) {
|
|
330
|
+
queryMut = queryMut.replaceAll(variable.key, variable.value);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return queryMut;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Extracts the first word after the `FROM` and replaces it with the necessary contents based on the context.
|
|
337
|
+
*
|
|
338
|
+
* Returns the adjusted query and the extracted lowercase table name.
|
|
339
|
+
*/
|
|
340
|
+
export function createCosmosQuery(query, variables, context) {
|
|
341
|
+
// Validate query:
|
|
342
|
+
{
|
|
343
|
+
// Query must not contain any action words.
|
|
344
|
+
const actionMatches = getQueryMatches(query, COSMOS_SQL_ACTION_WORDS_REGEX);
|
|
345
|
+
if (actionMatches.length > 0) {
|
|
346
|
+
throw new Error(`Cannot execute action query`);
|
|
347
|
+
}
|
|
348
|
+
// Query must not have more than 1 `SELECT`, `FROM`, or `WHERE`.
|
|
349
|
+
const selectMatches = getQueryMatches(query, COSMOS_SQL_SELECT_REGEX);
|
|
350
|
+
if (selectMatches.length > 1) {
|
|
351
|
+
throw new Error(`Multiple queries or subqueries are not allowed`);
|
|
352
|
+
}
|
|
353
|
+
const fromMatches = getQueryMatches(query, COSMOS_SQL_FROM_REGEX);
|
|
354
|
+
if (fromMatches.length > 1) {
|
|
355
|
+
throw new Error(`Multiple queries or subqueries are not allowed`);
|
|
356
|
+
}
|
|
357
|
+
const whereMatches = getQueryMatches(query, COSMOS_SQL_WHERE_REGEX);
|
|
358
|
+
if (whereMatches.length > 1) {
|
|
359
|
+
throw new Error(`Multiple queries or subqueries are not allowed`);
|
|
360
|
+
}
|
|
361
|
+
const tableMatches = getQueryMatches(query, COSMOS_SQL_APPROVED_TABLES_REGEX);
|
|
362
|
+
if (tableMatches.length === 0) {
|
|
363
|
+
throw new Error(`Must only query approved tables`);
|
|
364
|
+
}
|
|
365
|
+
else if (tableMatches.length > 1) {
|
|
366
|
+
throw new Error(`Multiple queries or subqueries are not allowed`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
let table = '';
|
|
370
|
+
let hasAs = !!query.match(/FROM\s+([A-Za-z0-9_]+)\s+(AS)/gmi);
|
|
371
|
+
let queryMut = query.replace(/FROM\s+([A-Za-z0-9_]+)/gmi, (match, matchedTable) => {
|
|
372
|
+
table = matchedTable;
|
|
373
|
+
// NOTE: we will never have `organization` or `warehouse` without `customer`.
|
|
374
|
+
if (!!context && !!context.customer) {
|
|
375
|
+
let whereClause = '';
|
|
376
|
+
if (!!context.warehouse) {
|
|
377
|
+
if (table === 'user_roles') {
|
|
378
|
+
whereClause = `WHERE c.customer = '${context.customer}' AND c.warehouse = '${context.warehouse}'`;
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
whereClause = `WHERE c.clientId = '${chatwmsGetClientId(context.customer, context.warehouse)}'`;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
else if (!!context.organization) {
|
|
385
|
+
if (table === 'user_roles') {
|
|
386
|
+
whereClause = `WHERE c.customer = '${context.customer}' AND c.warehouse LIKE '${context.organization}_%'`;
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
whereClause = `WHERE c.clientId LIKE '${context.customer}_${context.organization}_%'`;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
if (table === 'user_roles') {
|
|
394
|
+
whereClause = `WHERE c.customer = '${context.customer}'`;
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
whereClause = `WHERE c.clientId LIKE '${context.customer}_%'`;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return `FROM (SELECT * FROM c ${whereClause})${hasAs ? '' : ' AS c'}`;
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
return 'FROM c';
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
if (table === '') {
|
|
407
|
+
throw new Error(`No table detected in COSMOS query: ${query}`);
|
|
408
|
+
}
|
|
409
|
+
queryMut = injectCosmosVariables(queryMut, variables);
|
|
410
|
+
return { table: table.toLowerCase(), query: queryMut };
|
|
411
|
+
}
|
|
412
|
+
async function getUserDetails() {
|
|
413
|
+
let map = new Map();
|
|
414
|
+
(await chatwmsCosmosSelect('user_settings', 'SELECT DISTINCT c.userId, c.userDetails FROM c ORDER BY c.userId')).map(user => {
|
|
415
|
+
map.set(user.userId, user.userDetails);
|
|
416
|
+
});
|
|
417
|
+
return map;
|
|
418
|
+
}
|
|
419
|
+
async function getClientDescriptions() {
|
|
420
|
+
let map = new Map();
|
|
421
|
+
(await chatwmsCosmosSelect('client_configs', 'SELECT DISTINCT c.clientId, c.description FROM c ORDER BY c.clientId')).map(client => {
|
|
422
|
+
map.set(client.clientId, client.description);
|
|
423
|
+
});
|
|
424
|
+
return map;
|
|
425
|
+
}
|
|
426
|
+
async function getDashboardTitles() {
|
|
427
|
+
let map = new Map();
|
|
428
|
+
(await chatwmsCosmosSelect('dashboards', 'SELECT DISTINCT c.dashboardId, c.dashboardTitle FROM c ORDER BY c.dashboardId')).map(dashboard => {
|
|
429
|
+
map.set(dashboard.dashboardId, dashboard.dashboardTitle);
|
|
430
|
+
});
|
|
431
|
+
return map;
|
|
432
|
+
}
|
|
433
|
+
async function getReportTitles() {
|
|
434
|
+
let map = new Map();
|
|
435
|
+
(await chatwmsCosmosSelect('reports', 'SELECT DISTINCT c.reportId, c.reportTitle FROM c ORDER BY c.reportId')).map(report => {
|
|
436
|
+
map.set(report.reportId, report.reportTitle);
|
|
437
|
+
});
|
|
438
|
+
return map;
|
|
439
|
+
}
|
|
440
|
+
async function getAlertTitles() {
|
|
441
|
+
let map = new Map();
|
|
442
|
+
(await chatwmsCosmosSelect('alerts', 'SELECT DISTINCT c.alertId, c.alertTitle FROM c ORDER BY c.alertId')).map(alert => {
|
|
443
|
+
map.set(alert.alertId, alert.alertTitle);
|
|
444
|
+
});
|
|
445
|
+
return map;
|
|
446
|
+
}
|
|
447
|
+
export async function executeCosmosQuery(cosmosQuery, parameters, rowLimit) {
|
|
448
|
+
let queryMut = injectParameters(cosmosQuery.query, parameters);
|
|
449
|
+
if (!!rowLimit) {
|
|
450
|
+
// NOTE: we do not need to worry about semicolons or common table expressions -- these are not allowed in Cosmos.
|
|
451
|
+
queryMut = `SELECT TOP ${rowLimit} * FROM (${queryMut}) limit_sq`;
|
|
452
|
+
}
|
|
453
|
+
let res = await chatwmsCosmosSelect(cosmosQuery.table, queryMut);
|
|
454
|
+
if (res.length === 0) {
|
|
455
|
+
return [];
|
|
456
|
+
}
|
|
457
|
+
// Depending on the table/columns queried, we are going to inject a few things.
|
|
458
|
+
{
|
|
459
|
+
const firstRow = res[0];
|
|
460
|
+
let userDetails = undefined;
|
|
461
|
+
let clientDescriptions = undefined;
|
|
462
|
+
let dashboardTitles = undefined;
|
|
463
|
+
let reportTitles = undefined;
|
|
464
|
+
let alertTitles = undefined;
|
|
465
|
+
if ('userId' in firstRow && !('userDetails' in firstRow)) {
|
|
466
|
+
userDetails = await getUserDetails();
|
|
467
|
+
}
|
|
468
|
+
if ('clientId' in firstRow && !('description' in firstRow)) {
|
|
469
|
+
clientDescriptions = await getClientDescriptions();
|
|
470
|
+
}
|
|
471
|
+
if (cosmosQuery.table === 'dashboard_widgets' || cosmosQuery.table === 'dashboard_usage') {
|
|
472
|
+
if ('dashboardId' in firstRow && !('dashboardTitle' in firstRow)) {
|
|
473
|
+
dashboardTitles = await getDashboardTitles();
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
else if (cosmosQuery.table === 'report_lines' || cosmosQuery.table === 'report_usage') {
|
|
477
|
+
if ('reportId' in firstRow && !('reportTitle' in firstRow)) {
|
|
478
|
+
reportTitles = await getReportTitles();
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
else if (cosmosQuery.table === 'alert_subscriptions' || cosmosQuery.table === 'alert_executions') {
|
|
482
|
+
if ('alertId' in firstRow && !('alertTitle' in firstRow)) {
|
|
483
|
+
alertTitles = await getAlertTitles();
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
let rowIdx = 1;
|
|
487
|
+
res.forEach(row => {
|
|
488
|
+
// Include row number no matter what.
|
|
489
|
+
row['rowNumber'] = rowIdx++;
|
|
490
|
+
if (!!userDetails) {
|
|
491
|
+
row['userDetails'] = userDetails.get(row['userId']) ?? '';
|
|
492
|
+
}
|
|
493
|
+
if (!!clientDescriptions) {
|
|
494
|
+
row['description'] = clientDescriptions.get(row['clientId']) ?? '';
|
|
495
|
+
}
|
|
496
|
+
if (!!dashboardTitles) {
|
|
497
|
+
row['dashboardTitle'] = dashboardTitles.get(row['dashboardId']) ?? '';
|
|
498
|
+
}
|
|
499
|
+
else if (!!reportTitles) {
|
|
500
|
+
row['reportTitle'] = reportTitles.get(row['reportId']) ?? '';
|
|
501
|
+
}
|
|
502
|
+
else if (!!alertTitles) {
|
|
503
|
+
row['alertTitle'] = alertTitles.get(row['alertId']) ?? '';
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
return res;
|
|
508
|
+
}
|
|
@@ -115,7 +115,7 @@ export interface DatagridCondition {
|
|
|
115
115
|
value2?: string;
|
|
116
116
|
}
|
|
117
117
|
export declare function initDatagridCondition(): DatagridCondition;
|
|
118
|
-
export declare function summarizeCondition(condition: DatagridCondition, localeMessageFn: (language: string, messageId: string) => Promise<string
|
|
118
|
+
export declare function summarizeCondition(condition: DatagridCondition, localeMessageFn: (language: string, messageId: string) => Promise<string>, markdown?: boolean): Promise<string>;
|
|
119
119
|
export declare function codifyCondition(condition: DatagridCondition): string;
|
|
120
120
|
/**
|
|
121
121
|
* Equivalent of `parseNumeric` in front end
|
package/dist/chatwms/datagrid.js
CHANGED
|
@@ -265,26 +265,48 @@ export function initDatagridCondition() {
|
|
|
265
265
|
value: ''
|
|
266
266
|
};
|
|
267
267
|
}
|
|
268
|
-
export async function summarizeCondition(condition, localeMessageFn) {
|
|
268
|
+
export async function summarizeCondition(condition, localeMessageFn, markdown) {
|
|
269
269
|
let ruleStr = '';
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
270
|
+
if (!!markdown) {
|
|
271
|
+
switch (condition.rule) {
|
|
272
|
+
case ConditionalFormatRule.BETWEEN:
|
|
273
|
+
ruleStr = `**${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)}** ${condition.value} **${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, 'conditional-format-rule-and')}** ${condition.value2}`;
|
|
274
|
+
break;
|
|
275
|
+
case ConditionalFormatRule.BLANK:
|
|
276
|
+
case ConditionalFormatRule.NOT_BLANK:
|
|
277
|
+
ruleStr = `**${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)}**`;
|
|
278
|
+
break;
|
|
279
|
+
default:
|
|
280
|
+
if (condition.dataType === 'text') {
|
|
281
|
+
ruleStr = `**${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)}** '${condition.value}'`;
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
ruleStr = `**${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)}** ${condition.value}`;
|
|
285
|
+
}
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
return `\`${condition.columnName}\` ${ruleStr}`;
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
switch (condition.rule) {
|
|
292
|
+
case ConditionalFormatRule.BETWEEN:
|
|
293
|
+
ruleStr = `${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)} ${condition.value} ${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, 'conditional-format-rule-and')} ${condition.value2}`;
|
|
294
|
+
break;
|
|
295
|
+
case ConditionalFormatRule.BLANK:
|
|
296
|
+
case ConditionalFormatRule.NOT_BLANK:
|
|
297
|
+
ruleStr = `${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)}`;
|
|
298
|
+
break;
|
|
299
|
+
default:
|
|
300
|
+
if (condition.dataType === 'text') {
|
|
301
|
+
ruleStr = `${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)} '${condition.value}'`;
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
ruleStr = `${await localeMessageFn(CHATWMS_DEFAULT_LANGUAGE, condition.rule)} ${condition.value}`;
|
|
305
|
+
}
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
return `${condition.columnName} ${ruleStr}`;
|
|
286
309
|
}
|
|
287
|
-
return `${condition.columnName} ${ruleStr}`;
|
|
288
310
|
}
|
|
289
311
|
export function codifyCondition(condition) {
|
|
290
312
|
// NOTE: since we check for action/unsafe SQL with every query, we do not need to check for SQL injection here.
|