dt-common-device 13.0.7 → 13.0.9

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.
@@ -9,6 +9,11 @@ export declare class AdminRepository {
9
9
  getZonesByAccessGroups(accessGroupIds: string[], type?: string[]): Promise<any[]>;
10
10
  getAccessGroup(accessGroupId: string, propertyId?: string): Promise<IAccessGroup | null>;
11
11
  getZoneAccessGroupByZoneId(zoneId: string): Promise<IZoneAccessGroup[] | null>;
12
+ getAllParentZones(zoneId: string): Promise<string[]>;
13
+ getDirectChildZones(zoneId: string, propertyId?: string): Promise<string[]>;
14
+ getAllChildZones(zoneId: string, propertyId?: string): Promise<string[]>;
15
+ getAccessGroupsByZoneId(zoneId: string): Promise<IAccessGroup[]>;
16
+ getAccessGroupsByZoneIds(zoneIds: string[]): Promise<IAccessGroup[]>;
12
17
  getZone(zoneId: string, propertyId?: string): Promise<IZone | null>;
13
18
  getUser(userId: string): Promise<IUser | null>;
14
19
  getZoneByDeviceId(deviceId: string): Promise<IZone | null>;
@@ -224,10 +224,11 @@ let AdminRepository = (() => {
224
224
  // Use default types if not provided
225
225
  const zoneTypesToFilter = type || ["Guest Room", "Room"];
226
226
  // Fetch zone type IDs for the specified type
227
+ // Using IN with unnest() for better compatibility with string arrays
227
228
  const zoneTypesQuery = `
228
229
  SELECT id
229
230
  FROM "dt_zoneTypes"
230
- WHERE name = ANY($1)
231
+ WHERE name IN (SELECT unnest($1::text[]))
231
232
  `;
232
233
  const zoneTypes = await this.postgres.query(zoneTypesQuery, [
233
234
  zoneTypesToFilter,
@@ -277,6 +278,116 @@ let AdminRepository = (() => {
277
278
  }
278
279
  return null;
279
280
  }
281
+ async getAllParentZones(zoneId) {
282
+ const allParentZoneIds = [];
283
+ let currentZoneId = zoneId;
284
+ while (currentZoneId) {
285
+ const zone = await this.getZone(currentZoneId);
286
+ if (!zone || !zone.parentId) {
287
+ break;
288
+ }
289
+ allParentZoneIds.push(zone.parentId);
290
+ currentZoneId = zone.parentId;
291
+ }
292
+ return allParentZoneIds;
293
+ }
294
+ async getDirectChildZones(zoneId, propertyId) {
295
+ const redisKey = propertyId
296
+ ? `${propertyId}:childZones:${zoneId}`
297
+ : `childZones:${zoneId}`;
298
+ // Try to get from cache first
299
+ const zonesCache = await this.redisUtils.get(redisKey);
300
+ let zones = null;
301
+ if (zonesCache !== null && zonesCache !== undefined) {
302
+ (0, config_1.getLogger)().info(`Got child zones from redis for zone ${zoneId}`);
303
+ zones = JSON.parse(zonesCache);
304
+ }
305
+ else {
306
+ const response = await (0, utils_1.getAdminServiceAxiosInstance)().get(`/zones/child?zoneId=${zoneId}`);
307
+ zones = response?.data?.data;
308
+ if (zones) {
309
+ await this.redisUtils.set(redisKey, JSON.stringify(zones), 86400);
310
+ }
311
+ }
312
+ // Get only direct children (first level), not all descendants
313
+ if (zones && zones.childZones) {
314
+ if (Array.isArray(zones.childZones)) {
315
+ return zones.childZones
316
+ .map((z) => z.id)
317
+ .filter((id) => id);
318
+ }
319
+ else if (zones.childZones.id) {
320
+ return [zones.childZones.id];
321
+ }
322
+ }
323
+ return [];
324
+ }
325
+ async getAllChildZones(zoneId, propertyId) {
326
+ const redisKey = propertyId
327
+ ? `${propertyId}:childZones:${zoneId}`
328
+ : `childZones:${zoneId}`;
329
+ // Try to get from cache first
330
+ const zonesCache = await this.redisUtils.get(redisKey);
331
+ let zones = null;
332
+ if (zonesCache !== null && zonesCache !== undefined) {
333
+ (0, config_1.getLogger)().info(`Got child zones from redis for zone ${zoneId}`);
334
+ zones = JSON.parse(zonesCache);
335
+ }
336
+ else {
337
+ const response = await (0, utils_1.getAdminServiceAxiosInstance)().get(`/zones/child?zoneId=${zoneId}`);
338
+ zones = response?.data?.data;
339
+ if (zones) {
340
+ await this.redisUtils.set(redisKey, JSON.stringify(zones), 86400);
341
+ }
342
+ }
343
+ // Recursively collect all child zone IDs (using the same pattern as getZonesByAccessGroupIds)
344
+ const _zones = (nestedZones, allZones = []) => {
345
+ nestedZones.forEach((z) => {
346
+ const onlyZone = { ...z };
347
+ delete onlyZone.childZones;
348
+ allZones.push(onlyZone);
349
+ if (!Array.isArray(z.childZones)) {
350
+ if (z.childZones && z.childZones.id)
351
+ z.childZones = [z.childZones];
352
+ }
353
+ if (z.childZones && z.childZones.length) {
354
+ _zones(z.childZones, allZones);
355
+ }
356
+ });
357
+ return allZones.map((e) => e.id);
358
+ };
359
+ if (zones && zones.childZones && zones.childZones.length > 0) {
360
+ const childZoneIds = _zones(zones.childZones, []);
361
+ return childZoneIds;
362
+ }
363
+ return [];
364
+ }
365
+ async getAccessGroupsByZoneId(zoneId) {
366
+ const query = `
367
+ SELECT DISTINCT c.*
368
+ FROM dt_collections c
369
+ INNER JOIN dt_zones_collection_map zcm ON c.id = zcm."collectionId"
370
+ WHERE zcm."zoneId" = $1
371
+ AND c."isDeleted" = false
372
+ `;
373
+ const result = await this.postgres.query(query, [zoneId]);
374
+ return result.rows;
375
+ }
376
+ async getAccessGroupsByZoneIds(zoneIds) {
377
+ if (zoneIds.length === 0) {
378
+ return [];
379
+ }
380
+ // Get all access groups associated with any of these zones
381
+ const query = `
382
+ SELECT DISTINCT c.*
383
+ FROM dt_collections c
384
+ INNER JOIN dt_zones_collection_map zcm ON c.id = zcm."collectionId"
385
+ WHERE zcm."zoneId" = ANY($1)
386
+ AND c."isDeleted" = false
387
+ `;
388
+ const result = await this.postgres.query(query, [zoneIds]);
389
+ return result.rows;
390
+ }
280
391
  async getZone(zoneId, propertyId) {
281
392
  try {
282
393
  let query;
@@ -7,6 +7,7 @@ export declare class AdminService {
7
7
  getZonesByAccessGroups(accessGroupIds: string[], type?: string[]): Promise<any[]>;
8
8
  getAccessGroup(accessGroupId: string, propertyId?: string): Promise<IAccessGroup | null>;
9
9
  getAccessGroupByZoneId(zoneId: string): Promise<IAccessGroup[] | []>;
10
+ getAccessgroupBySubParentZoneId(zoneId: string): Promise<IAccessGroup[]>;
10
11
  getZone(zoneId: string, propertyId?: string): Promise<IZone | null>;
11
12
  getUser(userId: string): Promise<IUser | null>;
12
13
  getZoneByDeviceId(deviceId: string): Promise<IZone | null>;
@@ -133,6 +133,84 @@ let AdminService = (() => {
133
133
  }
134
134
  return accessGroups;
135
135
  }
136
+ async getAccessgroupBySubParentZoneId(zoneId) {
137
+ if (!zoneId) {
138
+ throw new Error("Zone ID is required");
139
+ }
140
+ try {
141
+ // Get the zone to retrieve propertyId if needed
142
+ const zone = await this.adminRepository.getZone(zoneId);
143
+ if (!zone) {
144
+ return [];
145
+ }
146
+ // Use Map to collect unique access groups (by ID)
147
+ const accessGroupsMap = new Map();
148
+ // Track visited zones to avoid cycles and duplicate checks
149
+ const visitedZoneIds = new Set();
150
+ // OPTIMIZATION: Set to true if you only need to check if ANY access group exists
151
+ // Set to false if you need ALL access groups from entire hierarchy
152
+ const stopOnFirstFound = true;
153
+ // Recursive function to traverse hierarchy and collect access groups
154
+ const traverseZoneHierarchy = async (currentZoneId, propertyId) => {
155
+ // Base case 1: if zone already visited, return (prevents cycles)
156
+ if (visitedZoneIds.has(currentZoneId)) {
157
+ return false;
158
+ }
159
+ // Base case 2: early exit if we found access group and only need existence check
160
+ if (stopOnFirstFound && accessGroupsMap.size > 0) {
161
+ return true;
162
+ }
163
+ // Mark as visited
164
+ visitedZoneIds.add(currentZoneId);
165
+ // Check access groups for current zone (query as we traverse)
166
+ const zoneAccessGroups = await this.adminRepository.getAccessGroupsByZoneId(currentZoneId);
167
+ // If we found access groups, add to map
168
+ if (zoneAccessGroups.length > 0) {
169
+ zoneAccessGroups.forEach((ag) => accessGroupsMap.set(ag.id, ag));
170
+ // Early exit optimization: if we only need to know if access group exists
171
+ if (stopOnFirstFound) {
172
+ return true; // Stop traversal - we found what we need
173
+ }
174
+ }
175
+ // Get current zone details
176
+ const currentZone = await this.adminRepository.getZone(currentZoneId);
177
+ if (!currentZone) {
178
+ return false;
179
+ }
180
+ // Recursive case 1: Traverse up to parent zone (if exists and not visited)
181
+ if (currentZone.parentId && !visitedZoneIds.has(currentZone.parentId)) {
182
+ const found = await traverseZoneHierarchy(currentZone.parentId, propertyId);
183
+ // Early exit: if we found access group in parent, stop checking children
184
+ if (found && stopOnFirstFound) {
185
+ return true;
186
+ }
187
+ }
188
+ // Recursive case 2: Traverse down to direct child zones only
189
+ // Only check children if we haven't found an access group yet (optimization)
190
+ if (!stopOnFirstFound || accessGroupsMap.size === 0) {
191
+ const directChildZoneIds = await this.adminRepository.getDirectChildZones(currentZoneId, propertyId);
192
+ // Recursively process each direct child zone
193
+ for (const childZoneId of directChildZoneIds) {
194
+ if (!visitedZoneIds.has(childZoneId)) {
195
+ const found = await traverseZoneHierarchy(childZoneId, propertyId);
196
+ // Early exit: if we found access group in any child, we can stop
197
+ if (found && stopOnFirstFound) {
198
+ return true;
199
+ }
200
+ }
201
+ }
202
+ }
203
+ return accessGroupsMap.size > 0;
204
+ };
205
+ // Start recursive traversal from the given zone
206
+ await traverseZoneHierarchy(zoneId, zone.propertyId);
207
+ return Array.from(accessGroupsMap.values());
208
+ }
209
+ catch (error) {
210
+ console.error("Error in getAccessgroupBySubParentZoneId:", error);
211
+ return [];
212
+ }
213
+ }
136
214
  async getZone(zoneId, propertyId) {
137
215
  if (!zoneId) {
138
216
  throw new Error("Zone ID is required");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dt-common-device",
3
- "version": "13.0.7",
3
+ "version": "13.0.9",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [