tm1npm 1.6.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/lib/objects/Axis.d.ts +1 -0
  3. package/lib/objects/Axis.d.ts.map +1 -1
  4. package/lib/objects/Axis.js +3 -0
  5. package/lib/objects/Chore.d.ts +2 -2
  6. package/lib/objects/Chore.d.ts.map +1 -1
  7. package/lib/objects/Chore.js +7 -13
  8. package/lib/objects/Cube.d.ts.map +1 -1
  9. package/lib/objects/Cube.js +2 -1
  10. package/lib/objects/Hierarchy.js +10 -10
  11. package/lib/objects/MDXView.d.ts +2 -0
  12. package/lib/objects/MDXView.d.ts.map +1 -1
  13. package/lib/objects/MDXView.js +30 -9
  14. package/lib/objects/NativeView.d.ts +5 -5
  15. package/lib/objects/NativeView.d.ts.map +1 -1
  16. package/lib/objects/NativeView.js +17 -34
  17. package/lib/objects/Process.d.ts +8 -3
  18. package/lib/objects/Process.d.ts.map +1 -1
  19. package/lib/objects/Process.js +143 -33
  20. package/lib/objects/Subset.d.ts.map +1 -1
  21. package/lib/objects/Subset.js +10 -3
  22. package/lib/objects/User.d.ts +5 -5
  23. package/lib/objects/User.d.ts.map +1 -1
  24. package/lib/objects/User.js +14 -23
  25. package/lib/services/ApplicationService.d.ts.map +1 -1
  26. package/lib/services/AsyncOperationService.d.ts +8 -1
  27. package/lib/services/AsyncOperationService.d.ts.map +1 -1
  28. package/lib/services/AsyncOperationService.js +69 -26
  29. package/lib/services/FileService.d.ts.map +1 -1
  30. package/lib/services/ProcessService.d.ts +18 -13
  31. package/lib/services/ProcessService.d.ts.map +1 -1
  32. package/lib/services/ProcessService.js +28 -17
  33. package/lib/services/RestService.d.ts +213 -25
  34. package/lib/services/RestService.d.ts.map +1 -1
  35. package/lib/services/RestService.js +840 -271
  36. package/lib/services/TM1Service.d.ts +42 -1
  37. package/lib/services/TM1Service.d.ts.map +1 -1
  38. package/lib/services/TM1Service.js +94 -4
  39. package/lib/tests/asyncOperationService.test.js +51 -45
  40. package/lib/tests/debuggerService.test.js +3 -1
  41. package/lib/tests/objectModelParity.test.js +362 -11
  42. package/lib/tests/objects.improved.test.js +28 -5
  43. package/lib/tests/processService.comprehensive.test.js +2 -2
  44. package/lib/tests/processService.test.js +20 -6
  45. package/lib/tests/restService.test.d.ts +0 -4
  46. package/lib/tests/restService.test.d.ts.map +1 -1
  47. package/lib/tests/restService.test.js +1558 -143
  48. package/lib/tests/tm1Service.test.js +80 -8
  49. package/lib/tests/user.issue61.test.d.ts +2 -0
  50. package/lib/tests/user.issue61.test.d.ts.map +1 -0
  51. package/lib/tests/user.issue61.test.js +180 -0
  52. package/lib/utils/Utils.d.ts +6 -1
  53. package/lib/utils/Utils.d.ts.map +1 -1
  54. package/lib/utils/Utils.js +56 -7
  55. package/package.json +1 -1
  56. package/src/objects/Axis.ts +4 -0
  57. package/src/objects/Chore.ts +7 -14
  58. package/src/objects/Cube.ts +2 -1
  59. package/src/objects/Hierarchy.ts +11 -11
  60. package/src/objects/MDXView.ts +29 -9
  61. package/src/objects/NativeView.ts +26 -42
  62. package/src/objects/Process.ts +182 -66
  63. package/src/objects/Subset.ts +17 -3
  64. package/src/objects/User.ts +17 -23
  65. package/src/services/ApplicationService.ts +4 -4
  66. package/src/services/AsyncOperationService.ts +76 -29
  67. package/src/services/FileService.ts +3 -3
  68. package/src/services/ProcessService.ts +67 -37
  69. package/src/services/RestService.ts +1020 -278
  70. package/src/services/TM1Service.ts +124 -6
  71. package/src/tests/asyncOperationService.test.ts +52 -48
  72. package/src/tests/debuggerService.test.ts +3 -1
  73. package/src/tests/objectModelParity.test.ts +456 -11
  74. package/src/tests/objects.improved.test.ts +41 -9
  75. package/src/tests/processService.comprehensive.test.ts +3 -3
  76. package/src/tests/processService.test.ts +21 -9
  77. package/src/tests/restService.test.ts +1844 -139
  78. package/src/tests/tm1Service.test.ts +95 -11
  79. package/src/tests/user.issue61.test.ts +206 -0
  80. package/src/utils/Utils.ts +60 -7
