@deephaven-enterprise/query-utils 2026.1.38 → 2026.1.39

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.
@@ -0,0 +1,19 @@
1
+ import type { EditableQueryInfo, PlainEditableQueryInfo } from '@deephaven-enterprise/jsapi-types';
2
+ import type DraftQuery from './DraftQuery';
3
+ import type { ScriptDraftQuery } from './DraftQuery';
4
+ declare const FIELDS: {
5
+ readonly SCRIPT_LANGUAGE: "scriptLanguage";
6
+ readonly SCRIPT_PATH: "scriptPath";
7
+ readonly SCRIPT_CODE: "scriptCode";
8
+ };
9
+ type QueryContentFields = Pick<EditableQueryInfo, typeof FIELDS.SCRIPT_LANGUAGE | typeof FIELDS.SCRIPT_PATH | typeof FIELDS.SCRIPT_CODE>;
10
+ /**
11
+ * Check if the content fields in the given queries have different values
12
+ * @param queryA Query A
13
+ * @param queryB Query B
14
+ * @returns True, if the content fields don't match
15
+ */
16
+ export declare function isContentChanged(queryA: QueryContentFields, queryB: QueryContentFields): boolean;
17
+ export declare function getPlainEditableQueryInfo(query: EditableQueryInfo | PlainEditableQueryInfo): PlainEditableQueryInfo;
18
+ export declare function isScriptDraftQuery(query: DraftQuery | ScriptDraftQuery): query is ScriptDraftQuery;
19
+ export {};
@@ -0,0 +1,53 @@
1
+ const FIELDS = {
2
+ SCRIPT_LANGUAGE: 'scriptLanguage',
3
+ SCRIPT_PATH: 'scriptPath',
4
+ SCRIPT_CODE: 'scriptCode',
5
+ };
6
+ /**
7
+ * Check if the content fields in the given queries have different values
8
+ * @param queryA Query A
9
+ * @param queryB Query B
10
+ * @returns True, if the content fields don't match
11
+ */
12
+ export function isContentChanged(queryA, queryB) {
13
+ return Object.values(FIELDS).some(field => queryA[field] !== queryB[field]);
14
+ }
15
+ export function getPlainEditableQueryInfo(query) {
16
+ // Can't use a spread operator because the EditableQueryInfo JS API object uses property accessors
17
+ return {
18
+ adminGroups: [...query.adminGroups],
19
+ dataMemoryRatio: query.dataMemoryRatio,
20
+ dbServerName: query.dbServerName,
21
+ enabled: query.enabled,
22
+ enableGcLogs: query.enableGcLogs,
23
+ envVars: query.envVars,
24
+ extraClasspaths: query.extraClasspaths,
25
+ heapSize: query.heapSize,
26
+ additionalMemory: query.additionalMemory,
27
+ jvmArgs: query.jvmArgs,
28
+ jvmProfile: query.jvmProfile,
29
+ name: query.name,
30
+ owner: query.owner,
31
+ restartUsers: query.restartUsers,
32
+ scheduling: [...query.scheduling],
33
+ scriptLanguage: query.scriptLanguage,
34
+ scriptPath: query.scriptPath,
35
+ timeout: query.timeout,
36
+ type: query.type,
37
+ typeSpecificFields: query.typeSpecificFields == null ? null : Object.assign({}, query.typeSpecificFields),
38
+ viewerGroups: [...query.viewerGroups],
39
+ replicaCount: query.replicaCount,
40
+ spareCount: query.spareCount,
41
+ assignmentPolicy: query.assignmentPolicy,
42
+ assignmentPolicyParams: query.assignmentPolicyParams,
43
+ scriptCode: query.scriptCode,
44
+ serial: query.serial,
45
+ genericWorkerControl: query.genericWorkerControl,
46
+ kubernetesControl: query.kubernetesControl,
47
+ pythonControl: query.pythonControl,
48
+ workerKind: query.workerKind,
49
+ };
50
+ }
51
+ export function isScriptDraftQuery(query) {
52
+ return query.scriptLanguage != null;
53
+ }
@@ -0,0 +1,5 @@
1
+ import type { EnterpriseClient, QueryInfo } from '@deephaven-enterprise/jsapi-types';
2
+ export declare function findQueryByGrpcUrl(client: EnterpriseClient, grpcUrl: string): QueryInfo | undefined;
3
+ export declare function findQueryByName(client: EnterpriseClient, queryName: string): QueryInfo | undefined;
4
+ export declare function findQueryBySerial(client: EnterpriseClient, querySerial: string): QueryInfo | undefined;
5
+ export declare function getQueryNameForSerial(client: EnterpriseClient, querySerial: string): string | null;
@@ -0,0 +1,15 @@
1
+ export function findQueryByGrpcUrl(client, grpcUrl) {
2
+ return client
3
+ .getKnownConfigs()
4
+ .find(({ designated }) => (designated === null || designated === void 0 ? void 0 : designated.grpcUrl) === grpcUrl);
5
+ }
6
+ export function findQueryByName(client, queryName) {
7
+ return client.getKnownConfigs().find(({ name }) => name === queryName);
8
+ }
9
+ export function findQueryBySerial(client, querySerial) {
10
+ return client.getKnownConfigs().find(({ serial }) => serial === querySerial);
11
+ }
12
+ export function getQueryNameForSerial(client, querySerial) {
13
+ const query = findQueryBySerial(client, querySerial);
14
+ return query ? query.name : null;
15
+ }
@@ -0,0 +1,41 @@
1
+ import type { EnterpriseUser, QueryConfigurationType, QueryInfo, QuerySelectionPermissions } from '@deephaven-enterprise/jsapi-types';
2
+ import DraftQuery from './DraftQuery';
3
+ export declare const RESTART_USERS: Readonly<{
4
+ readonly RESTARTUSERS_ADMIN: 1;
5
+ readonly RESTARTUSERS_ADMINANDVIEWERS: 2;
6
+ readonly RESTARTUSERS_VIEWERSWHENDOWN: 4;
7
+ }>;
8
+ export declare const TYPE_SPECIFIC_FIELD_PARTITION_FORMULA = "PartitionFormula";
9
+ /**
10
+ * Check if the user can view permissions for the query
11
+ * @param user User object to check if can view permissions for the query
12
+ * @param draftQuery The draft query object to check against
13
+ * @returns True if the user can view permissions for the query, false otherwise
14
+ */
15
+ export declare function canViewPermissions(user: EnterpriseUser, draftQuery: DraftQuery | null): boolean;
16
+ /**
17
+ * Get the query configuration types that are displayable and the user is allowed to create
18
+ * @param queryConfigurationTypes Query configuration types to filter
19
+ * @param userGroups Groups the user is in
20
+ * @param isSuperUser Whether the user is a super user
21
+ * @returns Query configuration types that are displayable and the user is allowed to create
22
+ */
23
+ export declare function getDisplayableQueryTypes(queryConfigurationTypes: QueryConfigurationType[], userGroups: string[], isSuperUser?: boolean): QueryConfigurationType[];
24
+ /**
25
+ * Get the user permissions for selected queries.
26
+ *
27
+ * Based on com.illumon.iris.controller.utils.PersistentQueryConfigTableUtils.SelectedQueryStates#SelectedQueryStates
28
+ *
29
+ * @param user The user to check permissions for
30
+ * @param selectedQueries The queries to check permissions for
31
+ * @returns The query permissions for the user for the selected queries
32
+ */
33
+ export declare function getQuerySelectionPermissions(user: EnterpriseUser, selectedQueries: QueryInfo[]): QuerySelectionPermissions;
34
+ /**
35
+ * Check if the user is allowed to create a query of this type
36
+ * @param queryConfigurationType Type of query configuration
37
+ * @param userGroups Groups the user is in
38
+ * @param isSuperUser Whether the user is a super user
39
+ * @returns True if the user is allowed to create a query of this type, false otherwise
40
+ */
41
+ export declare function isAllowedQueryConfigurationType(queryConfigurationType: QueryConfigurationType | undefined, userGroups: string[], isSuperUser?: boolean): boolean;
@@ -0,0 +1,148 @@
1
+ import DraftQuery from './DraftQuery';
2
+ import { QueryScheduler } from './QueryScheduler';
3
+ import { checkAllReplicas, isRunningForRestart, isStoppedForPermissions, } from './QueryStateUtils';
4
+ import { getQuerySchedulerType } from './QueryUtils';
5
+ export const RESTART_USERS = Object.freeze({
6
+ RESTARTUSERS_ADMIN: 1,
7
+ RESTARTUSERS_ADMINANDVIEWERS: 2,
8
+ RESTARTUSERS_VIEWERSWHENDOWN: 4,
9
+ });
10
+ export const TYPE_SPECIFIC_FIELD_PARTITION_FORMULA = 'PartitionFormula';
11
+ /**
12
+ * Check if the user can view permissions for the query
13
+ * @param user User object to check if can view permissions for the query
14
+ * @param draftQuery The draft query object to check against
15
+ * @returns True if the user can view permissions for the query, false otherwise
16
+ */
17
+ export function canViewPermissions(user, draftQuery) {
18
+ if (draftQuery == null) {
19
+ return false;
20
+ }
21
+ // If they own the query or are creating a new one, permissions tab is available only if they have the share permission
22
+ if (draftQuery.serial === DraftQuery.NO_SERIAL ||
23
+ draftQuery.owner === user.operateAs) {
24
+ return user.permissions.canShareQueries;
25
+ }
26
+ // If it's shared with them and they're an admin, show the permissions tab
27
+ if (draftQuery.adminGroups.some(group => user.groups.includes(group))) {
28
+ return true;
29
+ }
30
+ // Otherwise, only show it if they can view the shared users
31
+ return user.permissions.canViewQuerySharedUsers;
32
+ }
33
+ /**
34
+ * Get the query configuration types that are displayable and the user is allowed to create
35
+ * @param queryConfigurationTypes Query configuration types to filter
36
+ * @param userGroups Groups the user is in
37
+ * @param isSuperUser Whether the user is a super user
38
+ * @returns Query configuration types that are displayable and the user is allowed to create
39
+ */
40
+ export function getDisplayableQueryTypes(queryConfigurationTypes, userGroups, isSuperUser = false) {
41
+ return queryConfigurationTypes.filter(queryConfigurationType => queryConfigurationType.isDisplayable &&
42
+ isAllowedQueryConfigurationType(queryConfigurationType, userGroups, isSuperUser));
43
+ }
44
+ /**
45
+ * Get the user permissions for selected queries.
46
+ *
47
+ * Based on com.illumon.iris.controller.utils.PersistentQueryConfigTableUtils.SelectedQueryStates#SelectedQueryStates
48
+ *
49
+ * @param user The user to check permissions for
50
+ * @param selectedQueries The queries to check permissions for
51
+ * @returns The query permissions for the user for the selected queries
52
+ */
53
+ export function getQuerySelectionPermissions(user, selectedQueries) {
54
+ const permissions = {
55
+ allAdmin: true,
56
+ allOwner: true,
57
+ allRestartable: true,
58
+ allStoppable: true,
59
+ allStopped: true,
60
+ allDisabled: true,
61
+ allEnabled: true,
62
+ allTemporary: true,
63
+ allImportMerge: true,
64
+ readOnlyUser: user.permissions.isQueryViewOnly,
65
+ };
66
+ // If there are no queries selected, then don't assume allTemporary
67
+ if (selectedQueries.length === 0) {
68
+ permissions.allTemporary = false;
69
+ }
70
+ const { isQueryManager } = user.permissions;
71
+ selectedQueries.forEach(query => {
72
+ const isOwner = query.owner === user.operateAs;
73
+ const isAdmin = user.permissions.isSuperUser ||
74
+ user.groups.includes(query.owner) ||
75
+ query.adminGroups.some(group => user.groups.includes(group));
76
+ const isViewer = query.viewerGroups.some(group => user.groups.includes(group));
77
+ const isVisibleToUser = isOwner || isAdmin || isViewer;
78
+ if (!isOwner) {
79
+ permissions.allOwner = false;
80
+ }
81
+ if (!isAdmin) {
82
+ permissions.allAdmin = false;
83
+ }
84
+ if (permissions.allTemporary &&
85
+ getQuerySchedulerType(query.scheduling) !== QueryScheduler.TYPES.TEMPORARY) {
86
+ permissions.allTemporary = false;
87
+ }
88
+ // Check if the query can be restarted based on the restartUsers setting
89
+ switch (query.restartUsers) {
90
+ case RESTART_USERS.RESTARTUSERS_ADMINANDVIEWERS:
91
+ permissions.allRestartable =
92
+ permissions.allRestartable && (isAdmin || isViewer || isQueryManager);
93
+ break;
94
+ case RESTART_USERS.RESTARTUSERS_VIEWERSWHENDOWN:
95
+ if (!isAdmin && !isQueryManager) {
96
+ const isRunning = checkAllReplicas(query, isRunningForRestart);
97
+ permissions.allRestartable =
98
+ permissions.allRestartable && !isRunning && isVisibleToUser;
99
+ }
100
+ break;
101
+ case RESTART_USERS.RESTARTUSERS_ADMIN:
102
+ default:
103
+ permissions.allRestartable =
104
+ permissions.allRestartable && (isAdmin || isQueryManager);
105
+ }
106
+ permissions.allStoppable =
107
+ permissions.allStoppable && (isAdmin || isQueryManager);
108
+ const isStopped = checkAllReplicas(query, isStoppedForPermissions);
109
+ if (!isStopped) {
110
+ permissions.allStopped = false;
111
+ }
112
+ if (query.enabled) {
113
+ permissions.allDisabled = false;
114
+ }
115
+ else {
116
+ permissions.allEnabled = false;
117
+ }
118
+ const { typeSpecificFields } = query;
119
+ if (typeSpecificFields != null) {
120
+ const hasPartitionFormula = Object.hasOwn(typeSpecificFields, TYPE_SPECIFIC_FIELD_PARTITION_FORMULA);
121
+ if (!hasPartitionFormula) {
122
+ permissions.allImportMerge = false;
123
+ }
124
+ }
125
+ else {
126
+ permissions.allImportMerge = false;
127
+ }
128
+ });
129
+ return permissions;
130
+ }
131
+ /**
132
+ * Check if the user is allowed to create a query of this type
133
+ * @param queryConfigurationType Type of query configuration
134
+ * @param userGroups Groups the user is in
135
+ * @param isSuperUser Whether the user is a super user
136
+ * @returns True if the user is allowed to create a query of this type, false otherwise
137
+ */
138
+ export function isAllowedQueryConfigurationType(queryConfigurationType, userGroups, isSuperUser = false) {
139
+ if (queryConfigurationType == null) {
140
+ return false;
141
+ }
142
+ if (isSuperUser) {
143
+ return true;
144
+ }
145
+ const { allowedGroups } = queryConfigurationType;
146
+ return (allowedGroups.length === 0 ||
147
+ allowedGroups.some(group => userGroups.includes(group)));
148
+ }
@@ -1,4 +1,4 @@
1
- import { CalendarDateTime } from '@internationalized/date';
1
+ import { type CalendarDateTime } from '@internationalized/date';
2
2
  /**
3
3
  * QueryScheduler is the client side equivalent of the server side class IrisScheduler.
4
4
  *
@@ -0,0 +1,57 @@
1
+ import type { dh } from '@deephaven/jsapi-types';
2
+ import type { QueryInfo } from '@deephaven-enterprise/jsapi-types';
3
+ import type DraftQuery from './DraftQuery';
4
+ export type QueryInfoMap = Map<string, QueryInfo>;
5
+ export declare const NON_RUNNING_STATUSES: Set<string>;
6
+ /**
7
+ * Determines if the given draft query is a batch query
8
+ * @param type the type of the draft query to check
9
+ * @returns true if the draft query is a batch query, false otherwise
10
+ */
11
+ export declare function isBatchQueryType(type: string | null | undefined): boolean;
12
+ export declare function isEnableable(queryInfoMap: QueryInfoMap, serial: string): boolean;
13
+ export declare function isDisableable(queryInfoMap: QueryInfoMap, serial: string): boolean;
14
+ export declare function isRestartable(queryInfoMap: QueryInfoMap | undefined, serial: string): boolean;
15
+ export declare function isStartable(queryInfoMap: QueryInfoMap | undefined, serial: string): boolean;
16
+ export declare function isStoppable(queryInfoMap: QueryInfoMap | undefined, serial: string): boolean;
17
+ export declare function isRunning(query: QueryInfo): boolean;
18
+ export declare function isWebClient(query: QueryInfo): boolean;
19
+ /**
20
+ * Check if the specified query can be restarted in it's current state.
21
+ * @param status the status of the query replica
22
+ */
23
+ export declare function isRestartableForEdit(status: unknown): boolean;
24
+ export declare function isRestartableForEditByRow(table?: dh.Table, row?: dh.Row): boolean;
25
+ /**
26
+ * Check if the query has a pending update to be applied. That is, that the currently
27
+ * running version of the query is not the latest saved configuration of the query.
28
+ *
29
+ * @param status the status field of the query replica
30
+ * @param configVersion the version of the query configuration
31
+ * @param runningVersion the currently running version of the query replica
32
+ * @returns true if an update is pending, false otherwise
33
+ */
34
+ export declare function isQueryUpdatePending(status: unknown, configVersion: unknown, runningVersion?: unknown): boolean;
35
+ export declare function isUpdatePendingForRow(table?: dh.Table, row?: dh.Row): boolean;
36
+ /**
37
+ * Check if this query is allowed to be saved without a restart.
38
+ * Queries are allowed to be saved without restart as long as:
39
+ * - The Owner has not changed
40
+ * - The Admin Groups have not been removed from
41
+ * - The query type has not changed
42
+ * - The scheduler and scheduler properties have not changed
43
+ * - The query is not a Temporary query
44
+ *
45
+ * @param draft the draft query to compare
46
+ * @param queryInfo the original query to compare to
47
+ */
48
+ export declare function isNoRestartAllowed(draft?: DraftQuery | null, queryInfo?: Partial<QueryInfo> | null): boolean;
49
+ /**
50
+ * Checks if the query is running or executing, which means it can be restarted.
51
+ *
52
+ * @param queryStatus The status of the query to check
53
+ * @returns true if the query is running or executing, false otherwise
54
+ */
55
+ export declare function isRunningForRestart(queryStatus: string): boolean;
56
+ export declare function isStoppedForPermissions(queryStatus: string): boolean;
57
+ export declare function checkAllReplicas(query: QueryInfo, statusFunction: (status: string) => boolean): boolean;
@@ -0,0 +1,187 @@
1
+ import { QueryColumns } from './QueryColumns';
2
+ import { QueryScheduler } from './QueryScheduler';
3
+ import { QueryStatus } from './QueryStatus';
4
+ import { QueryType } from './QueryType';
5
+ import { WEB_CLIENT_DATA_CORE_CONFIG_TYPE } from './QueryUtils';
6
+ export const NON_RUNNING_STATUSES = new Set([
7
+ QueryStatus.uninitialized,
8
+ QueryStatus.stopped,
9
+ QueryStatus.error,
10
+ QueryStatus.failed,
11
+ QueryStatus.disconnected,
12
+ QueryStatus.completed,
13
+ QueryStatus.none,
14
+ ]);
15
+ /**
16
+ * Determines if the given draft query is a batch query
17
+ * @param type the type of the draft query to check
18
+ * @returns true if the draft query is a batch query, false otherwise
19
+ */
20
+ export function isBatchQueryType(type) {
21
+ return (type === QueryType.RUN_AND_DONE || type === QueryType.RUN_AND_DONE_IMPORT);
22
+ }
23
+ export function isEnableable(queryInfoMap, serial) {
24
+ var _a, _b;
25
+ return (queryInfoMap.has(serial) && !((_b = (_a = queryInfoMap.get(serial)) === null || _a === void 0 ? void 0 : _a.enabled) !== null && _b !== void 0 ? _b : false));
26
+ }
27
+ export function isDisableable(queryInfoMap, serial) {
28
+ var _a;
29
+ if (!queryInfoMap.has(serial)) {
30
+ return false;
31
+ }
32
+ const queryInfo = queryInfoMap.get(serial);
33
+ if (!queryInfo) {
34
+ return false;
35
+ }
36
+ return (queryInfo.enabled &&
37
+ // Can't disable temporary queries
38
+ !((_a = queryInfo.scheduling) === null || _a === void 0 ? void 0 : _a.includes(QueryScheduler.TOKENS.SCHEDULER_TYPE +
39
+ QueryScheduler.TOKENS.DELIMITER +
40
+ QueryScheduler.TYPES.TEMPORARY)));
41
+ }
42
+ export function isRestartable(queryInfoMap, serial) {
43
+ const query = queryInfoMap === null || queryInfoMap === void 0 ? void 0 : queryInfoMap.get(serial);
44
+ if (query == null)
45
+ return false;
46
+ return (query.enabled === true &&
47
+ query.type !== QueryType.INTERACTIVE_CONSOLE &&
48
+ query.type !== QueryType.SCHEMA_API);
49
+ }
50
+ export function isStartable(queryInfoMap, serial) {
51
+ var _a, _b;
52
+ const query = queryInfoMap === null || queryInfoMap === void 0 ? void 0 : queryInfoMap.get(serial);
53
+ return (isRestartable(queryInfoMap, serial) &&
54
+ query != null &&
55
+ NON_RUNNING_STATUSES.has((_b = (_a = query === null || query === void 0 ? void 0 : query.designated) === null || _a === void 0 ? void 0 : _a.status) !== null && _b !== void 0 ? _b : QueryStatus.none));
56
+ }
57
+ export function isStoppable(queryInfoMap, serial) {
58
+ var _a, _b;
59
+ const query = queryInfoMap === null || queryInfoMap === void 0 ? void 0 : queryInfoMap.get(serial);
60
+ if (query == null)
61
+ return false;
62
+ return (query.enabled === true &&
63
+ ((_a = query.designated) === null || _a === void 0 ? void 0 : _a.status) !== QueryStatus.stopped &&
64
+ ((_b = query.designated) === null || _b === void 0 ? void 0 : _b.status) !== QueryStatus.stopping);
65
+ }
66
+ export function isRunning(query) {
67
+ var _a;
68
+ return ((_a = query.designated) === null || _a === void 0 ? void 0 : _a.status) === QueryStatus.running;
69
+ }
70
+ export function isWebClient(query) {
71
+ return query.type === WEB_CLIENT_DATA_CORE_CONFIG_TYPE;
72
+ }
73
+ /**
74
+ * Check if the specified query can be restarted in it's current state.
75
+ * @param status the status of the query replica
76
+ */
77
+ export function isRestartableForEdit(status) {
78
+ return (status === QueryStatus.running ||
79
+ status === QueryStatus.initializing ||
80
+ status === QueryStatus.executing);
81
+ }
82
+ export function isRestartableForEditByRow(table, row) {
83
+ if (table == null || row == null) {
84
+ return false;
85
+ }
86
+ const status = row.get(table.findColumn(QueryColumns.STATUS.name));
87
+ return isRestartableForEdit(status);
88
+ }
89
+ /**
90
+ * Check if the query has a pending update to be applied. That is, that the currently
91
+ * running version of the query is not the latest saved configuration of the query.
92
+ *
93
+ * @param status the status field of the query replica
94
+ * @param configVersion the version of the query configuration
95
+ * @param runningVersion the currently running version of the query replica
96
+ * @returns true if an update is pending, false otherwise
97
+ */
98
+ export function isQueryUpdatePending(status, configVersion, runningVersion) {
99
+ if (runningVersion == null || configVersion == null) {
100
+ return false;
101
+ }
102
+ return isRestartableForEdit(status) && configVersion !== runningVersion;
103
+ }
104
+ export function isUpdatePendingForRow(table, row) {
105
+ var _a, _b;
106
+ if (table == null || row == null) {
107
+ return false;
108
+ }
109
+ const status = row.get(table.findColumn(QueryColumns.STATUS.name));
110
+ const currentVersion = (_a = row
111
+ .get(table.findColumn(QueryColumns.CURRENTLY_RUNNING_VERSION.name))) === null || _a === void 0 ? void 0 : _a.valueOf();
112
+ const pendingVersion = (_b = row
113
+ .get(table.findColumn(QueryColumns.VERSION.name))) === null || _b === void 0 ? void 0 : _b.valueOf();
114
+ return isQueryUpdatePending(status, pendingVersion, currentVersion);
115
+ }
116
+ /**
117
+ * Check if this query is allowed to be saved without a restart.
118
+ * Queries are allowed to be saved without restart as long as:
119
+ * - The Owner has not changed
120
+ * - The Admin Groups have not been removed from
121
+ * - The query type has not changed
122
+ * - The scheduler and scheduler properties have not changed
123
+ * - The query is not a Temporary query
124
+ *
125
+ * @param draft the draft query to compare
126
+ * @param queryInfo the original query to compare to
127
+ */
128
+ export function isNoRestartAllowed(draft, queryInfo) {
129
+ var _a, _b;
130
+ if (!draft ||
131
+ !queryInfo ||
132
+ !draft.isModified ||
133
+ !isRestartableForEdit((_a = queryInfo === null || queryInfo === void 0 ? void 0 : queryInfo.designated) === null || _a === void 0 ? void 0 : _a.status)) {
134
+ return false;
135
+ }
136
+ const origSchedulerParams = queryInfo.scheduling;
137
+ const draftSchedulerParams = draft.scheduler.toStringArray();
138
+ if (origSchedulerParams == null ||
139
+ draftSchedulerParams == null ||
140
+ origSchedulerParams.length !== draftSchedulerParams.length) {
141
+ return false;
142
+ }
143
+ const newParams = new Set(draftSchedulerParams);
144
+ if (!origSchedulerParams.every(param => newParams.has(param))) {
145
+ return false;
146
+ }
147
+ if (draft.owner !== queryInfo.owner) {
148
+ return false;
149
+ }
150
+ if (draft.type !== queryInfo.type) {
151
+ return false;
152
+ }
153
+ if (draft.type === QueryScheduler.TYPES.TEMPORARY) {
154
+ return false;
155
+ }
156
+ const newAdmins = new Set(draft.adminGroups);
157
+ if (!((_b = queryInfo.adminGroups) !== null && _b !== void 0 ? _b : []).every(group => newAdmins.has(group))) {
158
+ return false;
159
+ }
160
+ return true;
161
+ }
162
+ /**
163
+ * Checks if the query is running or executing, which means it can be restarted.
164
+ *
165
+ * @param queryStatus The status of the query to check
166
+ * @returns true if the query is running or executing, false otherwise
167
+ */
168
+ export function isRunningForRestart(queryStatus) {
169
+ return (queryStatus === QueryStatus.running || queryStatus === QueryStatus.executing);
170
+ }
171
+ export function isStoppedForPermissions(queryStatus) {
172
+ return (queryStatus === QueryStatus.uninitialized ||
173
+ queryStatus === QueryStatus.stopped ||
174
+ queryStatus === QueryStatus.error ||
175
+ queryStatus === QueryStatus.failed ||
176
+ queryStatus === QueryStatus.disconnected ||
177
+ queryStatus === QueryStatus.completed ||
178
+ queryStatus === QueryStatus.none);
179
+ }
180
+ export function checkAllReplicas(query, statusFunction) {
181
+ var _a, _b;
182
+ const replicasAndSpares = [...query.replicas, ...query.spares];
183
+ if (replicasAndSpares.length === 0) {
184
+ return statusFunction((_b = (_a = query.designated) === null || _a === void 0 ? void 0 : _a.status) !== null && _b !== void 0 ? _b : QueryStatus.none);
185
+ }
186
+ return replicasAndSpares.every(replica => { var _a; return statusFunction((_a = replica.status) !== null && _a !== void 0 ? _a : QueryStatus.none); });
187
+ }
@@ -1,11 +1,11 @@
1
1
  import type { dh } from '@deephaven/jsapi-types';
