@sonisoft/now-sdk-ext-core 2.4.0 → 2.5.1
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/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/sn/aggregate/AggregateModels.d.ts +89 -0
- package/dist/sn/aggregate/AggregateModels.js +5 -0
- package/dist/sn/aggregate/AggregateModels.js.map +1 -0
- package/dist/sn/aggregate/AggregateQuery.d.ts +50 -0
- package/dist/sn/aggregate/AggregateQuery.js +144 -0
- package/dist/sn/aggregate/AggregateQuery.js.map +1 -0
- package/dist/sn/batch/QueryBatchModels.d.ts +93 -0
- package/dist/sn/batch/QueryBatchModels.js +5 -0
- package/dist/sn/batch/QueryBatchModels.js.map +1 -0
- package/dist/sn/batch/QueryBatchOperations.d.ts +41 -0
- package/dist/sn/batch/QueryBatchOperations.js +195 -0
- package/dist/sn/batch/QueryBatchOperations.js.map +1 -0
- package/dist/sn/cmdb/CMDBModels.d.ts +141 -0
- package/dist/sn/cmdb/CMDBModels.js +5 -0
- package/dist/sn/cmdb/CMDBModels.js.map +1 -0
- package/dist/sn/cmdb/CMDBRelationships.d.ts +60 -0
- package/dist/sn/cmdb/CMDBRelationships.js +286 -0
- package/dist/sn/cmdb/CMDBRelationships.js.map +1 -0
- package/dist/sn/discovery/DiscoveryModels.d.ts +160 -0
- package/dist/sn/discovery/DiscoveryModels.js +5 -0
- package/dist/sn/discovery/DiscoveryModels.js.map +1 -0
- package/dist/sn/discovery/InstanceDiscovery.d.ts +45 -0
- package/dist/sn/discovery/InstanceDiscovery.js +163 -0
- package/dist/sn/discovery/InstanceDiscovery.js.map +1 -0
- package/dist/sn/health/HealthModels.d.ts +124 -0
- package/dist/sn/health/HealthModels.js +5 -0
- package/dist/sn/health/HealthModels.js.map +1 -0
- package/dist/sn/health/InstanceHealth.d.ts +58 -0
- package/dist/sn/health/InstanceHealth.js +221 -0
- package/dist/sn/health/InstanceHealth.js.map +1 -0
- package/dist/sn/scope/ScopeManager.d.ts +7 -7
- package/dist/sn/scope/ScopeManager.js +19 -14
- package/dist/sn/scope/ScopeManager.js.map +1 -1
- package/dist/sn/scope/ScopeModels.d.ts +9 -3
- package/dist/sn/updateset/UpdateSetManager.d.ts +3 -3
- package/dist/sn/updateset/UpdateSetManager.js +12 -7
- package/dist/sn/updateset/UpdateSetManager.js.map +1 -1
- package/dist/sn/updateset/UpdateSetModels.d.ts +11 -0
- package/package.json +1 -1
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { Logger } from "../../util/Logger.js";
|
|
2
|
+
import { ServiceNowRequest } from "../../comm/http/ServiceNowRequest.js";
|
|
3
|
+
import { TableAPIRequest } from "../../comm/http/TableAPIRequest.js";
|
|
4
|
+
/**
|
|
5
|
+
* QueryBatchOperations provides query-based bulk update and delete operations.
|
|
6
|
+
* Records are found by encoded query, then updated or deleted in bulk.
|
|
7
|
+
* Includes a dry-run mode (default) for safe previewing before execution.
|
|
8
|
+
*/
|
|
9
|
+
export class QueryBatchOperations {
|
|
10
|
+
static DEFAULT_LIMIT = 200;
|
|
11
|
+
static MAX_LIMIT = 10000;
|
|
12
|
+
_logger = new Logger("QueryBatchOperations");
|
|
13
|
+
_req;
|
|
14
|
+
_tableAPI;
|
|
15
|
+
_instance;
|
|
16
|
+
_headers = {
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
"Accept": "application/json"
|
|
19
|
+
};
|
|
20
|
+
constructor(instance) {
|
|
21
|
+
this._instance = instance;
|
|
22
|
+
this._req = new ServiceNowRequest(instance);
|
|
23
|
+
this._tableAPI = new TableAPIRequest(instance);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Find records matching a query and update them with the provided data.
|
|
27
|
+
* Defaults to dry-run mode (confirm=false) which returns match count without executing.
|
|
28
|
+
*
|
|
29
|
+
* @param options Query update options
|
|
30
|
+
* @returns QueryUpdateResult with match count, update count, and any errors
|
|
31
|
+
* @throws Error if table, query, or data is empty
|
|
32
|
+
*/
|
|
33
|
+
async queryUpdate(options) {
|
|
34
|
+
const startTime = Date.now();
|
|
35
|
+
if (!options.table || options.table.trim().length === 0) {
|
|
36
|
+
throw new Error('Table name is required');
|
|
37
|
+
}
|
|
38
|
+
if (!options.query || options.query.trim().length === 0) {
|
|
39
|
+
throw new Error('Query is required');
|
|
40
|
+
}
|
|
41
|
+
if (!options.data || Object.keys(options.data).length === 0) {
|
|
42
|
+
throw new Error('Update data is required and must not be empty');
|
|
43
|
+
}
|
|
44
|
+
const limit = Math.min(options.limit ?? QueryBatchOperations.DEFAULT_LIMIT, QueryBatchOperations.MAX_LIMIT);
|
|
45
|
+
const isDryRun = options.confirm !== true;
|
|
46
|
+
this._logger.info(`Query update on '${options.table}' with query '${options.query}' (dryRun=${isDryRun}, limit=${limit})`);
|
|
47
|
+
// Step 1: Find matching records
|
|
48
|
+
const matchingSysIds = await this._findMatchingRecords(options.table, options.query, limit);
|
|
49
|
+
const matchCount = matchingSysIds.length;
|
|
50
|
+
if (options.onProgress) {
|
|
51
|
+
options.onProgress(`Found ${matchCount} matching records in '${options.table}'`);
|
|
52
|
+
}
|
|
53
|
+
// Step 2: Dry run - return count only
|
|
54
|
+
if (isDryRun) {
|
|
55
|
+
this._logger.info(`Dry run: ${matchCount} records would be updated in '${options.table}'`);
|
|
56
|
+
return {
|
|
57
|
+
dryRun: true,
|
|
58
|
+
matchCount,
|
|
59
|
+
updatedCount: 0,
|
|
60
|
+
success: true,
|
|
61
|
+
errors: [],
|
|
62
|
+
executionTimeMs: Date.now() - startTime
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// Step 3: Execute updates
|
|
66
|
+
const errors = [];
|
|
67
|
+
let updatedCount = 0;
|
|
68
|
+
for (let i = 0; i < matchingSysIds.length; i++) {
|
|
69
|
+
const sysId = matchingSysIds[i];
|
|
70
|
+
try {
|
|
71
|
+
const response = await this._tableAPI.put(options.table, sysId, options.data);
|
|
72
|
+
if (response && response.status === 200) {
|
|
73
|
+
updatedCount++;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
errors.push({ sysId, error: `Update failed with status: ${response?.status ?? 'unknown'}` });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
81
|
+
errors.push({ sysId, error: errorMsg });
|
|
82
|
+
}
|
|
83
|
+
if (options.onProgress && (i + 1) % 50 === 0) {
|
|
84
|
+
options.onProgress(`Updated ${updatedCount}/${matchCount} records (${errors.length} errors)`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (options.onProgress) {
|
|
88
|
+
options.onProgress(`Update complete: ${updatedCount} updated, ${errors.length} errors`);
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
dryRun: false,
|
|
92
|
+
matchCount,
|
|
93
|
+
updatedCount,
|
|
94
|
+
success: errors.length === 0,
|
|
95
|
+
errors,
|
|
96
|
+
executionTimeMs: Date.now() - startTime
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Find records matching a query and delete them.
|
|
101
|
+
* Defaults to dry-run mode (confirm=false) which returns match count without executing.
|
|
102
|
+
*
|
|
103
|
+
* @param options Query delete options
|
|
104
|
+
* @returns QueryDeleteResult with match count, delete count, and any errors
|
|
105
|
+
* @throws Error if table or query is empty
|
|
106
|
+
*/
|
|
107
|
+
async queryDelete(options) {
|
|
108
|
+
const startTime = Date.now();
|
|
109
|
+
if (!options.table || options.table.trim().length === 0) {
|
|
110
|
+
throw new Error('Table name is required');
|
|
111
|
+
}
|
|
112
|
+
if (!options.query || options.query.trim().length === 0) {
|
|
113
|
+
throw new Error('Query is required');
|
|
114
|
+
}
|
|
115
|
+
const limit = Math.min(options.limit ?? QueryBatchOperations.DEFAULT_LIMIT, QueryBatchOperations.MAX_LIMIT);
|
|
116
|
+
const isDryRun = options.confirm !== true;
|
|
117
|
+
this._logger.info(`Query delete on '${options.table}' with query '${options.query}' (dryRun=${isDryRun}, limit=${limit})`);
|
|
118
|
+
// Step 1: Find matching records
|
|
119
|
+
const matchingSysIds = await this._findMatchingRecords(options.table, options.query, limit);
|
|
120
|
+
const matchCount = matchingSysIds.length;
|
|
121
|
+
if (options.onProgress) {
|
|
122
|
+
options.onProgress(`Found ${matchCount} matching records in '${options.table}'`);
|
|
123
|
+
}
|
|
124
|
+
// Step 2: Dry run - return count only
|
|
125
|
+
if (isDryRun) {
|
|
126
|
+
this._logger.info(`Dry run: ${matchCount} records would be deleted from '${options.table}'`);
|
|
127
|
+
return {
|
|
128
|
+
dryRun: true,
|
|
129
|
+
matchCount,
|
|
130
|
+
deletedCount: 0,
|
|
131
|
+
success: true,
|
|
132
|
+
errors: [],
|
|
133
|
+
executionTimeMs: Date.now() - startTime
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// Step 3: Execute deletes
|
|
137
|
+
const errors = [];
|
|
138
|
+
let deletedCount = 0;
|
|
139
|
+
for (let i = 0; i < matchingSysIds.length; i++) {
|
|
140
|
+
const sysId = matchingSysIds[i];
|
|
141
|
+
try {
|
|
142
|
+
const request = {
|
|
143
|
+
path: `/api/now/table/${options.table}/${sysId}`,
|
|
144
|
+
method: 'delete',
|
|
145
|
+
headers: this._headers,
|
|
146
|
+
query: null,
|
|
147
|
+
body: null
|
|
148
|
+
};
|
|
149
|
+
const response = await this._req.executeRequest(request);
|
|
150
|
+
if (response && (response.status === 200 || response.status === 204)) {
|
|
151
|
+
deletedCount++;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
errors.push({ sysId, error: `Delete failed with status: ${response?.status ?? 'unknown'}` });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
159
|
+
errors.push({ sysId, error: errorMsg });
|
|
160
|
+
}
|
|
161
|
+
if (options.onProgress && (i + 1) % 50 === 0) {
|
|
162
|
+
options.onProgress(`Deleted ${deletedCount}/${matchCount} records (${errors.length} errors)`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (options.onProgress) {
|
|
166
|
+
options.onProgress(`Delete complete: ${deletedCount} deleted, ${errors.length} errors`);
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
dryRun: false,
|
|
170
|
+
matchCount,
|
|
171
|
+
deletedCount,
|
|
172
|
+
success: errors.length === 0,
|
|
173
|
+
errors,
|
|
174
|
+
executionTimeMs: Date.now() - startTime
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Find records matching a query and return their sys_ids.
|
|
179
|
+
* Only fetches sys_id field for efficiency.
|
|
180
|
+
* @private
|
|
181
|
+
*/
|
|
182
|
+
async _findMatchingRecords(table, query, limit) {
|
|
183
|
+
const queryParams = {
|
|
184
|
+
sysparm_query: query,
|
|
185
|
+
sysparm_limit: limit,
|
|
186
|
+
sysparm_fields: 'sys_id'
|
|
187
|
+
};
|
|
188
|
+
const response = await this._tableAPI.get(table, queryParams);
|
|
189
|
+
if (response && response.status === 200 && response.bodyObject?.result) {
|
|
190
|
+
return response.bodyObject.result.map(r => r.sys_id);
|
|
191
|
+
}
|
|
192
|
+
throw new Error(`Failed to query records in table '${table}'. Status: ${response?.status ?? 'unknown'}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=QueryBatchOperations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryBatchOperations.js","sourceRoot":"","sources":["../../../src/sn/batch/QueryBatchOperations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direction of relationship traversal.
|
|
3
|
+
*/
|
|
4
|
+
export type TraversalDirection = 'upstream' | 'downstream' | 'both';
|
|
5
|
+
/**
|
|
6
|
+
* Options for getting direct relationships of a CI.
|
|
7
|
+
*/
|
|
8
|
+
export interface GetRelationshipsOptions {
|
|
9
|
+
/** The sys_id of the CI to get relationships for (required) */
|
|
10
|
+
ciSysId: string;
|
|
11
|
+
/** Direction of traversal. Defaults to 'both'. */
|
|
12
|
+
direction?: TraversalDirection;
|
|
13
|
+
/** Optional relationship type filter (name from cmdb_rel_type) */
|
|
14
|
+
relationType?: string;
|
|
15
|
+
/** Maximum number of relationships to return. Defaults to 100. */
|
|
16
|
+
limit?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Options for traversing the CMDB relationship graph.
|
|
20
|
+
*/
|
|
21
|
+
export interface TraverseGraphOptions {
|
|
22
|
+
/** The sys_id of the starting CI (required) */
|
|
23
|
+
ciSysId: string;
|
|
24
|
+
/** Direction of traversal. Defaults to 'downstream'. */
|
|
25
|
+
direction?: TraversalDirection;
|
|
26
|
+
/** Maximum traversal depth. Defaults to 3. Max allowed: 5. */
|
|
27
|
+
maxDepth?: number;
|
|
28
|
+
/** Optional relationship type filter */
|
|
29
|
+
relationType?: string;
|
|
30
|
+
/** Maximum total CIs to visit. Defaults to 200. Max allowed: 1000. */
|
|
31
|
+
maxNodes?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A CI record from the CMDB.
|
|
35
|
+
*/
|
|
36
|
+
export interface CMDBCIRecord {
|
|
37
|
+
/** The system ID */
|
|
38
|
+
sys_id: string;
|
|
39
|
+
/** The CI name */
|
|
40
|
+
name?: string;
|
|
41
|
+
/** The CI class (table name) */
|
|
42
|
+
sys_class_name?: string;
|
|
43
|
+
/** Additional fields */
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A relationship record from cmdb_rel_ci.
|
|
48
|
+
*/
|
|
49
|
+
export interface CMDBRelationshipRecord {
|
|
50
|
+
/** The system ID of the relationship */
|
|
51
|
+
sys_id: string;
|
|
52
|
+
/** The parent CI sys_id */
|
|
53
|
+
parent: string | {
|
|
54
|
+
link: string;
|
|
55
|
+
value: string;
|
|
56
|
+
display_value?: string;
|
|
57
|
+
};
|
|
58
|
+
/** The child CI sys_id */
|
|
59
|
+
child: string | {
|
|
60
|
+
link: string;
|
|
61
|
+
value: string;
|
|
62
|
+
display_value?: string;
|
|
63
|
+
};
|
|
64
|
+
/** The relationship type */
|
|
65
|
+
type: string | {
|
|
66
|
+
link: string;
|
|
67
|
+
value: string;
|
|
68
|
+
display_value?: string;
|
|
69
|
+
};
|
|
70
|
+
/** Additional fields */
|
|
71
|
+
[key: string]: unknown;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A node in the relationship graph.
|
|
75
|
+
*/
|
|
76
|
+
export interface GraphNode {
|
|
77
|
+
/** The CI sys_id */
|
|
78
|
+
sysId: string;
|
|
79
|
+
/** The CI name */
|
|
80
|
+
name: string;
|
|
81
|
+
/** The CI class */
|
|
82
|
+
className: string;
|
|
83
|
+
/** Depth from the starting CI (0 = root) */
|
|
84
|
+
depth: number;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* An edge in the relationship graph.
|
|
88
|
+
*/
|
|
89
|
+
export interface GraphEdge {
|
|
90
|
+
/** Parent CI sys_id */
|
|
91
|
+
parentSysId: string;
|
|
92
|
+
/** Child CI sys_id */
|
|
93
|
+
childSysId: string;
|
|
94
|
+
/** Relationship type name */
|
|
95
|
+
typeName: string;
|
|
96
|
+
/** Relationship sys_id */
|
|
97
|
+
relationshipSysId: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Result of getting direct relationships.
|
|
101
|
+
*/
|
|
102
|
+
export interface RelationshipsResult {
|
|
103
|
+
/** The queried CI */
|
|
104
|
+
ci: CMDBCIRecord;
|
|
105
|
+
/** Direct relationships */
|
|
106
|
+
relationships: Array<{
|
|
107
|
+
/** The related CI */
|
|
108
|
+
relatedCI: CMDBCIRecord;
|
|
109
|
+
/** Direction: 'upstream' (this CI is child) or 'downstream' (this CI is parent) */
|
|
110
|
+
direction: 'upstream' | 'downstream';
|
|
111
|
+
/** Relationship type name */
|
|
112
|
+
typeName: string;
|
|
113
|
+
/** Relationship record sys_id */
|
|
114
|
+
relationshipSysId: string;
|
|
115
|
+
}>;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Result of a full graph traversal.
|
|
119
|
+
*/
|
|
120
|
+
export interface GraphTraversalResult {
|
|
121
|
+
/** The starting CI */
|
|
122
|
+
rootCI: CMDBCIRecord;
|
|
123
|
+
/** All nodes visited in the graph */
|
|
124
|
+
nodes: GraphNode[];
|
|
125
|
+
/** All edges discovered in the graph */
|
|
126
|
+
edges: GraphEdge[];
|
|
127
|
+
/** Total number of API calls made */
|
|
128
|
+
apiCallCount: number;
|
|
129
|
+
/** Whether the traversal was truncated due to maxDepth or maxNodes */
|
|
130
|
+
truncated: boolean;
|
|
131
|
+
/** Reason for truncation if truncated is true */
|
|
132
|
+
truncationReason?: string;
|
|
133
|
+
}
|
|
134
|
+
/** Response from cmdb_ci query. */
|
|
135
|
+
export interface CMDBCIResponse {
|
|
136
|
+
result: CMDBCIRecord[];
|
|
137
|
+
}
|
|
138
|
+
/** Response from cmdb_rel_ci query. */
|
|
139
|
+
export interface CMDBRelResponse {
|
|
140
|
+
result: CMDBRelationshipRecord[];
|
|
141
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CMDBModels.js","sourceRoot":"","sources":["../../../src/sn/cmdb/CMDBModels.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,gBAAgB;AAChB,+DAA+D"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ServiceNowInstance } from "../ServiceNowInstance.js";
|
|
2
|
+
import { GetRelationshipsOptions, TraverseGraphOptions, RelationshipsResult, GraphTraversalResult } from './CMDBModels.js';
|
|
3
|
+
/**
|
|
4
|
+
* CMDBRelationships provides methods for querying and traversing
|
|
5
|
+
* CMDB relationship graphs. Supports single-level lookups and
|
|
6
|
+
* multi-level BFS traversal with configurable depth and direction.
|
|
7
|
+
*/
|
|
8
|
+
export declare class CMDBRelationships {
|
|
9
|
+
private static readonly CMDB_CI_TABLE;
|
|
10
|
+
private static readonly CMDB_REL_CI_TABLE;
|
|
11
|
+
private static readonly MAX_DEPTH;
|
|
12
|
+
private static readonly MAX_NODES;
|
|
13
|
+
private _logger;
|
|
14
|
+
private _tableAPI;
|
|
15
|
+
private _instance;
|
|
16
|
+
/** Cache for CI records to minimize API calls during traversal */
|
|
17
|
+
private _ciCache;
|
|
18
|
+
constructor(instance: ServiceNowInstance);
|
|
19
|
+
/**
|
|
20
|
+
* Get direct relationships of a CI (single level).
|
|
21
|
+
*
|
|
22
|
+
* @param options Relationship query options
|
|
23
|
+
* @returns RelationshipsResult with the CI and its direct relationships
|
|
24
|
+
* @throws Error if ciSysId is empty
|
|
25
|
+
*/
|
|
26
|
+
getRelationships(options: GetRelationshipsOptions): Promise<RelationshipsResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Traverse the CMDB relationship graph using BFS starting from a CI.
|
|
29
|
+
*
|
|
30
|
+
* @param options Traversal options
|
|
31
|
+
* @returns GraphTraversalResult with all nodes, edges, and metadata
|
|
32
|
+
* @throws Error if ciSysId is empty
|
|
33
|
+
*/
|
|
34
|
+
traverseGraph(options: TraverseGraphOptions): Promise<GraphTraversalResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Look up a single CI by sys_id. Uses cache when available.
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
private _lookupCI;
|
|
40
|
+
/**
|
|
41
|
+
* Batch look up multiple CIs by sys_id.
|
|
42
|
+
* @private
|
|
43
|
+
*/
|
|
44
|
+
private _batchLookupCIs;
|
|
45
|
+
/**
|
|
46
|
+
* Query relationships from cmdb_rel_ci.
|
|
47
|
+
* @private
|
|
48
|
+
*/
|
|
49
|
+
private _queryRelationships;
|
|
50
|
+
/**
|
|
51
|
+
* Extract sys_id from a field that may be a string or reference object.
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
54
|
+
private _extractSysId;
|
|
55
|
+
/**
|
|
56
|
+
* Extract display value or value from a field.
|
|
57
|
+
* @private
|
|
58
|
+
*/
|
|
59
|
+
private _extractDisplayValue;
|
|
60
|
+
}
|