tm1npm 2.0.0 → 2.1.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/lib/objects/Axis.d.ts +1 -0
- package/lib/objects/Axis.d.ts.map +1 -1
- package/lib/objects/Axis.js +3 -0
- package/lib/objects/Chore.d.ts +2 -2
- package/lib/objects/Chore.d.ts.map +1 -1
- package/lib/objects/Chore.js +7 -13
- package/lib/objects/Cube.d.ts.map +1 -1
- package/lib/objects/Cube.js +2 -1
- package/lib/objects/Hierarchy.js +10 -10
- package/lib/objects/MDXView.d.ts +2 -0
- package/lib/objects/MDXView.d.ts.map +1 -1
- package/lib/objects/MDXView.js +30 -9
- package/lib/objects/NativeView.d.ts +5 -5
- package/lib/objects/NativeView.d.ts.map +1 -1
- package/lib/objects/NativeView.js +17 -34
- package/lib/objects/Process.d.ts +8 -3
- package/lib/objects/Process.d.ts.map +1 -1
- package/lib/objects/Process.js +143 -33
- package/lib/objects/Subset.d.ts.map +1 -1
- package/lib/objects/Subset.js +10 -3
- package/lib/objects/User.d.ts +5 -5
- package/lib/objects/User.d.ts.map +1 -1
- package/lib/objects/User.js +14 -23
- package/lib/tests/debuggerService.test.js +3 -1
- package/lib/tests/objectModelParity.test.js +362 -11
- package/lib/tests/objects.improved.test.js +28 -5
- package/lib/tests/user.issue61.test.d.ts +2 -0
- package/lib/tests/user.issue61.test.d.ts.map +1 -0
- package/lib/tests/user.issue61.test.js +180 -0
- package/lib/utils/Utils.d.ts +6 -1
- package/lib/utils/Utils.d.ts.map +1 -1
- package/lib/utils/Utils.js +56 -7
- package/package.json +1 -1
- package/src/objects/Axis.ts +4 -0
- package/src/objects/Chore.ts +7 -14
- package/src/objects/Cube.ts +2 -1
- package/src/objects/Hierarchy.ts +11 -11
- package/src/objects/MDXView.ts +29 -9
- package/src/objects/NativeView.ts +26 -42
- package/src/objects/Process.ts +182 -66
- package/src/objects/Subset.ts +17 -3
- package/src/objects/User.ts +17 -23
- package/src/tests/debuggerService.test.ts +3 -1
- package/src/tests/objectModelParity.test.ts +456 -11
- package/src/tests/objects.improved.test.ts +41 -9
- package/src/tests/user.issue61.test.ts +206 -0
- package/src/utils/Utils.ts +60 -7
|
@@ -163,86 +163,70 @@ export class NativeView extends View {
|
|
|
163
163
|
this._rows.push(row);
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
public removeTitle(dimensionName: string):
|
|
167
|
-
|
|
168
|
-
caseAndSpaceInsensitiveEquals(t.dimensionName, dimensionName));
|
|
169
|
-
if (index !== -1) {
|
|
170
|
-
this._titles.splice(index, 1);
|
|
171
|
-
return true;
|
|
172
|
-
}
|
|
173
|
-
return false;
|
|
166
|
+
public removeTitle(dimensionName: string): void {
|
|
167
|
+
this._titles = this._titles.filter(
|
|
168
|
+
t => !caseAndSpaceInsensitiveEquals(t.dimensionName, dimensionName));
|
|
174
169
|
}
|
|
175
170
|
|
|
176
|
-
public removeColumn(dimensionName: string):
|
|
177
|
-
|
|
178
|
-
caseAndSpaceInsensitiveEquals(c.
|
|
179
|
-
if (index !== -1) {
|
|
180
|
-
this._columns.splice(index, 1);
|
|
181
|
-
return true;
|
|
182
|
-
}
|
|
183
|
-
return false;
|
|
171
|
+
public removeColumn(dimensionName: string): void {
|
|
172
|
+
this._columns = this._columns.filter(
|
|
173
|
+
c => !caseAndSpaceInsensitiveEquals(c.dimensionName, dimensionName));
|
|
184
174
|
}
|
|
185
175
|
|
|
186
|
-
public removeRow(dimensionName: string):
|
|
187
|
-
|
|
188
|
-
caseAndSpaceInsensitiveEquals(r.
|
|
189
|
-
if (index !== -1) {
|
|
190
|
-
this._rows.splice(index, 1);
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
193
|
-
return false;
|
|
176
|
+
public removeRow(dimensionName: string): void {
|
|
177
|
+
this._rows = this._rows.filter(
|
|
178
|
+
r => !caseAndSpaceInsensitiveEquals(r.dimensionName, dimensionName));
|
|
194
179
|
}
|
|
195
180
|
|
|
196
181
|
public substituteTitle(dimension: string, element: string): void {
|
|
197
|
-
/** Substitute the title element for a given dimension
|
|
198
|
-
*
|
|
199
|
-
* :param dimension: str, name of dimension
|
|
200
|
-
* :param element: str, name of element
|
|
201
|
-
*/
|
|
202
182
|
for (const title of this._titles) {
|
|
203
183
|
if (caseAndSpaceInsensitiveEquals(title.dimensionName, dimension)) {
|
|
184
|
+
title.subset = new AnonymousSubset(dimension, dimension, undefined, [element]);
|
|
204
185
|
title.selected = element;
|
|
205
186
|
return;
|
|
206
187
|
}
|
|
207
188
|
}
|
|
208
|
-
throw new Error(`
|
|
189
|
+
throw new Error(`Dimension '${dimension}' not found in titles`);
|
|
209
190
|
}
|
|
210
191
|
|
|
211
|
-
public static fromJSON(viewAsJson: string, cubeName
|
|
192
|
+
public static fromJSON(viewAsJson: string, cubeName?: string): NativeView {
|
|
212
193
|
const viewAsDict = JSON.parse(viewAsJson);
|
|
213
194
|
return NativeView.fromDict(viewAsDict, cubeName);
|
|
214
195
|
}
|
|
215
196
|
|
|
216
|
-
public static fromDict(viewAsDict: any, cubeName
|
|
197
|
+
public static fromDict(viewAsDict: any, cubeName?: string): NativeView {
|
|
198
|
+
let resolvedCube = cubeName;
|
|
199
|
+
if (!resolvedCube) {
|
|
200
|
+
const ctx: string = viewAsDict["@odata.context"];
|
|
201
|
+
resolvedCube = ctx.substring(20, ctx.indexOf("')/"));
|
|
202
|
+
}
|
|
203
|
+
|
|
217
204
|
const view = new NativeView(
|
|
218
|
-
|
|
205
|
+
resolvedCube,
|
|
219
206
|
viewAsDict.Name,
|
|
220
207
|
viewAsDict.SuppressEmptyColumns || false,
|
|
221
208
|
viewAsDict.SuppressEmptyRows || false,
|
|
222
209
|
viewAsDict.FormatString || "0.#########"
|
|
223
210
|
);
|
|
224
211
|
|
|
225
|
-
// Parse titles
|
|
226
212
|
if (viewAsDict.Titles) {
|
|
227
213
|
for (const titleDict of viewAsDict.Titles) {
|
|
228
|
-
|
|
229
|
-
|
|
214
|
+
if (!('Selected' in titleDict) && !('Selected@odata.bind' in titleDict)) {
|
|
215
|
+
throw new Error("View Title dict must contain 'Selected' or 'Selected@odata.bind' as key");
|
|
216
|
+
}
|
|
217
|
+
view.addTitle(ViewTitleSelection.fromDict(titleDict));
|
|
230
218
|
}
|
|
231
219
|
}
|
|
232
220
|
|
|
233
|
-
// Parse columns
|
|
234
221
|
if (viewAsDict.Columns) {
|
|
235
222
|
for (const columnDict of viewAsDict.Columns) {
|
|
236
|
-
|
|
237
|
-
view.addColumn(column);
|
|
223
|
+
view.addColumn(ViewAxisSelection.fromDict(columnDict));
|
|
238
224
|
}
|
|
239
225
|
}
|
|
240
226
|
|
|
241
|
-
// Parse rows
|
|
242
227
|
if (viewAsDict.Rows) {
|
|
243
228
|
for (const rowDict of viewAsDict.Rows) {
|
|
244
|
-
|
|
245
|
-
view.addRow(row);
|
|
229
|
+
view.addRow(ViewAxisSelection.fromDict(rowDict));
|
|
246
230
|
}
|
|
247
231
|
}
|
|
248
232
|
|
package/src/objects/Process.ts
CHANGED
|
@@ -15,7 +15,7 @@ export class Process extends TM1Object {
|
|
|
15
15
|
public static readonly MAX_STATEMENTS_POST_11_8_015 = 100_000;
|
|
16
16
|
|
|
17
17
|
private _name: string;
|
|
18
|
-
private _hasSecurityAccess: boolean;
|
|
18
|
+
private _hasSecurityAccess: boolean | undefined;
|
|
19
19
|
private _uiData: string;
|
|
20
20
|
private _parameters: any[];
|
|
21
21
|
private _variables: any[];
|
|
@@ -28,7 +28,7 @@ export class Process extends TM1Object {
|
|
|
28
28
|
private _datasourceAsciiDecimalSeparator: string;
|
|
29
29
|
private _datasourceAsciiDelimiterChar: string;
|
|
30
30
|
private _datasourceAsciiDelimiterType: string;
|
|
31
|
-
private _datasourceAsciiHeaderRecords: number;
|
|
31
|
+
private _datasourceAsciiHeaderRecords: number | string;
|
|
32
32
|
private _datasourceAsciiQuoteCharacter: string;
|
|
33
33
|
private _datasourceAsciiThousandSeparator: string;
|
|
34
34
|
private _datasourceDataSourceNameForClient: string;
|
|
@@ -36,7 +36,7 @@ export class Process extends TM1Object {
|
|
|
36
36
|
private _datasourcePassword: string;
|
|
37
37
|
private _datasourceUserName: string;
|
|
38
38
|
private _datasourceQuery: string;
|
|
39
|
-
private _datasourceUsesUnicode: boolean;
|
|
39
|
+
private _datasourceUsesUnicode: boolean | string;
|
|
40
40
|
private _datasourceView: string;
|
|
41
41
|
private _datasourceSubset: string;
|
|
42
42
|
private _datasourceJsonRootPointer: string;
|
|
@@ -60,7 +60,7 @@ export class Process extends TM1Object {
|
|
|
60
60
|
|
|
61
61
|
constructor(
|
|
62
62
|
name: string,
|
|
63
|
-
hasSecurityAccess: boolean = false,
|
|
63
|
+
hasSecurityAccess: boolean | undefined = false,
|
|
64
64
|
uiData: string = "CubeAction=1511\fDataAction=1503\fCubeLogChanges=0\f",
|
|
65
65
|
parameters?: Iterable<any>,
|
|
66
66
|
variables?: Iterable<any>,
|
|
@@ -73,7 +73,7 @@ export class Process extends TM1Object {
|
|
|
73
73
|
datasourceAsciiDecimalSeparator: string = '.',
|
|
74
74
|
datasourceAsciiDelimiterChar: string = ';',
|
|
75
75
|
datasourceAsciiDelimiterType: string = 'Character',
|
|
76
|
-
datasourceAsciiHeaderRecords: number = 1,
|
|
76
|
+
datasourceAsciiHeaderRecords: number | string = 1,
|
|
77
77
|
datasourceAsciiQuoteCharacter: string = '',
|
|
78
78
|
datasourceAsciiThousandSeparator: string = ',',
|
|
79
79
|
datasourceDataSourceNameForClient: string = '',
|
|
@@ -81,7 +81,7 @@ export class Process extends TM1Object {
|
|
|
81
81
|
datasourcePassword: string = '',
|
|
82
82
|
datasourceUserName: string = '',
|
|
83
83
|
datasourceQuery: string = '',
|
|
84
|
-
datasourceUsesUnicode: boolean = true,
|
|
84
|
+
datasourceUsesUnicode: boolean | string = true,
|
|
85
85
|
datasourceView: string = '',
|
|
86
86
|
datasourceSubset: string = '',
|
|
87
87
|
datasourceJsonRootPointer: string = '',
|
|
@@ -123,11 +123,18 @@ export class Process extends TM1Object {
|
|
|
123
123
|
this._uiData = uiData;
|
|
124
124
|
this._parameters = parameters ? Array.from(parameters) : [];
|
|
125
125
|
this._variables = variables ? Array.from(variables) : [];
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
if (variablesUiData) {
|
|
127
|
+
// Handle encoding issue in variable_ui_data for async requests
|
|
128
|
+
this._variablesUiData = Array.from(variablesUiData).map((entry: any) =>
|
|
129
|
+
typeof entry === 'string' ? entry.replace(/€/g, '\f') : entry
|
|
130
|
+
);
|
|
131
|
+
} else {
|
|
132
|
+
this._variablesUiData = [];
|
|
133
|
+
}
|
|
134
|
+
this._prologProcedure = Process.addGeneratedStringToCode(prologProcedure);
|
|
135
|
+
this._metadataProcedure = Process.addGeneratedStringToCode(metadataProcedure);
|
|
136
|
+
this._dataProcedure = Process.addGeneratedStringToCode(dataProcedure);
|
|
137
|
+
this._epilogProcedure = Process.addGeneratedStringToCode(epilogProcedure);
|
|
131
138
|
this._datasourceType = datasourceType;
|
|
132
139
|
this._datasourceAsciiDecimalSeparator = datasourceAsciiDecimalSeparator;
|
|
133
140
|
this._datasourceAsciiDelimiterChar = datasourceAsciiDelimiterChar;
|
|
@@ -155,11 +162,11 @@ export class Process extends TM1Object {
|
|
|
155
162
|
this._name = value;
|
|
156
163
|
}
|
|
157
164
|
|
|
158
|
-
public get hasSecurityAccess(): boolean {
|
|
165
|
+
public get hasSecurityAccess(): boolean | undefined {
|
|
159
166
|
return this._hasSecurityAccess;
|
|
160
167
|
}
|
|
161
168
|
|
|
162
|
-
public set hasSecurityAccess(value: boolean) {
|
|
169
|
+
public set hasSecurityAccess(value: boolean | undefined) {
|
|
163
170
|
this._hasSecurityAccess = value;
|
|
164
171
|
}
|
|
165
172
|
|
|
@@ -241,37 +248,110 @@ export class Process extends TM1Object {
|
|
|
241
248
|
* :param process_as_dict: process as dict
|
|
242
249
|
* :return: process, an instance of this class
|
|
243
250
|
*/
|
|
251
|
+
const ds = processAsDict['DataSource'] ?? {};
|
|
244
252
|
return new Process(
|
|
245
|
-
processAsDict
|
|
246
|
-
processAsDict
|
|
247
|
-
processAsDict
|
|
248
|
-
processAsDict
|
|
249
|
-
processAsDict
|
|
250
|
-
processAsDict
|
|
251
|
-
processAsDict
|
|
252
|
-
processAsDict
|
|
253
|
-
processAsDict
|
|
254
|
-
processAsDict
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
253
|
+
processAsDict['Name'],
|
|
254
|
+
processAsDict['HasSecurityAccess'],
|
|
255
|
+
processAsDict['UIData'] ?? '',
|
|
256
|
+
processAsDict['Parameters'],
|
|
257
|
+
processAsDict['Variables'],
|
|
258
|
+
processAsDict['VariablesUIData'] ?? '',
|
|
259
|
+
processAsDict['PrologProcedure'],
|
|
260
|
+
processAsDict['MetadataProcedure'],
|
|
261
|
+
processAsDict['DataProcedure'],
|
|
262
|
+
processAsDict['EpilogProcedure'],
|
|
263
|
+
ds['Type'] ?? '',
|
|
264
|
+
ds['asciiDecimalSeparator'] ?? '',
|
|
265
|
+
ds['asciiDelimiterChar'] ?? '',
|
|
266
|
+
ds['asciiDelimiterType'] ?? '',
|
|
267
|
+
ds['asciiHeaderRecords'] ?? '',
|
|
268
|
+
ds['asciiQuoteCharacter'] ?? '',
|
|
269
|
+
ds['asciiThousandSeparator'] ?? '',
|
|
270
|
+
ds['dataSourceNameForClient'] ?? '',
|
|
271
|
+
ds['dataSourceNameForServer'] ?? '',
|
|
272
|
+
ds['password'] ?? '',
|
|
273
|
+
ds['userName'] ?? '',
|
|
274
|
+
ds['query'] ?? '',
|
|
275
|
+
ds['usesUnicode'] ?? '',
|
|
276
|
+
ds['view'] ?? '',
|
|
277
|
+
ds['subset'] ?? '',
|
|
278
|
+
ds['jsonRootPointer'] ?? '',
|
|
279
|
+
ds['jsonVariableMapping'] ?? ''
|
|
272
280
|
);
|
|
273
281
|
}
|
|
274
282
|
|
|
283
|
+
public addVariable(name: string, variableType: string): void {
|
|
284
|
+
// variable consists of actual variable and UI-Information ('ignore','other', etc.)
|
|
285
|
+
// 1. handle Variable info
|
|
286
|
+
const variable = {
|
|
287
|
+
Name: name,
|
|
288
|
+
Type: variableType,
|
|
289
|
+
Position: this._variables.length + 1,
|
|
290
|
+
StartByte: 0,
|
|
291
|
+
EndByte: 0,
|
|
292
|
+
};
|
|
293
|
+
this._variables.push(variable);
|
|
294
|
+
// 2. handle UI info
|
|
295
|
+
const varType = variableType === 'Numeric' ? 33 : 32;
|
|
296
|
+
// '\f' !
|
|
297
|
+
const variableUiData = 'VarType=' + varType + '\f' + 'ColType=' + 827 + '\f';
|
|
298
|
+
/*
|
|
299
|
+
* mapping VariableUIData:
|
|
300
|
+
* VarType 33 -> Numeric
|
|
301
|
+
* VarType 32 -> String
|
|
302
|
+
* ColType 827 -> Other
|
|
303
|
+
*/
|
|
304
|
+
this._variablesUiData.push(variableUiData);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
public removeVariable(name: string): void {
|
|
308
|
+
for (const variable of this._variables.slice()) {
|
|
309
|
+
if (variable['Name'] === name) {
|
|
310
|
+
const vuid = this._variablesUiData[this._variables.indexOf(variable)];
|
|
311
|
+
const vuidIdx = this._variablesUiData.indexOf(vuid);
|
|
312
|
+
if (vuidIdx !== -1) {
|
|
313
|
+
this._variablesUiData.splice(vuidIdx, 1);
|
|
314
|
+
}
|
|
315
|
+
const varIdx = this._variables.indexOf(variable);
|
|
316
|
+
if (varIdx !== -1) {
|
|
317
|
+
this._variables.splice(varIdx, 1);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
public addParameter(
|
|
324
|
+
name: string,
|
|
325
|
+
prompt: string,
|
|
326
|
+
value: string | number,
|
|
327
|
+
parameterType?: string
|
|
328
|
+
): void {
|
|
329
|
+
if (!parameterType) {
|
|
330
|
+
parameterType = typeof value === 'string' ? 'String' : 'Numeric';
|
|
331
|
+
}
|
|
332
|
+
const parameter = { Name: name, Prompt: prompt, Value: value, Type: parameterType };
|
|
333
|
+
this._parameters.push(parameter);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
public removeParameter(name: string): void {
|
|
337
|
+
for (const parameter of this._parameters.slice()) {
|
|
338
|
+
if (parameter['Name'] === name) {
|
|
339
|
+
const idx = this._parameters.indexOf(parameter);
|
|
340
|
+
if (idx !== -1) {
|
|
341
|
+
this._parameters.splice(idx, 1);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
public dropParameterTypes(): void {
|
|
348
|
+
for (let p = 0; p < this._parameters.length; p++) {
|
|
349
|
+
if ('Type' in this._parameters[p]) {
|
|
350
|
+
delete this._parameters[p]['Type'];
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
275
355
|
public get body(): string {
|
|
276
356
|
return JSON.stringify(this.constructBody());
|
|
277
357
|
}
|
|
@@ -281,40 +361,76 @@ export class Process extends TM1Object {
|
|
|
281
361
|
}
|
|
282
362
|
|
|
283
363
|
private constructBody(): any {
|
|
284
|
-
|
|
364
|
+
// general parameters — key order matches tm1py _construct_body_as_dict
|
|
365
|
+
const bodyAsDict: any = {
|
|
285
366
|
Name: this._name,
|
|
367
|
+
PrologProcedure: this._prologProcedure,
|
|
368
|
+
MetadataProcedure: this._metadataProcedure,
|
|
369
|
+
DataProcedure: this._dataProcedure,
|
|
370
|
+
EpilogProcedure: this._epilogProcedure,
|
|
286
371
|
HasSecurityAccess: this._hasSecurityAccess,
|
|
287
372
|
UIData: this._uiData,
|
|
373
|
+
DataSource: {},
|
|
288
374
|
Parameters: this._parameters,
|
|
289
375
|
Variables: this._variables,
|
|
290
376
|
VariablesUIData: this._variablesUiData,
|
|
291
|
-
PrologProcedure: this._prologProcedure,
|
|
292
|
-
MetadataProcedure: this._metadataProcedure,
|
|
293
|
-
DataProcedure: this._dataProcedure,
|
|
294
|
-
EpilogProcedure: this._epilogProcedure
|
|
295
377
|
};
|
|
296
378
|
|
|
297
|
-
//
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
379
|
+
// specific parameters (depending on datasource type)
|
|
380
|
+
if (this._datasourceType === 'ASCII') {
|
|
381
|
+
bodyAsDict['DataSource'] = {
|
|
382
|
+
Type: this._datasourceType,
|
|
383
|
+
asciiDecimalSeparator: this._datasourceAsciiDecimalSeparator,
|
|
384
|
+
asciiDelimiterChar: this._datasourceAsciiDelimiterChar,
|
|
385
|
+
asciiDelimiterType: this._datasourceAsciiDelimiterType,
|
|
386
|
+
asciiHeaderRecords: this._datasourceAsciiHeaderRecords,
|
|
387
|
+
asciiQuoteCharacter: this._datasourceAsciiQuoteCharacter,
|
|
388
|
+
asciiThousandSeparator: this._datasourceAsciiThousandSeparator,
|
|
389
|
+
dataSourceNameForClient: this._datasourceDataSourceNameForClient,
|
|
390
|
+
dataSourceNameForServer: this._datasourceDataSourceNameForServer,
|
|
391
|
+
};
|
|
392
|
+
if (this._datasourceAsciiDelimiterType === 'FixedWidth') {
|
|
393
|
+
delete bodyAsDict['DataSource']['asciiDelimiterChar'];
|
|
394
|
+
}
|
|
395
|
+
} else if (this._datasourceType === 'None') {
|
|
396
|
+
bodyAsDict['DataSource'] = { Type: 'None' };
|
|
397
|
+
} else if (this._datasourceType === 'ODBC') {
|
|
398
|
+
bodyAsDict['DataSource'] = {
|
|
399
|
+
Type: this._datasourceType,
|
|
400
|
+
dataSourceNameForClient: this._datasourceDataSourceNameForClient,
|
|
401
|
+
dataSourceNameForServer: this._datasourceDataSourceNameForServer,
|
|
402
|
+
userName: this._datasourceUserName,
|
|
403
|
+
password: this._datasourcePassword,
|
|
404
|
+
query: this._datasourceQuery,
|
|
405
|
+
usesUnicode: this._datasourceUsesUnicode,
|
|
406
|
+
};
|
|
407
|
+
} else if (this._datasourceType === 'TM1CubeView') {
|
|
408
|
+
bodyAsDict['DataSource'] = {
|
|
409
|
+
Type: this._datasourceType,
|
|
410
|
+
// Note: tm1py uses _datasource_data_source_name_for_server for BOTH client and server
|
|
411
|
+
dataSourceNameForClient: this._datasourceDataSourceNameForServer,
|
|
412
|
+
dataSourceNameForServer: this._datasourceDataSourceNameForServer,
|
|
413
|
+
view: this._datasourceView,
|
|
414
|
+
};
|
|
415
|
+
} else if (this._datasourceType === 'TM1DimensionSubset') {
|
|
416
|
+
bodyAsDict['DataSource'] = {
|
|
417
|
+
Type: this._datasourceType,
|
|
418
|
+
// Note: tm1py uses _datasource_data_source_name_for_server for BOTH client and server
|
|
419
|
+
dataSourceNameForClient: this._datasourceDataSourceNameForServer,
|
|
420
|
+
dataSourceNameForServer: this._datasourceDataSourceNameForServer,
|
|
421
|
+
subset: this._datasourceSubset,
|
|
422
|
+
};
|
|
423
|
+
} else if (this._datasourceType === 'JSON') {
|
|
424
|
+
bodyAsDict['DataSource'] = {
|
|
425
|
+
Type: this._datasourceType,
|
|
426
|
+
// Note: tm1py uses _datasource_data_source_name_for_server for BOTH client and server
|
|
427
|
+
dataSourceNameForClient: this._datasourceDataSourceNameForServer,
|
|
428
|
+
dataSourceNameForServer: this._datasourceDataSourceNameForServer,
|
|
429
|
+
jsonRootPointer: this._datasourceJsonRootPointer,
|
|
430
|
+
jsonVariableMapping: this._datasourceJsonVariableMapping,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
317
433
|
|
|
318
|
-
return
|
|
434
|
+
return bodyAsDict;
|
|
319
435
|
}
|
|
320
436
|
}
|
package/src/objects/Subset.ts
CHANGED
|
@@ -240,14 +240,28 @@ export class AnonymousSubset extends Subset {
|
|
|
240
240
|
} else if ("Hierarchy@odata.bind" in subsetAsDict) {
|
|
241
241
|
const hierarchyOdata = subsetAsDict["Hierarchy@odata.bind"];
|
|
242
242
|
|
|
243
|
-
|
|
244
|
-
|
|
243
|
+
// tm1py parity (TM1py/Objects/Subset.py): two read_object_name_from_url
|
|
244
|
+
// calls with these exact regex patterns. Both return match.group(1) (the
|
|
245
|
+
// first capture group), so both names resolve to the dimension. This
|
|
246
|
+
// mirrors tm1py's behavior — including the latent bug where a non-default
|
|
247
|
+
// hierarchy name in the URL is dropped. Do NOT "fix" without tm1py.
|
|
248
|
+
const dimResult = readObjectNameFromUrl(
|
|
249
|
+
hierarchyOdata,
|
|
250
|
+
/^Dimensions\('(.*?)'\)\/Hierarchies\('(.+?)'\)/
|
|
251
|
+
);
|
|
252
|
+
const hierResult = readObjectNameFromUrl(
|
|
253
|
+
hierarchyOdata,
|
|
254
|
+
/^Dimensions\('(.+?)'\)\/Hierarchies\('(.*?)'\)/
|
|
255
|
+
);
|
|
245
256
|
|
|
246
|
-
if (!
|
|
257
|
+
if (!dimResult || !hierResult) {
|
|
247
258
|
throw new Error(
|
|
248
259
|
`Unexpected value for 'Hierarchy@odata.bind' property in subset dict: '${hierarchyOdata}'`
|
|
249
260
|
);
|
|
250
261
|
}
|
|
262
|
+
|
|
263
|
+
dimensionName = dimResult;
|
|
264
|
+
hierarchyName = hierResult;
|
|
251
265
|
} else {
|
|
252
266
|
throw new Error("Subset dict must contain 'Hierarchy' or 'Hierarchy@odata.bind' as key");
|
|
253
267
|
}
|
package/src/objects/User.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { TM1Object } from './TM1Object';
|
|
2
|
-
import { CaseAndSpaceInsensitiveSet, formatUrl } from '../utils/Utils';
|
|
2
|
+
import { CaseAndSpaceInsensitiveSet, formatUrl, lowerAndDropSpaces } from '../utils/Utils';
|
|
3
3
|
|
|
4
4
|
export enum UserType {
|
|
5
|
-
User =
|
|
6
|
-
SecurityAdmin =
|
|
7
|
-
DataAdmin =
|
|
8
|
-
Admin =
|
|
9
|
-
OperationsAdmin =
|
|
5
|
+
User = 'User',
|
|
6
|
+
SecurityAdmin = 'SecurityAdmin',
|
|
7
|
+
DataAdmin = 'DataAdmin',
|
|
8
|
+
Admin = 'Admin',
|
|
9
|
+
OperationsAdmin = 'OperationsAdmin'
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
const USER_TYPE_LOOKUP = new Map<string, UserType>(
|
|
13
|
+
Object.entries(UserType).map(([k, v]) => [k.toLowerCase(), v as UserType])
|
|
14
|
+
);
|
|
15
|
+
|
|
12
16
|
export class User extends TM1Object {
|
|
13
17
|
/** Abstraction of a TM1 User
|
|
14
18
|
*
|
|
@@ -70,25 +74,15 @@ export class User extends TM1Object {
|
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
public set userType(value: UserType | string) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
for (const [key, enumValue] of Object.entries(UserType)) {
|
|
77
|
-
if (key.toLowerCase() === lowerValue) {
|
|
78
|
-
this._userType = enumValue as UserType;
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
if (this._userType === undefined) {
|
|
83
|
-
throw new Error(`Invalid element type=${value}`);
|
|
84
|
-
}
|
|
85
|
-
} else {
|
|
86
|
-
this._userType = value;
|
|
77
|
+
const resolved = USER_TYPE_LOOKUP.get(lowerAndDropSpaces(value));
|
|
78
|
+
if (resolved === undefined) {
|
|
79
|
+
throw new Error(`Invalid user type=${value}`);
|
|
87
80
|
}
|
|
81
|
+
this._userType = resolved;
|
|
88
82
|
|
|
89
83
|
// update groups as well, since TM1 doesn't react to change in user_type property
|
|
90
84
|
if (this._userType !== UserType.User) {
|
|
91
|
-
this.addGroup(this._userType
|
|
85
|
+
this.addGroup(this._userType);
|
|
92
86
|
}
|
|
93
87
|
}
|
|
94
88
|
|
|
@@ -109,7 +103,7 @@ export class User extends TM1Object {
|
|
|
109
103
|
}
|
|
110
104
|
|
|
111
105
|
public get isAdmin(): boolean {
|
|
112
|
-
return this._groups.has("
|
|
106
|
+
return this._groups.has("Admin");
|
|
113
107
|
}
|
|
114
108
|
|
|
115
109
|
public get isDataAdmin(): boolean {
|
|
@@ -165,7 +159,7 @@ export class User extends TM1Object {
|
|
|
165
159
|
userAsDict.Groups.map((group: any) => group.Name),
|
|
166
160
|
userAsDict.FriendlyName,
|
|
167
161
|
undefined, // password not included in dict
|
|
168
|
-
userAsDict.Type,
|
|
162
|
+
userAsDict.Type ?? undefined,
|
|
169
163
|
userAsDict.Enabled
|
|
170
164
|
);
|
|
171
165
|
}
|
|
@@ -370,7 +370,9 @@ describe('DebuggerService and Enhanced Process Debugging (Issue #13)', () => {
|
|
|
370
370
|
expect(plan.hasVariables).toBe(true);
|
|
371
371
|
expect(plan.variableCount).toBe(1);
|
|
372
372
|
expect(plan.procedures.hasPrologProcedure).toBe(true);
|
|
373
|
-
|
|
373
|
+
// addGeneratedStringToCode prepends ~73 chars to each procedure tab,
|
|
374
|
+
// so actual total exceeds 2000 → 'High'
|
|
375
|
+
expect(plan.estimatedComplexity).toBe('High');
|
|
374
376
|
});
|
|
375
377
|
});
|
|
376
378
|
});
|