2
- import type { UriVariableDescriptor } from '@deephaven/jsapi-bootstrap';
3
- import type { EnterpriseClient, EnterpriseDhType, QueryInfo, QueryVariableDescriptor, ReplicaStatus, UserInfo } from '@deephaven-enterprise/jsapi-types';
2
+ import type { EnterpriseClient, EnterpriseDhType, QueryConfigurationType, QueryInfo, QueryVariableDescriptor, ReplicaStatus, UserInfo } from '@deephaven-enterprise/jsapi-types';
4
3
  import { type Brand } from '@deephaven/utils';
5
4
  import DraftQuery, { type DraftQueryConstructorObject } from './DraftQuery';
6
5
  import type { CorePlusManager } from './CorePlusManager';
7
6
  export type ConsoleType = 'groovy' | 'python';
8
7
  export type QuerySerial = Brand<'QuerySerial', string>;
8
+ export type UriVariableDescriptor = string;
9
9
  export declare const DEFAULT_TEMPORARY_QUERY_AUTO_DELETE_TIMEOUT_MS: 600000;
10
10
  export declare const DEFAULT_TEMPORARY_QUERY_TIMEOUT_MS: 60000;
11
11
  export declare const INTERACTIVE_CONSOLE_TEMPORARY_QUEUE_NAME: "InteractiveConsoleTemporaryQueue";
