quickbase-js 2.4.0 → 2.4.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/README.md +144 -76
- package/dist/quickbase.esm.js +3 -3
- package/dist/quickbase.min.js +3 -3
- package/dist/quickbase.min.js.map +1 -1
- package/package.json +13 -9
- package/src/auth/index.ts +55 -0
- package/src/auth/sso-token.ts +143 -0
- package/src/auth/temp-token.ts +160 -0
- package/src/auth/ticket.ts +329 -0
- package/src/auth/token-cache.ts +97 -0
- package/src/auth/types.ts +50 -0
- package/src/auth/user-token.ts +38 -0
- package/src/cli/schema.ts +512 -0
- package/src/client/index.ts +36 -0
- package/src/client/pagination.ts +337 -0
- package/src/client/request.ts +544 -0
- package/src/client/retry.ts +169 -0
- package/src/client/throttle.ts +105 -0
- package/src/core/config.ts +160 -0
- package/src/core/dates.ts +63 -0
- package/src/core/errors.ts +349 -0
- package/src/core/index.ts +50 -0
- package/src/core/logger.ts +113 -0
- package/src/core/schema.ts +213 -0
- package/src/core/transform.ts +295 -0
- package/src/core/types.ts +337 -0
- package/src/generated/client.ts +1785 -0
- package/src/generated/operations.json +672 -0
- package/src/generated/types.ts +4884 -0
- package/src/index.ts +259 -0
- package/src/xml/codepages.ts +119 -0
- package/src/xml/dbvars.ts +75 -0
- package/src/xml/errors.ts +133 -0
- package/src/xml/fields.ts +121 -0
- package/src/xml/groups.ts +560 -0
- package/src/xml/html.ts +152 -0
- package/src/xml/index.ts +1196 -0
- package/src/xml/metadata.ts +111 -0
- package/src/xml/records.ts +301 -0
- package/src/xml/request.ts +238 -0
- package/src/xml/roles.ts +321 -0
- package/src/xml/schema.ts +436 -0
- package/src/xml/transform.ts +381 -0
- package/src/xml/types.ts +602 -0
- package/src/xml/users.ts +221 -0
- package/src/xml/webhooks.ts +260 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML API Schema and App Discovery
|
|
3
|
+
*
|
|
4
|
+
* Endpoints for discovering apps/tables and getting schema information.
|
|
5
|
+
*
|
|
6
|
+
* XML-API: Remove this file when QuickBase discontinues the XML API.
|
|
7
|
+
* To find all XML API code, search for: XML-API
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
XmlCaller,
|
|
12
|
+
DatabaseInfo,
|
|
13
|
+
DBInfo,
|
|
14
|
+
GetSchemaResult,
|
|
15
|
+
GrantedDBsResult,
|
|
16
|
+
FindDBByNameResult,
|
|
17
|
+
SchemaTable,
|
|
18
|
+
SchemaOriginal,
|
|
19
|
+
SchemaField,
|
|
20
|
+
SchemaQuery,
|
|
21
|
+
SchemaVariable,
|
|
22
|
+
SchemaChildTable,
|
|
23
|
+
} from './types.js';
|
|
24
|
+
import { checkError } from './errors.js';
|
|
25
|
+
import {
|
|
26
|
+
buildRequest,
|
|
27
|
+
escapeXml,
|
|
28
|
+
parseBaseResponse,
|
|
29
|
+
getTagContent,
|
|
30
|
+
getAttribute,
|
|
31
|
+
getAllElements,
|
|
32
|
+
parseXmlNumber,
|
|
33
|
+
parseXmlBool,
|
|
34
|
+
} from './request.js';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* List all apps/tables the user can access.
|
|
38
|
+
*
|
|
39
|
+
* Returns apps across all domains by default. Use realmAppsOnly to limit
|
|
40
|
+
* to the current realm.
|
|
41
|
+
*
|
|
42
|
+
* @see https://help.quickbase.com/docs/api-granteddbs
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const result = await grantedDBs(caller, { parentsOnly: true });
|
|
47
|
+
* for (const db of result.databases) {
|
|
48
|
+
* console.log(`${db.name} (${db.dbid})`);
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export async function grantedDBs(
|
|
53
|
+
caller: XmlCaller,
|
|
54
|
+
options?: {
|
|
55
|
+
parentsOnly?: boolean;
|
|
56
|
+
excludeParents?: boolean;
|
|
57
|
+
adminOnly?: boolean;
|
|
58
|
+
includeAncestors?: boolean;
|
|
59
|
+
withEmbeddedTables?: boolean;
|
|
60
|
+
realmAppsOnly?: boolean;
|
|
61
|
+
}
|
|
62
|
+
): Promise<GrantedDBsResult> {
|
|
63
|
+
let inner = '';
|
|
64
|
+
if (options?.excludeParents) {
|
|
65
|
+
inner += '<excludeparents>1</excludeparents>';
|
|
66
|
+
}
|
|
67
|
+
if (options?.parentsOnly) {
|
|
68
|
+
inner += '<Withembeddedtables>0</Withembeddedtables>';
|
|
69
|
+
}
|
|
70
|
+
if (options?.adminOnly) {
|
|
71
|
+
inner += '<adminOnly>true</adminOnly>';
|
|
72
|
+
}
|
|
73
|
+
if (options?.includeAncestors) {
|
|
74
|
+
inner += '<includeancestors>1</includeancestors>';
|
|
75
|
+
}
|
|
76
|
+
if (options?.withEmbeddedTables !== undefined) {
|
|
77
|
+
inner += `<withembeddedtables>${options.withEmbeddedTables ? '1' : '0'}</withembeddedtables>`;
|
|
78
|
+
}
|
|
79
|
+
if (options?.realmAppsOnly) {
|
|
80
|
+
inner += '<realmAppsOnly>true</realmAppsOnly>';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const body = buildRequest(inner);
|
|
84
|
+
const xml = await caller.doXml('main', 'API_GrantedDBs', body);
|
|
85
|
+
|
|
86
|
+
const base = parseBaseResponse(xml);
|
|
87
|
+
checkError(base);
|
|
88
|
+
|
|
89
|
+
// Parse databases
|
|
90
|
+
const dbElements = getAllElements(xml, 'dbinfo');
|
|
91
|
+
const databases: DatabaseInfo[] = dbElements.map((dbXml) => {
|
|
92
|
+
const info: DatabaseInfo = {
|
|
93
|
+
dbid: getTagContent(dbXml, 'dbid'),
|
|
94
|
+
name: getTagContent(dbXml, 'dbname'),
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const ancestorAppId = getTagContent(dbXml, 'ancestorappid');
|
|
98
|
+
if (ancestorAppId) {
|
|
99
|
+
info.ancestorAppId = ancestorAppId;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const oldestAncestorAppId = getTagContent(dbXml, 'oldestancestorappid');
|
|
103
|
+
if (oldestAncestorAppId) {
|
|
104
|
+
info.oldestAncestorAppId = oldestAncestorAppId;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return info;
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return { databases };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Find an app by name.
|
|
115
|
+
*
|
|
116
|
+
* Searches only apps you have access to. May return multiple results
|
|
117
|
+
* if multiple apps share the same name.
|
|
118
|
+
*
|
|
119
|
+
* @see https://help.quickbase.com/docs/api-finddbbyname
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const result = await findDBByName(caller, 'My App', true);
|
|
124
|
+
* console.log(`Found app: ${result.dbid}`);
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export async function findDBByName(
|
|
128
|
+
caller: XmlCaller,
|
|
129
|
+
name: string,
|
|
130
|
+
parentsOnly?: boolean
|
|
131
|
+
): Promise<FindDBByNameResult> {
|
|
132
|
+
let inner = `<dbname>${escapeXml(name)}</dbname>`;
|
|
133
|
+
if (parentsOnly) {
|
|
134
|
+
inner += '<ParentsOnly>1</ParentsOnly>';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const body = buildRequest(inner);
|
|
138
|
+
const xml = await caller.doXml('main', 'API_FindDBByName', body);
|
|
139
|
+
|
|
140
|
+
const base = parseBaseResponse(xml);
|
|
141
|
+
checkError(base);
|
|
142
|
+
|
|
143
|
+
const dbid = getTagContent(xml, 'dbid');
|
|
144
|
+
if (!dbid) {
|
|
145
|
+
throw new Error('Invalid API_FindDBByName response: no dbid element');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { dbid };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get app/table metadata.
|
|
153
|
+
*
|
|
154
|
+
* Returns information like last modified time, record count, manager info.
|
|
155
|
+
*
|
|
156
|
+
* @see https://help.quickbase.com/docs/api-getdbinfo
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* const info = await getDBInfo(caller, 'bqxyz123');
|
|
161
|
+
* console.log(`${info.name}: ${info.numRecords} records`);
|
|
162
|
+
* console.log(`Manager: ${info.managerName}`);
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export async function getDBInfo(
|
|
166
|
+
caller: XmlCaller,
|
|
167
|
+
dbid: string
|
|
168
|
+
): Promise<DBInfo> {
|
|
169
|
+
const body = buildRequest('');
|
|
170
|
+
const xml = await caller.doXml(dbid, 'API_GetDBInfo', body);
|
|
171
|
+
|
|
172
|
+
const base = parseBaseResponse(xml);
|
|
173
|
+
checkError(base);
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
name: getTagContent(xml, 'dbname'),
|
|
177
|
+
lastRecModTime: getTagContent(xml, 'lastRecModTime') || undefined,
|
|
178
|
+
lastModifiedTime: getTagContent(xml, 'lastModifiedTime') || undefined,
|
|
179
|
+
createdTime: getTagContent(xml, 'createdTime') || undefined,
|
|
180
|
+
numRecords: parseXmlNumber(getTagContent(xml, 'numRecords')),
|
|
181
|
+
managerId: getTagContent(xml, 'mgrID') || undefined,
|
|
182
|
+
managerName: getTagContent(xml, 'mgrName') || undefined,
|
|
183
|
+
version: getTagContent(xml, 'version') || undefined,
|
|
184
|
+
timeZone: getTagContent(xml, 'time_zone') || undefined,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get total record count for a table.
|
|
190
|
+
*
|
|
191
|
+
* @see https://help.quickbase.com/docs/api-getnumrecords
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```typescript
|
|
195
|
+
* const count = await getNumRecords(caller, 'bqtable123');
|
|
196
|
+
* console.log(`Table has ${count} records`);
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export async function getNumRecords(
|
|
200
|
+
caller: XmlCaller,
|
|
201
|
+
tableId: string
|
|
202
|
+
): Promise<number> {
|
|
203
|
+
const body = buildRequest('');
|
|
204
|
+
const xml = await caller.doXml(tableId, 'API_GetNumRecords', body);
|
|
205
|
+
|
|
206
|
+
const base = parseBaseResponse(xml);
|
|
207
|
+
checkError(base);
|
|
208
|
+
|
|
209
|
+
return parseXmlNumber(getTagContent(xml, 'num_records'));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Parse a field element from GetSchema response
|
|
214
|
+
*/
|
|
215
|
+
function parseSchemaField(fieldXml: string): SchemaField {
|
|
216
|
+
const field: SchemaField = {
|
|
217
|
+
id: parseXmlNumber(getAttribute(fieldXml, 'id')),
|
|
218
|
+
fieldType: getAttribute(fieldXml, 'field_type'),
|
|
219
|
+
baseType: getAttribute(fieldXml, 'base_type'),
|
|
220
|
+
label: getTagContent(fieldXml, 'label'),
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const mode = getAttribute(fieldXml, 'mode');
|
|
224
|
+
if (mode) field.mode = mode;
|
|
225
|
+
|
|
226
|
+
const nowrap = getTagContent(fieldXml, 'nowrap');
|
|
227
|
+
if (nowrap) field.nowrap = parseXmlBool(nowrap);
|
|
228
|
+
|
|
229
|
+
const bold = getTagContent(fieldXml, 'bold');
|
|
230
|
+
if (bold) field.bold = parseXmlBool(bold);
|
|
231
|
+
|
|
232
|
+
const required = getTagContent(fieldXml, 'required');
|
|
233
|
+
if (required) field.required = parseXmlBool(required);
|
|
234
|
+
|
|
235
|
+
const unique = getTagContent(fieldXml, 'unique');
|
|
236
|
+
if (unique) field.unique = parseXmlBool(unique);
|
|
237
|
+
|
|
238
|
+
const fieldHelp = getTagContent(fieldXml, 'fieldhelp');
|
|
239
|
+
if (fieldHelp) field.fieldHelp = fieldHelp;
|
|
240
|
+
|
|
241
|
+
const appearsByDefault = getTagContent(fieldXml, 'appears_by_default');
|
|
242
|
+
if (appearsByDefault) field.appearsByDefault = parseXmlBool(appearsByDefault);
|
|
243
|
+
|
|
244
|
+
const findEnabled = getTagContent(fieldXml, 'find_enabled');
|
|
245
|
+
if (findEnabled) field.findEnabled = parseXmlBool(findEnabled);
|
|
246
|
+
|
|
247
|
+
const allowNewChoices = getTagContent(fieldXml, 'allow_new_choices');
|
|
248
|
+
if (allowNewChoices) field.allowNewChoices = parseXmlBool(allowNewChoices);
|
|
249
|
+
|
|
250
|
+
const sortAsGiven = getTagContent(fieldXml, 'sort_as_given');
|
|
251
|
+
if (sortAsGiven) field.sortAsGiven = parseXmlBool(sortAsGiven);
|
|
252
|
+
|
|
253
|
+
const carryChoices = getTagContent(fieldXml, 'carrychoices');
|
|
254
|
+
if (carryChoices) field.carryChoices = parseXmlBool(carryChoices);
|
|
255
|
+
|
|
256
|
+
const foreignKey = getTagContent(fieldXml, 'foreignkey');
|
|
257
|
+
if (foreignKey) field.foreignKey = parseXmlBool(foreignKey);
|
|
258
|
+
|
|
259
|
+
const doesTotal = getTagContent(fieldXml, 'does_total');
|
|
260
|
+
if (doesTotal) field.doesTotal = parseXmlBool(doesTotal);
|
|
261
|
+
|
|
262
|
+
const doesAverage = getTagContent(fieldXml, 'does_average');
|
|
263
|
+
if (doesAverage) field.doesAverage = parseXmlBool(doesAverage);
|
|
264
|
+
|
|
265
|
+
const defaultKind = getTagContent(fieldXml, 'default_kind');
|
|
266
|
+
if (defaultKind) field.defaultKind = defaultKind;
|
|
267
|
+
|
|
268
|
+
const defaultValue = getTagContent(fieldXml, 'default_value');
|
|
269
|
+
if (defaultValue) field.defaultValue = defaultValue;
|
|
270
|
+
|
|
271
|
+
// Parse choices if present
|
|
272
|
+
const choicesMatch = fieldXml.match(/<choices>([\s\S]*?)<\/choices>/);
|
|
273
|
+
if (choicesMatch && choicesMatch[1]) {
|
|
274
|
+
const choiceElements = getAllElements(choicesMatch[1], 'choice');
|
|
275
|
+
field.choices = choiceElements.map((c) => getTagContent(c, 'choice') || c.replace(/<\/?choice>/g, ''));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Parse summary fields
|
|
279
|
+
const summaryReferenceFid = getTagContent(fieldXml, 'summaryReferenceFid');
|
|
280
|
+
if (summaryReferenceFid) field.summaryReferenceFid = parseXmlNumber(summaryReferenceFid);
|
|
281
|
+
|
|
282
|
+
const summaryTargetFid = getTagContent(fieldXml, 'summaryTargetFid');
|
|
283
|
+
if (summaryTargetFid) field.summaryTargetFid = parseXmlNumber(summaryTargetFid);
|
|
284
|
+
|
|
285
|
+
const summaryFunction = getTagContent(fieldXml, 'summaryFunction');
|
|
286
|
+
if (summaryFunction) field.summaryFunction = summaryFunction;
|
|
287
|
+
|
|
288
|
+
return field;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Parse a query element from GetSchema response
|
|
293
|
+
*/
|
|
294
|
+
function parseSchemaQuery(queryXml: string): SchemaQuery {
|
|
295
|
+
const query: SchemaQuery = {
|
|
296
|
+
id: parseXmlNumber(getAttribute(queryXml, 'id')),
|
|
297
|
+
name: getTagContent(queryXml, 'qyname') || getTagContent(queryXml, 'qname'),
|
|
298
|
+
type: getTagContent(queryXml, 'qytype'),
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const desc = getTagContent(queryXml, 'qydesc');
|
|
302
|
+
if (desc) query.description = desc;
|
|
303
|
+
|
|
304
|
+
const crit = getTagContent(queryXml, 'qycrit');
|
|
305
|
+
if (crit) query.criteria = crit;
|
|
306
|
+
|
|
307
|
+
const clst = getTagContent(queryXml, 'qyclst');
|
|
308
|
+
if (clst) query.columnList = clst;
|
|
309
|
+
|
|
310
|
+
const slst = getTagContent(queryXml, 'qyslst');
|
|
311
|
+
if (slst) query.sortList = slst;
|
|
312
|
+
|
|
313
|
+
const opts = getTagContent(queryXml, 'qyopts');
|
|
314
|
+
if (opts) query.options = opts;
|
|
315
|
+
|
|
316
|
+
const calst = getTagContent(queryXml, 'qycalst');
|
|
317
|
+
if (calst) query.calcFields = calst;
|
|
318
|
+
|
|
319
|
+
return query;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Get comprehensive app/table schema information.
|
|
324
|
+
*
|
|
325
|
+
* When called on an app dbid: returns DBVars and child table dbids.
|
|
326
|
+
* When called on a table dbid: returns fields, queries, DBVars, and more.
|
|
327
|
+
*
|
|
328
|
+
* @see https://help.quickbase.com/docs/api-getschema
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```typescript
|
|
332
|
+
* const schema = await getSchema(caller, 'bqtable123');
|
|
333
|
+
* console.log(`Table: ${schema.table.name}`);
|
|
334
|
+
* for (const field of schema.table.fields ?? []) {
|
|
335
|
+
* console.log(` Field ${field.id}: ${field.label} (${field.fieldType})`);
|
|
336
|
+
* }
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
export async function getSchema(
|
|
340
|
+
caller: XmlCaller,
|
|
341
|
+
dbid: string
|
|
342
|
+
): Promise<GetSchemaResult> {
|
|
343
|
+
const body = buildRequest('');
|
|
344
|
+
const xml = await caller.doXml(dbid, 'API_GetSchema', body);
|
|
345
|
+
|
|
346
|
+
const base = parseBaseResponse(xml);
|
|
347
|
+
checkError(base);
|
|
348
|
+
|
|
349
|
+
// Parse top-level elements
|
|
350
|
+
const timeZone = getTagContent(xml, 'time_zone') || undefined;
|
|
351
|
+
const dateFormat = getTagContent(xml, 'date_format') || undefined;
|
|
352
|
+
|
|
353
|
+
// Parse table element
|
|
354
|
+
const tableMatch = xml.match(/<table>([\s\S]*?)<\/table>/);
|
|
355
|
+
if (!tableMatch) {
|
|
356
|
+
throw new Error('Invalid API_GetSchema response: no table element');
|
|
357
|
+
}
|
|
358
|
+
const tableXml = tableMatch[0];
|
|
359
|
+
|
|
360
|
+
const table: SchemaTable = {
|
|
361
|
+
name: getTagContent(tableXml, 'name'),
|
|
362
|
+
description: getTagContent(tableXml, 'desc') || undefined,
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
// Parse original metadata
|
|
366
|
+
const originalMatch = tableXml.match(/<original>([\s\S]*?)<\/original>/);
|
|
367
|
+
if (originalMatch) {
|
|
368
|
+
const origXml = originalMatch[0];
|
|
369
|
+
const original: SchemaOriginal = {};
|
|
370
|
+
|
|
371
|
+
const appId = getTagContent(origXml, 'app_id');
|
|
372
|
+
if (appId) original.appId = appId;
|
|
373
|
+
|
|
374
|
+
const tableId = getTagContent(origXml, 'table_id');
|
|
375
|
+
if (tableId) original.tableId = tableId;
|
|
376
|
+
|
|
377
|
+
const creDate = getTagContent(origXml, 'cre_date');
|
|
378
|
+
if (creDate) original.createdTime = creDate;
|
|
379
|
+
|
|
380
|
+
const modDate = getTagContent(origXml, 'mod_date');
|
|
381
|
+
if (modDate) original.modifiedTime = modDate;
|
|
382
|
+
|
|
383
|
+
const nextRecordId = getTagContent(origXml, 'next_record_id');
|
|
384
|
+
if (nextRecordId) original.nextRecordId = parseXmlNumber(nextRecordId);
|
|
385
|
+
|
|
386
|
+
const nextFieldId = getTagContent(origXml, 'next_field_id');
|
|
387
|
+
if (nextFieldId) original.nextFieldId = parseXmlNumber(nextFieldId);
|
|
388
|
+
|
|
389
|
+
const nextQueryId = getTagContent(origXml, 'next_query_id');
|
|
390
|
+
if (nextQueryId) original.nextQueryId = parseXmlNumber(nextQueryId);
|
|
391
|
+
|
|
392
|
+
const defSortFid = getTagContent(origXml, 'def_sort_fid');
|
|
393
|
+
if (defSortFid) original.defaultSortFid = parseXmlNumber(defSortFid);
|
|
394
|
+
|
|
395
|
+
const defSortOrder = getTagContent(origXml, 'def_sort_order');
|
|
396
|
+
if (defSortOrder) original.defaultSortOrder = parseXmlNumber(defSortOrder);
|
|
397
|
+
|
|
398
|
+
table.original = original;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Parse variables
|
|
402
|
+
const variablesMatch = tableXml.match(/<variables>([\s\S]*?)<\/variables>/);
|
|
403
|
+
if (variablesMatch) {
|
|
404
|
+
const varElements = getAllElements(variablesMatch[0], 'var');
|
|
405
|
+
table.variables = varElements.map((varXml): SchemaVariable => ({
|
|
406
|
+
name: getAttribute(varXml, 'name'),
|
|
407
|
+
value: getTagContent(varXml, 'var') || '',
|
|
408
|
+
}));
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Parse child tables (chdbids)
|
|
412
|
+
const chdbidsMatch = tableXml.match(/<chdbids>([\s\S]*?)<\/chdbids>/);
|
|
413
|
+
if (chdbidsMatch) {
|
|
414
|
+
const chdbElements = getAllElements(chdbidsMatch[0], 'chdbid');
|
|
415
|
+
table.childTables = chdbElements.map((chXml): SchemaChildTable => ({
|
|
416
|
+
name: getAttribute(chXml, 'name'),
|
|
417
|
+
dbid: getTagContent(chXml, 'chdbid') || '',
|
|
418
|
+
}));
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Parse queries
|
|
422
|
+
const queriesMatch = tableXml.match(/<queries>([\s\S]*?)<\/queries>/);
|
|
423
|
+
if (queriesMatch) {
|
|
424
|
+
const queryElements = getAllElements(queriesMatch[0], 'query');
|
|
425
|
+
table.queries = queryElements.map(parseSchemaQuery);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Parse fields
|
|
429
|
+
const fieldsMatch = tableXml.match(/<fields>([\s\S]*?)<\/fields>/);
|
|
430
|
+
if (fieldsMatch && fieldsMatch[0].length > 20) {
|
|
431
|
+
const fieldElements = getAllElements(fieldsMatch[0], 'field');
|
|
432
|
+
table.fields = fieldElements.map(parseSchemaField);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return { table, timeZone, dateFormat };
|
|
436
|
+
}
|