@@ -7,6 +7,7 @@
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
8
  const TM1Service_1 = require("../services/TM1Service");
9
9
  const RestService_1 = require("../services/RestService");
10
+ const User_1 = require("../objects/User");
10
11
  // Mock all service dependencies
11
12
  jest.mock('../services/RestService');
12
13
  jest.mock('../services/DimensionService');
@@ -22,6 +23,19 @@ jest.mock('../services/FileService');
22
23
  jest.mock('../services/SessionService');
23
24
  jest.mock('../services/ServerService');
24
25
  jest.mock('../services/MonitoringService');
26
+ jest.mock('../services/AnnotationService');
27
+ jest.mock('../services/ChoreService');
28
+ jest.mock('../services/GitService');
29
+ jest.mock('../services/ApplicationService');
30
+ jest.mock('../services/SandboxService');
31
+ jest.mock('../services/JobService');
32
+ jest.mock('../services/UserService');
33
+ jest.mock('../services/ThreadService');
34
+ jest.mock('../services/TransactionLogService');
35
+ jest.mock('../services/MessageLogService');
36
+ jest.mock('../services/ConfigurationService');
37
+ jest.mock('../services/AuditLogService');
38
+ jest.mock('../services/LoggerService');
25
39
  describe('TM1Service', () => {
26
40
  let tm1Service;
27
41
  let mockRestService;
@@ -56,6 +70,8 @@ describe('TM1Service', () => {
56
70
  setSandbox: jest.fn(),
57
71
  getSandbox: jest.fn().mockReturnValue('test-sandbox'),
58
72
  isLoggedIn: jest.fn().mockReturnValue(true),
73
+ getVersion: jest.fn().mockResolvedValue('12.0.0'),
74
+ version: undefined,
59
75
  };
60
76
  // Mock RestService constructor
61
77
  RestService_1.RestService.mockImplementation(() => mockRestService);
@@ -75,6 +91,7 @@ describe('TM1Service', () => {
75
91
  expect(tm1Service.security).toBeDefined();
76
92
  expect(tm1Service.files).toBeDefined();
77
93
  expect(tm1Service.sessions).toBeDefined();
94
+ expect(tm1Service.applications).toBeDefined();
78
95
  });
79
96
  test('should create RestService with provided config', () => {
80
97
  expect(RestService_1.RestService).toHaveBeenCalledWith(mockConfig);
@@ -123,14 +140,16 @@ describe('TM1Service', () => {
123
140
  });
124
141
  });
125
142
  describe('User and Authentication', () => {
126
- test('should get current user with whoami', async () => {
127
- // Mock security service getCurrentUser method
143
+ test('should get current user as User object with whoami', async () => {
144
+ const expectedUser = new User_1.User('test-user', ['ADMIN'], 'Test User', undefined, User_1.UserType.Admin, true);
128
145
  const mockSecurityService = {
129
- getCurrentUser: jest.fn().mockResolvedValue({ name: 'test-user' })
146
+ getCurrentUser: jest.fn().mockResolvedValue(expectedUser)
130
147
  };
131
148
  tm1Service.security = mockSecurityService;
132
149
  const result = await tm1Service.whoami();
133
- expect(result).toBe('test-user');
150
+ expect(result).toBeInstanceOf(User_1.User);
151
+ expect(result.name).toBe('test-user');
152
+ expect(result).toBe(expectedUser);
134
153
  expect(mockSecurityService.getCurrentUser).toHaveBeenCalledTimes(1);
135
154
  });
136
155
  test('should check if user is logged in', () => {
@@ -157,11 +176,11 @@ describe('TM1Service', () => {
157
176
  expect(result).toEqual({ metadata: 'test-metadata' });
158
177
  expect(mockRestService.get).toHaveBeenCalledWith('/$metadata');
159
178
  });
160
- test('should get TM1 version', async () => {
161
- mockRestService.get.mockResolvedValueOnce(mockResponse({ value: '12.0.0' }));
179
+ test('should get TM1 version via cached RestService.getVersion', async () => {
180
+ mockRestService.getVersion.mockResolvedValueOnce('12.0.0');
162
181
  const result = await tm1Service.getVersion();
163
182
  expect(result).toBe('12.0.0');
164
- expect(mockRestService.get).toHaveBeenCalledWith('/Configuration/ProductVersion');
183
+ expect(mockRestService.getVersion).toHaveBeenCalledTimes(1);
165
184
  });
166
185
  test('should handle metadata retrieval errors', async () => {
167
186
  const metadataError = new Error('Metadata not available');
@@ -170,7 +189,7 @@ describe('TM1Service', () => {
170
189
  });
171
190
  test('should handle version retrieval errors', async () => {
172
191
  const versionError = new Error('Version not available');
173
- mockRestService.get.mockRejectedValueOnce(versionError);
192
+ mockRestService.getVersion.mockRejectedValueOnce(versionError);
174
193
  await expect(tm1Service.getVersion()).rejects.toThrow('Version not available');
175
194
  });
176
195
  });
@@ -286,5 +305,58 @@ describe('TM1Service', () => {
286
305
  expect(monitoring1).toBe(monitoring2);
287
306
  });
288
307
  });
308
+ describe('Lazy Services (Issue #82)', () => {
309
+ const lazyServiceNames = [
310
+ 'annotations',
311
+ 'chores',
312
+ 'git',
313
+ 'sandboxes',
314
+ 'jobs',
315
+ 'users',
316
+ 'threads',
317
+ 'transactionLogs',
318
+ 'messageLogs',
319
+ 'configuration',
320
+ 'auditLogs',
321
+ 'loggers',
322
+ ];
323
+ test.each(lazyServiceNames)('should lazy-initialize %s service', (serviceName) => {
324
+ const instance = tm1Service[serviceName];
325
+ expect(instance).toBeDefined();
326
+ });
327
+ test.each(lazyServiceNames)('should cache %s service instance across accesses', (serviceName) => {
328
+ const first = tm1Service[serviceName];
329
+ const second = tm1Service[serviceName];
330
+ expect(second).toBe(first);
331
+ });
332
+ });
333
+ describe('Version Getter (Issue #82)', () => {
334
+ test('should expose cached version via sync getter', () => {
335
+ Object.defineProperty(mockRestService, 'version', {
336
+ get: () => '11.8.0',
337
+ configurable: true,
338
+ });
339
+ expect(tm1Service.version).toBe('11.8.0');
340
+ });
341
+ test('should return undefined when version has not been fetched yet', () => {
342
+ Object.defineProperty(mockRestService, 'version', {
343
+ get: () => undefined,
344
+ configurable: true,
345
+ });
346
+ expect(tm1Service.version).toBeUndefined();
347
+ });
348
+ });
349
+ describe('reConnect (Issue #82)', () => {
350
+ test('should call connect without disconnecting (tm1py parity)', async () => {
351
+ await tm1Service.reConnect();
352
+ expect(mockRestService.connect).toHaveBeenCalledTimes(1);
353
+ expect(mockRestService.disconnect).not.toHaveBeenCalled();
354
+ });
355
+ test('should propagate errors from connect', async () => {
356
+ mockRestService.connect.mockRejectedValueOnce(new Error('Connect failed'));
357
+ await expect(tm1Service.reConnect()).rejects.toThrow('Connect failed');
358
+ expect(mockRestService.connect).toHaveBeenCalledTimes(1);
359
+ });
360
+ });
289
361
  });
290
362
  //# sourceMappingURL=tm1Service.test.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=user.issue61.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.issue61.test.d.ts","sourceRoot":"","sources":["../../src/tests/user.issue61.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const User_1 = require("../objects/User");
4
+ const Utils_1 = require("../utils/Utils");
5
+ describe('UserType — string enum (issue #61)', () => {
6
+ test('should produce correct string names from toString()', () => {
7
+ expect(User_1.UserType.User.toString()).toBe('User');
8
+ expect(User_1.UserType.SecurityAdmin.toString()).toBe('SecurityAdmin');
9
+ expect(User_1.UserType.DataAdmin.toString()).toBe('DataAdmin');
10
+ expect(User_1.UserType.Admin.toString()).toBe('Admin');
11
+ expect(User_1.UserType.OperationsAdmin.toString()).toBe('OperationsAdmin');
12
+ });
13
+ test('should serialize Type field as string name in body', () => {
14
+ const user = new User_1.User('Alice', [], undefined, undefined, User_1.UserType.Admin);
15
+ const body = JSON.parse(user.body);
16
+ expect(body.Type).toBe('Admin');
17
+ });
18
+ test('should serialize User type as "User" string in body', () => {
19
+ const user = new User_1.User('Alice', []);
20
+ const body = JSON.parse(user.body);
21
+ expect(body.Type).toBe('User');
22
+ });
23
+ test('should parse string value in userType setter', () => {
24
+ const user = new User_1.User('Alice', []);
25
+ user.userType = 'Admin';
26
+ expect(user.userType).toBe(User_1.UserType.Admin);
27
+ });
28
+ test('should parse case-insensitive string in userType setter', () => {
29
+ const user = new User_1.User('Alice', []);
30
+ user.userType = 'admin';
31
+ expect(user.userType).toBe(User_1.UserType.Admin);
32
+ });
33
+ test('should throw on invalid userType string', () => {
34
+ const user = new User_1.User('Alice', []);
35
+ expect(() => { user.userType = 'InvalidType'; }).toThrow();
36
+ });
37
+ });
38
+ describe('User — group auto-detection (issue #61)', () => {
39
+ test('should detect Admin type from groups', () => {
40
+ const user = new User_1.User('Alice', ['Admin']);
41
+ expect(user.userType).toBe(User_1.UserType.Admin);
42
+ });
43
+ test('should detect SecurityAdmin type from groups', () => {
44
+ const user = new User_1.User('Alice', ['SecurityAdmin']);
45
+ expect(user.userType).toBe(User_1.UserType.SecurityAdmin);
46
+ });
47
+ test('should detect DataAdmin type from groups', () => {
48
+ const user = new User_1.User('Alice', ['DataAdmin']);
49
+ expect(user.userType).toBe(User_1.UserType.DataAdmin);
50
+ });
51
+ test('should detect OperationsAdmin type from groups', () => {
52
+ const user = new User_1.User('Alice', ['OperationsAdmin']);
53
+ expect(user.userType).toBe(User_1.UserType.OperationsAdmin);
54
+ });
55
+ test('should default to User type when no special groups present', () => {
56
+ const user = new User_1.User('Alice', ['Everyone', 'SomeTeam']);
57
+ expect(user.userType).toBe(User_1.UserType.User);
58
+ });
59
+ test('should add correct string group when userType set to Admin', () => {
60
+ const user = new User_1.User('Alice', []);
61
+ user.userType = User_1.UserType.Admin;
62
+ expect(user.groups).toContain('Admin');
63
+ });
64
+ test('should not add a group when userType set to User', () => {
65
+ const user = new User_1.User('Alice', []);
66
+ user.userType = User_1.UserType.User;
67
+ expect(user.groups).toHaveLength(0);
68
+ });
69
+ });
70
+ describe('User — isXxxAdmin getters (issue #61)', () => {
71
+ test('should return true for isAdmin when Admin group present', () => {
72
+ const user = new User_1.User('Alice', ['Admin']);
73
+ expect(user.isAdmin).toBe(true);
74
+ });
75
+ test('should return false for isAdmin when Admin group absent', () => {
76
+ const user = new User_1.User('Alice', ['Everyone']);
77
+ expect(user.isAdmin).toBe(false);
78
+ });
79
+ test('should return true for isDataAdmin when Admin group present', () => {
80
+ const user = new User_1.User('Alice', ['Admin']);
81
+ expect(user.isDataAdmin).toBe(true);
82
+ });
83
+ test('should return true for isDataAdmin when DataAdmin group present', () => {
84
+ const user = new User_1.User('Alice', ['DataAdmin']);
85
+ expect(user.isDataAdmin).toBe(true);
86
+ });
87
+ test('should return true for isSecurityAdmin when SecurityAdmin group present', () => {
88
+ const user = new User_1.User('Alice', ['SecurityAdmin']);
89
+ expect(user.isSecurityAdmin).toBe(true);
90
+ });
91
+ test('should return true for isOpsAdmin when OperationsAdmin group present', () => {
92
+ const user = new User_1.User('Alice', ['OperationsAdmin']);
93
+ expect(user.isOpsAdmin).toBe(true);
94
+ });
95
+ });
96
+ describe('User.fromDict — Type field parsing (issue #61)', () => {
97
+ test('should parse Type string field from API response dict', () => {
98
+ const dict = {
99
+ Name: 'Alice',
100
+ FriendlyName: 'Alice',
101
+ Groups: [{ Name: 'Admin' }],
102
+ Type: 'Admin',
103
+ Enabled: true,
104
+ };
105
+ const user = User_1.User.fromDict(dict);
106
+ expect(user.userType).toBe(User_1.UserType.Admin);
107
+ });
108
+ test('should parse SecurityAdmin Type field from API response dict', () => {
109
+ const dict = {
110
+ Name: 'Bob',
111
+ FriendlyName: 'Bob',
112
+ Groups: [{ Name: 'SecurityAdmin' }],
113
+ Type: 'SecurityAdmin',
114
+ Enabled: true,
115
+ };
116
+ const user = User_1.User.fromDict(dict);
117
+ expect(user.userType).toBe(User_1.UserType.SecurityAdmin);
118
+ });
119
+ });
120
+ describe('CaseAndSpaceInsensitiveSet — casing preservation (issue #61)', () => {
121
+ test('should preserve original casing of first insertion', () => {
122
+ const set = new Utils_1.CaseAndSpaceInsensitiveSet();
123
+ set.add('Admin');
124
+ set.add('ADMIN');
125
+ set.add('admin');
126
+ expect(set.size).toBe(1);
127
+ expect(Array.from(set)).toEqual(['Admin']);
128
+ });
129
+ test('should find by any casing variant', () => {
130
+ const set = new Utils_1.CaseAndSpaceInsensitiveSet();
131
+ set.add('HelloWorld');
132
+ expect(set.has('helloworld')).toBe(true);
133
+ expect(set.has('HELLOWORLD')).toBe(true);
134
+ expect(set.has('Hello World')).toBe(true);
135
+ expect(set.has('hello world')).toBe(true);
136
+ });
137
+ test('should return first-inserted casing during iteration', () => {
138
+ const set = new Utils_1.CaseAndSpaceInsensitiveSet();
139
+ set.add('MyGroup');
140
+ set.add('mygroup');
141
+ set.add('MYGROUP');
142
+ expect(Array.from(set)).toEqual(['MyGroup']);
143
+ });
144
+ test('should delete by any casing variant', () => {
145
+ const set = new Utils_1.CaseAndSpaceInsensitiveSet();
146
+ set.add('Admin');
147
+ expect(set.delete('ADMIN')).toBe(true);
148
+ expect(set.size).toBe(0);
149
+ expect(set.has('Admin')).toBe(false);
150
+ });
151
+ test('should return false when deleting non-existent entry', () => {
152
+ const set = new Utils_1.CaseAndSpaceInsensitiveSet();
153
+ expect(set.delete('NonExistent')).toBe(false);
154
+ });
155
+ test('should maintain correct size after operations', () => {
156
+ const set = new Utils_1.CaseAndSpaceInsensitiveSet();
157
+ set.add('A');
158
+ set.add('B');
159
+ set.add('a'); // duplicate — ignored
160
+ expect(set.size).toBe(2);
161
+ set.delete('A');
162
+ expect(set.size).toBe(1);
163
+ });
164
+ test('should clear all entries', () => {
165
+ const set = new Utils_1.CaseAndSpaceInsensitiveSet();
166
+ set.add('A');
167
+ set.add('B');
168
+ set.clear();
169
+ expect(set.size).toBe(0);
170
+ expect(set.has('A')).toBe(false);
171
+ });
172
+ test('should handle values with spaces', () => {
173
+ const set = new Utils_1.CaseAndSpaceInsensitiveSet();
174
+ set.add('Data Admin');
175
+ expect(set.has('dataadmin')).toBe(true);
176
+ expect(set.has('DataAdmin')).toBe(true);
177
+ expect(Array.from(set)).toEqual(['Data Admin']);
178
+ });
179
+ });
180
+ //# sourceMappingURL=user.issue61.test.js.map
@@ -20,14 +20,17 @@ export declare class CaseAndSpaceInsensitiveMap<T> extends Map<string, T> {
20
20
  delete(key: string): boolean;
21
21
  }
22
22
  export declare class CaseAndSpaceInsensitiveSet extends Set<string> {
23
- private normalizeValue;
23
+ private _normalizedMap;
24
+ constructor(values?: Iterable<string>);
24
25
  add(value: string): this;
25
26
  has(value: string): boolean;
26
27
  delete(value: string): boolean;
28
+ clear(): void;
27
29
  }
28
30
  export declare function caseAndSpaceInsensitiveEquals(str1: string, str2: string): boolean;
29
31
  export declare function lowerAndDropSpaces(str: string): string;
30
32
  export declare function escapeODataValue(str: string): string;
33
+ export declare function buildUrlFriendlyObjectName(objectName: string): string;
31
34
  export declare function formatUrl(template: string, ...args: string[]): string;
32
35
  export declare function extractCellsetCells(cellset: any): any[];
33
36
  export declare function buildMdxFromAxes(axes: any[]): string;
@@ -59,6 +62,7 @@ export declare function getMdxElementFromAttribute(attribute: string, cube: stri
59
62
  export declare function buildMdxTuple(members: string[]): string;
60
63
  export declare function verifyVersion(actualVersion: string, requiredVersion: string): boolean;
61
64
  export declare function readObjectNameFromUrl(url: string): string;
65
+ export declare function readObjectNameFromUrl(url: string, pattern: string | RegExp): string | null;
62
66
  export declare function parseODataBindUrl(url: string): string[];
63
67
  export declare function integerizeVersion(version: string): number;
64
68
  export declare function frameToSignificantValue(value: any): any;
@@ -74,6 +78,7 @@ export declare const Utils: {
74
78
  CaseAndSpaceInsensitiveSet: typeof CaseAndSpaceInsensitiveSet;
75
79
  caseAndSpaceInsensitiveEquals: typeof caseAndSpaceInsensitiveEquals;
76
80
  lowerAndDropSpaces: typeof lowerAndDropSpaces;
81
+ buildUrlFriendlyObjectName: typeof buildUrlFriendlyObjectName;
77
82
  formatUrl: typeof formatUrl;
78
83
  extractCellsetCells: typeof extractCellsetCells;
79
84
  buildMdxFromAxes: typeof buildMdxFromAxes;
@@ -1 +1 @@
1
- {"version":3,"file":"Utils.d.ts","sourceRoot":"","sources":["../../src/utils/Utils.ts"],"names":[],"mappings":"AAAA,qBAAa,2BAA2B,CAAC,CAAC,CAAE,SAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,YAAY;IAIpB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAIhC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAI/B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG/B;AAED,qBAAa,iCAAiC,CAAC,CAAC,CAAE,SAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IACpE,OAAO,CAAC,YAAY;IAIpB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAIhC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAI/B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG/B;AAED,qBAAa,0BAA0B,CAAC,CAAC,CAAE,SAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,YAAY;IAIpB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAIhC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAI/B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG/B;AAED,qBAAa,0BAA2B,SAAQ,GAAG,CAAC,MAAM,CAAC;IACvD,OAAO,CAAC,cAAc;IAItB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIxB,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAI3B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;CAGjC;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAMjF;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAMrE;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG,GAAG,GAAG,EAAE,CAKvD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,CA0BpD;AAED,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAE,MAAY,GAAG,MAAM,CAE3G;AAED,wBAAgB,4CAA4C,CAAC,UAAU,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAgBzG;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAGnH;AAED,wBAAgB,wCAAwC,CAAC,yBAAyB,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAgBpH;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,KAAK,IAAI,CAS/H;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,KAAK,IAAI,CAU9H;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAQnG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAUvG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAU3G;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAUtG;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAK7D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQxE;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAQ5D;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAI3E;AAED,wBAAgB,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAGhD;AAGD,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAElF;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAKvD;AAGD,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAmBrF;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAKvD;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMzD;AAGD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,CAQvD;AAGD,qBAAa,4BAA4B;IACzB,OAAO,CAAC,aAAa;gBAAb,aAAa,GAAE,GAAQ;CAG9C;AAGD,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIhE;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAExD;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BjB,CAAC;AAGF;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAiCtG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,GAAE,OAAc,EAAE,UAAU,GAAE,OAAc,IACtE,QAAQ,GAAG,EAAE,aAAa,MAAM,EAAE,YAAY,kBAAkB,KAAG,IAAI,CAsC3F;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,UAAU,GAAE,MAAU,EAAE,SAAS,GAAE,MAAa,IACrD,QAAQ,GAAG,EAAE,aAAa,MAAM,EAAE,YAAY,kBAAkB,KAAG,IAAI,CAiC3F"}
1
+ {"version":3,"file":"Utils.d.ts","sourceRoot":"","sources":["../../src/utils/Utils.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ exports.Utils = exports.HTTPAdapterWithSocketOptions = exports.CaseAndSpaceInsen
4
4
  exports.caseAndSpaceInsensitiveEquals = caseAndSpaceInsensitiveEquals;
5
5
  exports.lowerAndDropSpaces = lowerAndDropSpaces;
6
6
  exports.escapeODataValue = escapeODataValue;
7
+ exports.buildUrlFriendlyObjectName = buildUrlFriendlyObjectName;
7
8
  exports.formatUrl = formatUrl;
8
9
  exports.extractCellsetCells = extractCellsetCells;
9
10
  exports.buildMdxFromAxes = buildMdxFromAxes;
@@ -90,17 +91,37 @@ class CaseAndSpaceInsensitiveMap extends Map {
90
91
  }
91
92
  exports.CaseAndSpaceInsensitiveMap = CaseAndSpaceInsensitiveMap;
92
93
  class CaseAndSpaceInsensitiveSet extends Set {
93
- normalizeValue(value) {
94
- return value.toLowerCase().replace(/\s+/g, '');
94
+ constructor(values) {
95
+ super();
96
+ this._normalizedMap = new Map();
97
+ if (values) {
98
+ for (const v of values) {
99
+ this.add(v);
100
+ }
101
+ }
95
102
  }
96
103
  add(value) {
97
- return super.add(this.normalizeValue(value));
104
+ const key = lowerAndDropSpaces(value);
105
+ if (!this._normalizedMap.has(key)) {
106
+ this._normalizedMap.set(key, value);
107
+ super.add(value);
108
+ }
109
+ return this;
98
110
  }
99
111
  has(value) {
100
- return super.has(this.normalizeValue(value));
112
+ return this._normalizedMap.has(lowerAndDropSpaces(value));
101
113
  }
102
114
  delete(value) {
103
- return super.delete(this.normalizeValue(value));
115
+ const key = lowerAndDropSpaces(value);
116
+ const original = this._normalizedMap.get(key);
117
+ if (original === undefined)
118
+ return false;
119
+ this._normalizedMap.delete(key);
120
+ return super.delete(original);
121
+ }
122
+ clear() {
123
+ this._normalizedMap.clear();
124
+ super.clear();
104
125
  }
105
126
  }
106
127
  exports.CaseAndSpaceInsensitiveSet = CaseAndSpaceInsensitiveSet;
@@ -118,6 +139,14 @@ function lowerAndDropSpaces(str) {
118
139
  function escapeODataValue(str) {
119
140
  return str.replace(/'/g, "''");
120
141
  }
142
+ function buildUrlFriendlyObjectName(objectName) {
143
+ return objectName
144
+ .replace(/'/g, "''")
145
+ .replace(/%/g, "%25")
146
+ .replace(/#/g, "%23")
147
+ .replace(/\?/g, "%3F")
148
+ .replace(/&/g, "%26");
149
+ }
121
150
  function formatUrl(template, ...args) {
122
151
  let url = template;
123
152
  for (const arg of args) {
@@ -329,8 +358,27 @@ function verifyVersion(actualVersion, requiredVersion) {
329
358
  }
330
359
  return true; // Equal versions
331
360
  }
332
- function readObjectNameFromUrl(url) {
333
- // Extract object name from URL like "/Dimensions('DimName')" -> "DimName"
361
+ function readObjectNameFromUrl(url, pattern) {
362
+ // tm1py parity: when `pattern` is provided, behave like
363
+ // `re.match(pattern, url)` + `unquote(match.group(1))` — anchored at start,
364
+ // URL-decodes the first capture group, returns null on no match.
365
+ if (pattern !== undefined) {
366
+ const re = typeof pattern === 'string'
367
+ ? new RegExp(pattern.startsWith('^') ? pattern : '^' + pattern)
368
+ : pattern;
369
+ const m = url.match(re);
370
+ if (!m || m[1] === undefined)
371
+ return null;
372
+ try {
373
+ return decodeURIComponent(m[1]);
374
+ }
375
+ catch (_a) {
376
+ // tm1py parity: urllib.parse.unquote is permissive on malformed %XX
377
+ // (returns the original string). decodeURIComponent throws — fall back.
378
+ return m[1];
379
+ }
380
+ }
381
+ // Backward-compat: extract first ('name') segment, return '' on no match
334
382
  const match = url.match(/\('([^']+)'\)/);
335
383
  return match ? match[1] : '';
336
384
  }
@@ -381,6 +429,7 @@ exports.Utils = {
381
429
  CaseAndSpaceInsensitiveSet,
382
430
  caseAndSpaceInsensitiveEquals,
383
431
  lowerAndDropSpaces,
432
+ buildUrlFriendlyObjectName,
384
433
  formatUrl,
385
434
  extractCellsetCells,
386
435
  buildMdxFromAxes,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tm1npm",
3
- "version": "1.6.0",
3
+ "version": "2.1.0",
4
4
  "description": "A Node.js module for TM1",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -102,6 +102,10 @@ export class ViewTitleSelection {
102
102
  return this._subset;
103
103
  }
104
104
 
105
+ public set subset(value: Subset | AnonymousSubset) {
106
+ this._subset = value;
107
+ }
108
+
105
109
  public get dimensionName(): string {
106
110
  return this._dimensionName;
107
111
  }
@@ -148,11 +148,11 @@ export class Chore extends TM1Object {
148
148
  return body;
149
149
  }
150
150
 
151
- public reschedule(frequency: ChoreFrequency, startTime?: ChoreStartTime): void {
152
- /** Reschedule the chore
151
+ public setFrequency(frequency: ChoreFrequency, startTime?: ChoreStartTime): void {
152
+ /** Replace the chore frequency (and optionally start time)
153
153
  *
154
154
  * :param frequency: new ChoreFrequency
155
- * :param start_time: new ChoreStartTime (optional)
155
+ * :param startTime: new ChoreStartTime (optional)
156
156
  */
157
157
  this._frequency = frequency;
158
158
  if (startTime) {
@@ -197,22 +197,15 @@ export class Chore extends TM1Object {
197
197
  return { [this._name]: processNames };
198
198
  }
199
199
 
200
- public rescheduleByTime(days: number = 0, hours: number = 0, minutes: number = 0, seconds: number = 0): void {
201
- /** Programmatically reschedule a chore by adding time to current start time
200
+ public reschedule(days: number = 0, hours: number = 0, minutes: number = 0, seconds: number = 0): void {
201
+ /** Reschedule the chore by adding time to the current start time.
202
+ *
202
203
  * :param days: Days to add
203
204
  * :param hours: Hours to add
204
205
  * :param minutes: Minutes to add
205
206
  * :param seconds: Seconds to add
206
207
  */
207
- if (this._startTime.datetime) {
208
- const newDateTime = new Date(this._startTime.datetime);
209
- newDateTime.setDate(newDateTime.getDate() + days);
210
- newDateTime.setHours(newDateTime.getHours() + hours);
211
- newDateTime.setMinutes(newDateTime.getMinutes() + minutes);
212
- newDateTime.setSeconds(newDateTime.getSeconds() + seconds);
213
-
214
- this._startTime = new ChoreStartTime(newDateTime, this._startTime.tz);
215
- }
208
+ this._startTime.add(days, hours, minutes, seconds);
216
209
  }
217
210
 
218
211
  public static fromJson(choreAsJson: string): Chore {
@@ -1,5 +1,6 @@
1
1
  import { TM1Object } from './TM1Object';
2
2
  import { Rules } from './Rules';
3
+ import { buildUrlFriendlyObjectName } from '../utils/Utils';
3
4
 
4
5
  export class Cube extends TM1Object {
5
6
  /** Abstraction of a TM1 Cube
@@ -113,7 +114,7 @@ export class Cube extends TM1Object {
113
114
  private constructBody(): any {
114
115
  const body: any = {
115
116
  Name: this._name,
116
- Dimensions: this._dimensions.map(dim => ({ Name: dim }))
117
+ "Dimensions@odata.bind": this._dimensions.map(dim => `Dimensions('${buildUrlFriendlyObjectName(dim)}')`)
117
118
  };
118
119
 
119
120
  if (this._rules) {
@@ -1,7 +1,7 @@
1
1
  import { TM1Object } from './TM1Object';
2
2
  import { Element, ElementType } from './Element';
3
3
  import { ElementAttribute } from './ElementAttribute';
4
- import { lowerAndDropSpaces } from '../utils/Utils';
4
+ import { lowerAndDropSpaces, caseAndSpaceInsensitiveEquals } from '../utils/Utils';
5
5
 
6
6
  export class Hierarchy extends TM1Object {
7
7
  private _name: string;
@@ -29,7 +29,7 @@ export class Hierarchy extends TM1Object {
29
29
 
30
30
  if (elements) {
31
31
  for (const elem of elements) {
32
- this._elements.set(elem.name.toLowerCase(), elem);
32
+ this._elements.set(lowerAndDropSpaces(elem.name), elem);
33
33
  }
34
34
  }
35
35
 
@@ -98,7 +98,7 @@ export class Hierarchy extends TM1Object {
98
98
  }
99
99
 
100
100
  public get elementNames(): string[] {
101
- return Array.from(this._elements.keys());
101
+ return Array.from(this._elements.values()).map(e => e.name);
102
102
  }
103
103
 
104
104
  public get elementAttributes(): ElementAttribute[] {
@@ -172,19 +172,19 @@ export class Hierarchy extends TM1Object {
172
172
  }
173
173
 
174
174
  public addElement(element: Element): void {
175
- this._elements.set(element.name.toLowerCase(), element);
175
+ this._elements.set(lowerAndDropSpaces(element.name), element);
176
176
  }
177
177
 
178
178
  public removeElement(elementName: string): boolean {
179
- return this._elements.delete(elementName.toLowerCase());
179
+ return this._elements.delete(lowerAndDropSpaces(elementName));
180
180
  }
181
181
 
182
182
  public getElement(elementName: string): Element | undefined {
183
- return this._elements.get(elementName.toLowerCase());
183
+ return this._elements.get(lowerAndDropSpaces(elementName));
184
184
  }
185
185
 
186
186
  public hasElement(elementName: string): boolean {
187
- return this._elements.has(elementName.toLowerCase());
187
+ return this._elements.has(lowerAndDropSpaces(elementName));
188
188
  }
189
189
 
190
190
  public addEdge(parentName: string, componentName: string, weight: number = 1): void {
@@ -216,7 +216,7 @@ export class Hierarchy extends TM1Object {
216
216
 
217
217
  public removeElementAttribute(attributeName: string): boolean {
218
218
  const index = this._elementAttributes.findIndex(ea =>
219
- ea.name.toLowerCase() === attributeName.toLowerCase());
219
+ caseAndSpaceInsensitiveEquals(ea.name, attributeName));
220
220
 
221
221
  if (index !== -1) {
222
222
  this._elementAttributes.splice(index, 1);
@@ -227,12 +227,12 @@ export class Hierarchy extends TM1Object {
227
227
 
228
228
  public getElementAttribute(attributeName: string): ElementAttribute | undefined {
229
229
  return this._elementAttributes.find(ea =>
230
- ea.name.toLowerCase() === attributeName.toLowerCase());
230
+ caseAndSpaceInsensitiveEquals(ea.name, attributeName));
231
231
  }
232
232
 
233
233
  public hasElementAttribute(attributeName: string): boolean {
234
234
  return this._elementAttributes.some(ea =>
235
- ea.name.toLowerCase() === attributeName.toLowerCase());
235
+ caseAndSpaceInsensitiveEquals(ea.name, attributeName));
236
236
  }
237
237
 
238
238
  public getAncestors(elementName: string, recursive: boolean = false): string[] {
@@ -337,7 +337,7 @@ export class Hierarchy extends TM1Object {
337
337
  const element = this._elements.get(oldKey)!;
338
338
  element.name = newName;
339
339
  this._elements.delete(oldKey);
340
- this._elements.set(newName.toLowerCase(), element);
340
+ this._elements.set(lowerAndDropSpaces(newName), element);
341
341
  }
342
342
 
343
343
  // Rebuild edges replacing all occurrences of oldName