@@ -96,6 +96,20 @@ export declare function getQueryObjectDefinitionByName(query: QueryInfo, name: s
96
96
  * @returns Resolves to the ReplicaStatus
97
97
  */
98
98
  export declare function getWorkerForSlot(query: QueryInfo, slot?: number | null): ReplicaStatus | undefined;
99
+ /**
100
+ * Parses only the scheduling type out of a QueryInfo's scheduling array.
101
+ * Logic is duplicated from QueryScheduler.parseBaseScheduler()
102
+ * @param schedulingArray Array containing scheduling data received from the server
103
+ * @returns The scheduler type, or undefined if not found
104
+ */
105
+ export declare function getQuerySchedulerType(schedulingArray: readonly string[]): string | undefined;
106
+ /**
107
+ * Check if the specified query configuration type supports community.
108
+ * @param queryConfigurationTypes The map of query configuration types to check against.
109
+ * @param type The type of query configuration to check.
110
+ * @returns True if the specified query configuration type supports community, false otherwise.
111
+ */
112
+ export declare function hasCommunitySupport(queryConfigurationTypes: ReadonlyMap<string, QueryConfigurationType>, type: string): boolean;
99
113
  /**
100
114
  * Indicates that a table should be fetched from the WebClientTableFactoryService rather than the query scope.
101
115
  *
@@ -169,6 +169,30 @@ export function getWorkerForSlot(query, slot) {
169
169
  }
170
170
  return query.replicas[slot];
171
171
  }
172
+ /**
173
+ * Parses only the scheduling type out of a QueryInfo's scheduling array.
174
+ * Logic is duplicated from QueryScheduler.parseBaseScheduler()
175
+ * @param schedulingArray Array containing scheduling data received from the server
176
+ * @returns The scheduler type, or undefined if not found
177
+ */
178
+ export function getQuerySchedulerType(schedulingArray) {
179
+ const schedulerType = schedulingArray.find(s => s.startsWith(QueryScheduler.TOKENS.SCHEDULER_TYPE));
180
+ if (schedulerType == null)
181
+ return undefined;
182
+ const splitString = schedulerType.split(QueryScheduler.TOKENS.DELIMITER);
183
+ QueryScheduler.validateSplitLength(schedulerType, splitString, 2);
184
+ return splitString[1];
185
+ }
186
+ /**
187
+ * Check if the specified query configuration type supports community.
188
+ * @param queryConfigurationTypes The map of query configuration types to check against.
189
+ * @param type The type of query configuration to check.
190
+ * @returns True if the specified query configuration type supports community, false otherwise.
191
+ */
192
+ export function hasCommunitySupport(queryConfigurationTypes, type) {
193
+ var _a, _b;
194
+ return (_b = (_a = queryConfigurationTypes.get(type)) === null || _a === void 0 ? void 0 : _a.supportsCommunity) !== null && _b !== void 0 ? _b : false;
195
+ }
172
196
  /**
173
197
  * Indicates that a table should be fetched from the WebClientTableFactoryService rather than the query scope.
174
198
  *
package/dist/index.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  export * from './CorePlusManager';
2
2
  export * from './DraftQuery';
3
+ export * from './EditableQueryInfoUtils';
4
+ export * from './QueryFinders';
5
+ export * from './QueryPermissions';
6
+ export * from './QueryStateUtils';
3
7
  export * from './QueryColumns';
4
8
  export * from './QueryDisplayType';
5
9
  export * from './QueryScheduler';
package/dist/index.js CHANGED
@@ -1,5 +1,9 @@
1
1
  export * from './CorePlusManager';
2
2
  export * from './DraftQuery';
3
+ export * from './EditableQueryInfoUtils';
4
+ export * from './QueryFinders';
5
+ export * from './QueryPermissions';
6
+ export * from './QueryStateUtils';
3
7
  export * from './QueryColumns';
4
8
  export * from './QueryDisplayType';
5
9
  export * from './QueryScheduler';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deephaven-enterprise/query-utils",
3
- "version": "2026.1.38",
3
+ "version": "2026.1.39",
4
4
  "description": "Deephaven Enterprise Query Utils",
5
5
  "author": "Deephaven Data Labs LLC",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -21,7 +21,7 @@
21
21
  "@deephaven-enterprise/jsapi-types": "file:../jsapi-types",
22
22
  "@deephaven/log": "^0.97.0",
23
23
  "@deephaven/utils": "^0.97.0",
24
- "@internationalized/date": "^3.5.5",
24
+ "@internationalized/date": "^3.12.2",
25
25
  "nanoid": "^5.1.6"
26
26
  },
27
27
  "publishConfig": {