bruce-models 7.0.7 → 7.0.8

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.
@@ -2704,950 +2704,950 @@
2704
2704
  })(exports.ObjectUtils || (exports.ObjectUtils = {}));
2705
2705
 
2706
2706
  /**
2707
- * Describes an entity type schema attribute.
2707
+ * Utility to help with parsing and wrapping Nextspace paths.
2708
2708
  */
2709
- (function (EntityAttribute) {
2710
- let EType;
2711
- (function (EType) {
2712
- // Arbitrary text attribute.
2713
- EType["String"] = "String";
2714
- // Floating point number attribute.
2715
- EType["Double"] = "Double";
2716
- // Whole number attribute.
2717
- EType["Integer"] = "Integer";
2718
- // iso8601 date time string.
2719
- EType["Datetime"] = "Datetime";
2720
- // Group of attributes.
2721
- EType["Structure"] = "Structure";
2722
- // Nextspace vector geometry.
2723
- EType["Geometry"] = "Geometry";
2724
- // True/false attribute.
2725
- EType["Boolean"] = "Boolean";
2726
- // String User ID.
2727
- EType["User"] = "User";
2728
- // String Group ID.
2729
- EType["UserGroup"] = "UserGroup";
2730
- // String Entity ID.
2731
- EType["Entity"] = "Entity";
2732
- // Url attribute.
2733
- EType["Url"] = "Url";
2734
- // Serial number that increments for each new entity/missing-attr-value.
2735
- EType["Serial"] = "Serial";
2736
- })(EType = EntityAttribute.EType || (EntityAttribute.EType = {}));
2737
- /**
2738
- * Describes url open behavior.
2739
- */
2740
- let EOpenBehavior;
2741
- (function (EOpenBehavior) {
2742
- EOpenBehavior["POPUP"] = "POPUP";
2743
- EOpenBehavior["NEW_TAB"] = "NEW_TAB";
2744
- })(EOpenBehavior = EntityAttribute.EOpenBehavior || (EntityAttribute.EOpenBehavior = {}));
2709
+ (function (PathUtils) {
2745
2710
  /**
2746
- * Returns an attribute from a provided hierarchy of attributes.
2747
- * Eg: Use the path: ["Bruce", "ID"] to find the "ID" attribute.
2748
- * @param items
2749
- * @param path
2711
+ * Parses a Bruce string path into an array of strings.
2712
+ * Example of path: "\"location\"/\"latitude\"" or "location/latitude".
2713
+ * @param str
2750
2714
  * @returns
2751
2715
  */
2752
- function GetAttribute(items, path) {
2753
- if (!items || !path || !path.length) {
2754
- return null;
2755
- }
2756
- const key = path[0];
2757
- const item = items.find((i) => i.Key === key);
2758
- if (!item) {
2759
- return null;
2716
+ function Parse(str) {
2717
+ if (!(str === null || str === void 0 ? void 0 : str.length)) {
2718
+ return [];
2760
2719
  }
2761
- if (path.length === 1) {
2762
- return item;
2720
+ const broken = str.split("/");
2721
+ // Remove quotes from the first and last chars.
2722
+ for (let i = 0; i < broken.length; i++) {
2723
+ let piece = broken[i];
2724
+ if (piece.startsWith("\"")) {
2725
+ piece = piece.substring(1);
2726
+ }
2727
+ if (piece.endsWith("\"")) {
2728
+ piece = piece.substring(0, piece.length - 1);
2729
+ }
2730
+ broken[i] = piece;
2763
2731
  }
2764
- return GetAttribute(item.Structure, path.slice(1));
2732
+ return broken;
2765
2733
  }
2766
- EntityAttribute.GetAttribute = GetAttribute;
2734
+ PathUtils.Parse = Parse;
2767
2735
  /**
2768
- * Removes an attribute from a provided hierarchy of attributes.
2769
- * Eg: Use the path: ["Bruce", "ID"] to remove the "ID" attribute.
2770
- * This will mutate the items array.
2771
- * @param items
2736
+ * Wraps an array of strings into a Nextspace string path.
2772
2737
  * @param path
2738
+ * @returns
2773
2739
  */
2774
- function RemoveAttribute(items, path) {
2775
- if (!items || !(path === null || path === void 0 ? void 0 : path.length)) {
2776
- return;
2740
+ function Wrap(path) {
2741
+ if (!(path === null || path === void 0 ? void 0 : path.length)) {
2742
+ return "";
2777
2743
  }
2778
- const key = path[0];
2779
- if (path.length === 1) {
2780
- // If we're at the last key in the path, remove the item from the items array.
2781
- const index = items.findIndex((i) => i.Key === key);
2782
- if (index !== -1) {
2783
- items.splice(index, 1);
2744
+ let tmp = "\"";
2745
+ for (let i = 0; i < path.length; i++) {
2746
+ let section = path[i];
2747
+ tmp += section;
2748
+ if (i < path.length - 1) {
2749
+ tmp += "\"/\"";
2784
2750
  }
2785
- return;
2786
- }
2787
- // If we're not at the end of the path, dig further.
2788
- const item = items.find((i) => i.Key === key);
2789
- if (item && item.Structure) {
2790
- RemoveAttribute(item.Structure, path.slice(1));
2791
2751
  }
2752
+ tmp += "\"";
2753
+ return tmp;
2792
2754
  }
2793
- EntityAttribute.RemoveAttribute = RemoveAttribute;
2755
+ PathUtils.Wrap = Wrap;
2794
2756
  /**
2795
- * Adds an attribute to a provided hierarchy of attributes.
2796
- * Eg: Use the path: ["Bruce", "ID"] to add the "ID" attribute.
2797
- * This will mutate the items array.
2798
- * This requires the path to be valid and for a parent attribute to exist.
2799
- * @param items
2800
- * @param path
2801
- * @param attribute
2757
+ * Parses a Nextspace legacy string path into an array of strings.
2758
+ * @param str
2759
+ * @returns
2802
2760
  */
2803
- function AddAttribute(items, path, attribute) {
2804
- if (!items || !(path === null || path === void 0 ? void 0 : path.length)) {
2805
- return;
2761
+ function ParseLegacy(str) {
2762
+ if (!(str === null || str === void 0 ? void 0 : str.length)) {
2763
+ return [];
2806
2764
  }
2807
- const key = path[0];
2808
- if (path.length === 1) {
2809
- // If we're at the last key in the path, add the attribute to the items array.
2810
- const index = items.findIndex((i) => i.Key === key);
2811
- if (index !== -1) {
2812
- // Overwrite existing attribute if it already exists.
2813
- items[index] = attribute;
2765
+ const broken = str.split(".");
2766
+ for (let i = 0; i < broken.length; i++) {
2767
+ let piece = broken[i];
2768
+ if (piece.startsWith("\"")) {
2769
+ piece = piece.substring(1);
2814
2770
  }
2815
- else {
2816
- // Add new attribute if it doesn't exist.
2817
- items.push(attribute);
2771
+ if (piece.endsWith("\"")) {
2772
+ piece = piece.substring(0, piece.length - 1);
2818
2773
  }
2819
- return;
2820
- }
2821
- // If we're not at the end of the path, dig further.
2822
- let item = items.find((i) => i.Key === key);
2823
- if (!item) {
2824
- item = { Key: key, Structure: [] };
2825
- items.push(item);
2826
- }
2827
- if (!item.Structure) {
2828
- item.Structure = [];
2774
+ broken[i] = piece;
2829
2775
  }
2830
- AddAttribute(item.Structure, path.slice(1), attribute);
2776
+ return broken;
2831
2777
  }
2832
- EntityAttribute.AddAttribute = AddAttribute;
2833
- })(exports.EntityAttribute || (exports.EntityAttribute = {}));
2778
+ PathUtils.ParseLegacy = ParseLegacy;
2779
+ })(exports.PathUtils || (exports.PathUtils = {}));
2834
2780
 
2835
- (function (EntityType) {
2781
+ (function (EntityHistoricData) {
2836
2782
  /**
2837
- * Gets an entity type record.
2783
+ * Returns historic data for an array of Entity IDs.
2784
+ * A maximum number of records will be returned per Entity ID, this information is returned in the response.
2838
2785
  * @param params
2839
2786
  * @returns
2840
2787
  */
2841
- function Get(params) {
2788
+ function GetList(params) {
2842
2789
  return __awaiter(this, void 0, void 0, function* () {
2843
- let { api, entityTypeId: typeId, req: reqParams, expandLODs } = params;
2844
- if (!typeId) {
2845
- throw ("Type ID is required.");
2790
+ let { entityIds, attrKey, dateTimeFrom, dateTimeTo, api, req } = params;
2791
+ // Save time and just return a none response if no entity IDs are provided.
2792
+ if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
2793
+ return {
2794
+ limitPerEntity: 0,
2795
+ recordsByIds: {}
2796
+ };
2846
2797
  }
2847
2798
  if (!api) {
2848
2799
  api = exports.ENVIRONMENT.Api().GetBruceApi();
2849
2800
  }
2850
- const key = GetCacheKey(typeId, expandLODs);
2851
- const cache = api.GetCacheItem(key, reqParams);
2852
- if (cache === null || cache === void 0 ? void 0 : cache.found) {
2853
- return cache.data;
2801
+ let attrKeyStr = null;
2802
+ if (attrKey) {
2803
+ if (typeof attrKey != "string") {
2804
+ attrKeyStr = exports.PathUtils.Wrap(attrKey);
2805
+ }
2806
+ else {
2807
+ attrKeyStr = attrKey;
2808
+ }
2854
2809
  }
2855
- const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
2856
- try {
2857
- const urlParams = new URLSearchParams();
2858
- if (expandLODs) {
2859
- urlParams.append("Expand", "LOD");
2810
+ // If we have more than 100 Entity IDs we'll have to split the request to avoid a URL that is too long.
2811
+ const MAX_IDS = 100;
2812
+ // We will recursively call this function to get all the data.
2813
+ // Then merge at the end and return.
2814
+ if (entityIds.length > MAX_IDS) {
2815
+ const reqs = [];
2816
+ // Making the ID batches.
2817
+ // If this is too long we can end up in a loop.
2818
+ const splitEntityIds = [];
2819
+ for (let i = 0; i < entityIds.length; i += MAX_IDS) {
2820
+ const batchIds = entityIds.slice(i, i + MAX_IDS);
2821
+ // Detecting this early to avoid infinite loops.
2822
+ if (batchIds.length > MAX_IDS) {
2823
+ throw new Error("Nextspace Developer Error: EntityHistoricData.GetList() has too many Entity IDs. Please contact support.");
2860
2824
  }
2861
- const url = `entitytype/${typeId}?${urlParams.toString()}`;
2862
- const data = yield api.GET(url, exports.Api.PrepReqParams(reqParams));
2863
- appendInternalAttrSchema(data);
2864
- res({
2865
- entityType: data
2866
- });
2825
+ splitEntityIds.push(batchIds);
2867
2826
  }
2868
- catch (e) {
2869
- rej(e);
2827
+ for (const splitEntityId of splitEntityIds) {
2828
+ reqs.push(GetList({
2829
+ entityIds: splitEntityId,
2830
+ attrKey: attrKeyStr,
2831
+ dateTimeFrom: dateTimeFrom,
2832
+ dateTimeTo: dateTimeTo,
2833
+ api: api,
2834
+ req: req
2835
+ }));
2870
2836
  }
2871
- }));
2837
+ const res = yield Promise.all(reqs);
2838
+ const recordsByIds = {};
2839
+ let limitPerEntity = 0;
2840
+ for (const r of res) {
2841
+ limitPerEntity = r.limitPerEntity;
2842
+ for (const entityId in r.recordsByIds) {
2843
+ recordsByIds[entityId] = r.recordsByIds[entityId];
2844
+ }
2845
+ }
2846
+ // Returning merged data.
2847
+ return {
2848
+ recordsByIds: recordsByIds,
2849
+ limitPerEntity: limitPerEntity
2850
+ };
2851
+ }
2852
+ const cacheKey = GetListCacheKey(entityIds, attrKeyStr, dateTimeFrom, dateTimeTo);
2853
+ const cached = api.GetCacheItem(cacheKey, req);
2854
+ if (cached === null || cached === void 0 ? void 0 : cached.found) {
2855
+ return cached.data;
2856
+ }
2857
+ const urlParams = new URLSearchParams();
2858
+ for (const entityId of entityIds) {
2859
+ urlParams.append("entityId", entityId);
2860
+ }
2861
+ if (attrKeyStr) {
2862
+ urlParams.append("attrKey", attrKeyStr);
2863
+ }
2864
+ urlParams.append("dateTimeFrom", dateTimeFrom);
2865
+ urlParams.append("dateTimeTo", dateTimeTo);
2866
+ const prom = api.GET(`v1/entity/historicData?${urlParams.toString()}`, exports.Api.PrepReqParams(req));
2872
2867
  api.SetCacheItem({
2873
- key,
2868
+ key: cacheKey,
2874
2869
  value: prom,
2875
- req: reqParams
2870
+ req: req,
2871
+ // Short cache. 30 seconds.
2872
+ duration: 30000
2876
2873
  });
2877
2874
  return prom;
2878
2875
  });
2879
2876
  }
2880
- EntityType.Get = Get;
2881
- /**
2882
- * Deletes an entity type record and all corresponding entities.
2883
- * @param params
2884
- */
2885
- function Delete(params) {
2886
- return __awaiter(this, void 0, void 0, function* () {
2887
- let { api, entityTypeId: typeId, req: reqParams } = params;
2888
- if (!typeId) {
2889
- throw ("Type ID is required.");
2890
- }
2891
- if (!api) {
2892
- api = exports.ENVIRONMENT.Api().GetBruceApi();
2893
- }
2894
- yield api.DELETE(`entitytype/${typeId}`, exports.Api.PrepReqParams(reqParams));
2895
- api.Cache.RemoveByStartsWith(GetCacheKey(typeId));
2896
- api.Cache.RemoveByStartsWith(GetListCacheKey());
2897
- });
2898
- }
2899
- EntityType.Delete = Delete;
2877
+ EntityHistoricData.GetList = GetList;
2900
2878
  /**
2901
- * Gets a list of entity types.
2879
+ * Returns historic data statistics for an array of Entity IDs.
2902
2880
  * @param params
2903
2881
  * @returns
2904
2882
  */
2905
- function GetList(params) {
2883
+ function GetStats(params) {
2906
2884
  return __awaiter(this, void 0, void 0, function* () {
2907
- let { entityTypeIds, api, req: reqParams, parentTypeId, expandSettings, search, expandLODs } = params;
2885
+ let { entityIds, entityTypeId, api, req } = params;
2886
+ // Save time and just return a none response if no entity IDs or type ID are provided.
2887
+ if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length) && !entityTypeId) {
2888
+ return {
2889
+ stats: []
2890
+ };
2891
+ }
2908
2892
  if (!api) {
2909
2893
  api = exports.ENVIRONMENT.Api().GetBruceApi();
2910
2894
  }
2911
- const cache = api.GetCacheItem(GetListCacheKey({
2912
- typeIds: entityTypeIds,
2913
- parentTypeId,
2914
- expandLODs,
2915
- expandSettings,
2916
- search
2917
- }), reqParams);
2918
- if (cache === null || cache === void 0 ? void 0 : cache.found) {
2919
- return cache.data;
2920
- }
2921
- const req = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
2922
- try {
2923
- // If we have an array of typeIds then we'll request in batches to avoid overflowing the URL.
2924
- const BATCH_SIZE = 20;
2925
- const reqs = [];
2926
- if (entityTypeIds) {
2927
- for (let i = 0; i < entityTypeIds.length; i += BATCH_SIZE) {
2928
- const batch = entityTypeIds.slice(i, i + BATCH_SIZE);
2929
- const urlParams = new URLSearchParams();
2930
- for (const id of batch) {
2931
- urlParams.append("ID", id);
2932
- }
2933
- if (parentTypeId) {
2934
- urlParams.append("ParentTypeID", parentTypeId);
2935
- }
2936
- if (expandSettings && expandLODs) {
2937
- urlParams.append("Expand", "true");
2938
- }
2939
- else if (expandSettings) {
2940
- urlParams.append("Expand", "Schema");
2941
- }
2942
- else if (expandLODs) {
2943
- urlParams.append("Expand", "LOD");
2944
- }
2945
- if (search) {
2946
- urlParams.append("Search", search);
2947
- }
2948
- reqs.push(api.GET("entitytypes?" + urlParams.toString(), exports.Api.PrepReqParams(reqParams)));
2949
- }
2950
- }
2951
- else {
2952
- const urlParams = new URLSearchParams();
2953
- if (parentTypeId) {
2954
- urlParams.append("ParentTypeID", parentTypeId);
2955
- }
2956
- if (expandSettings && expandLODs) {
2957
- urlParams.append("Expand", "true");
2958
- }
2959
- else if (expandSettings) {
2960
- urlParams.append("Expand", "Schema");
2961
- }
2962
- else if (expandLODs) {
2963
- urlParams.append("Expand", "LOD");
2964
- }
2965
- if (search) {
2966
- urlParams.append("Search", search);
2967
- }
2968
- reqs.push(api.GET("entitytypes?" + urlParams.toString(), exports.Api.PrepReqParams(reqParams)));
2969
- }
2970
- const data = yield Promise.all(reqs);
2971
- // Populate array, while checking for already added types.
2972
- const types = [];
2973
- for (const item of data) {
2974
- for (const type of item.Items) {
2975
- appendInternalAttrSchema(type);
2976
- if (!types.find(x => x.ID == type.ID)) {
2977
- types.push(type);
2978
- }
2979
- }
2980
- }
2981
- res({
2982
- entityTypes: types
2983
- });
2984
- }
2985
- catch (e) {
2986
- rej(e);
2987
- }
2988
- }));
2989
- if (!parentTypeId) {
2990
- api.SetCacheItem({
2991
- key: GetListCacheKey({
2992
- typeIds: entityTypeIds,
2993
- parentTypeId,
2994
- expandSettings,
2995
- expandLODs,
2996
- search
2997
- }),
2998
- value: req,
2999
- req: reqParams,
3000
- duration: 60 * 5 // 5 minutes.
3001
- });
2895
+ req = exports.Api.PrepReqParams(req);
2896
+ const cacheKey = GetStatsCacheKey(entityIds, entityTypeId);
2897
+ const cached = api.GetCacheItem(cacheKey, req);
2898
+ if (cached === null || cached === void 0 ? void 0 : cached.found) {
2899
+ return cached.data;
3002
2900
  }
3003
- return req;
2901
+ const prom = yield api.POST("v1/entity/historicData/stats", {
2902
+ entityIds: entityIds,
2903
+ entityTypeId: entityTypeId
2904
+ }, req);
2905
+ api.SetCacheItem({
2906
+ key: cacheKey,
2907
+ value: prom,
2908
+ req: req,
2909
+ // Short cache. 60 seconds.
2910
+ duration: 60000
2911
+ });
2912
+ return prom;
3004
2913
  });
3005
2914
  }
3006
- EntityType.GetList = GetList;
2915
+ EntityHistoricData.GetStats = GetStats;
3007
2916
  /**
3008
- * Updates or creates an entity type record.
2917
+ * Creates or updates historic data records.
2918
+ * Please note that the expected input/output does not include internal fields found inside the "Bruce" attribute.
3009
2919
  * @param params
3010
2920
  * @returns
3011
2921
  */
3012
2922
  function Update(params) {
2923
+ var _a;
3013
2924
  return __awaiter(this, void 0, void 0, function* () {
3014
- let { api, entityType: data, req: reqParams } = params;
2925
+ let { records, api, req } = params;
2926
+ // Save time and just return a none response if no records are provided.
2927
+ if (!(records === null || records === void 0 ? void 0 : records.length)) {
2928
+ return {
2929
+ records: []
2930
+ };
2931
+ }
3015
2932
  if (!api) {
3016
2933
  api = exports.ENVIRONMENT.Api().GetBruceApi();
3017
2934
  }
3018
- if (!data) {
3019
- data = {};
3020
- }
3021
- if (!data.ID) {
3022
- data.ID = exports.ObjectUtils.UId();
2935
+ const res = yield api.POST("v1/entity/historicData", {
2936
+ records: records
2937
+ }, exports.Api.PrepReqParams(req));
2938
+ // Kill cache for every unique attrKey.
2939
+ let attrKeys = records.map(r => r.attrKey);
2940
+ attrKeys = attrKeys.filter((v, i) => attrKeys.indexOf(v) === i);
2941
+ for (const attrKey of attrKeys) {
2942
+ api.Cache.RemoveByContains(exports.Entity.GetHistoricContainsKey(attrKey));
3023
2943
  }
3024
- if (!data.Name) {
3025
- data.Name = data.ID;
2944
+ // Kill any stats cache that includes any of the Entity IDs.
2945
+ if ((_a = res.records) === null || _a === void 0 ? void 0 : _a.length) {
2946
+ const entityIds = res.records.map(r => r.entityId).filter((v, i) => v && res.records.indexOf(v) === i);
2947
+ ClearCacheByEntityIds(api, entityIds);
3026
2948
  }
3027
- // Will not append if we're not updating schema (not specified).
3028
- appendInternalAttrSchema(data);
3029
- const res = yield api.POST(`entitytype/${data.ID}`, data, exports.Api.PrepReqParams(reqParams));
3030
- api.Cache.RemoveByStartsWith(GetCacheKey(data.ID));
3031
- api.Cache.RemoveByStartsWith(GetListCacheKey());
3032
- // Useful to append afterwards as newly created Entity Types may have it missing.
3033
- // This makes our UI apps not have to check for default attribute existence.
3034
- appendInternalAttrSchema(res);
3035
- return {
3036
- entityType: res
3037
- };
2949
+ return res;
3038
2950
  });
3039
2951
  }
3040
- EntityType.Update = Update;
2952
+ EntityHistoricData.Update = Update;
3041
2953
  /**
3042
- * Starts a re-index background action on a specified Entity Type.
3043
- * This will ensure searchable data follows the current schema version.
3044
- * This will also perform certain data cleanup so that the data is consistent.
2954
+ * Deletes historic data records for an array of Entity IDs.
2955
+ * This deletes all records within a provided key + range.
3045
2956
  * @param params
3046
2957
  * @returns
3047
2958
  */
3048
- function ReIndex(params) {
2959
+ function Delete(params) {
3049
2960
  return __awaiter(this, void 0, void 0, function* () {
3050
- let { api, entityTypeId: typeId, req, dataTransformId, reSaveAll } = params;
2961
+ let { entityIds, attrKey, dateTimeFrom, dateTimeTo, api, req } = params;
2962
+ if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
2963
+ return;
2964
+ }
3051
2965
  if (!api) {
3052
2966
  api = exports.ENVIRONMENT.Api().GetBruceApi();
3053
2967
  }
3054
- const urlParams = new URLSearchParams();
3055
- if (dataTransformId) {
3056
- urlParams.append("dataTransformID", String(dataTransformId));
3057
- }
3058
- if (reSaveAll) {
3059
- urlParams.append("reSaveAll", "true");
2968
+ if (!attrKey || !dateTimeFrom || !dateTimeTo) {
2969
+ throw new Error("Invalid parameters provided.");
3060
2970
  }
3061
- let url = typeId ? `entityType/${typeId}/reindex` : "entities/reindex";
3062
- url += "?" + urlParams.toString();
3063
- req = exports.Api.PrepReqParams(req);
3064
- const res = yield api.POST(url, {}, req);
3065
- return {
3066
- pendingActionId: res.PendingActionID
3067
- };
3068
- });
3069
- }
3070
- EntityType.ReIndex = ReIndex;
3071
- /**
3072
- * Counts the total number of Entities in an Entity Type.
3073
- * @param params
3074
- * @returns
3075
- */
3076
- function Count(params) {
3077
- return __awaiter(this, void 0, void 0, function* () {
3078
- let { entityTypeId, api, req } = params;
3079
- if (!entityTypeId) {
3080
- throw ("Type ID is required.");
2971
+ if (typeof attrKey != "string") {
2972
+ attrKey = exports.PathUtils.Wrap(attrKey);
3081
2973
  }
3082
- if (!api) {
3083
- api = exports.ENVIRONMENT.Api().GetBruceApi();
2974
+ const urlParams = new URLSearchParams();
2975
+ for (const entityId of entityIds) {
2976
+ urlParams.append("entityId", entityId);
3084
2977
  }
3085
- const url = `entityType/${entityTypeId}/entitiesCount`;
3086
- const { TotalEntities } = yield api.GET(url, exports.Api.PrepReqParams(req));
3087
- return TotalEntities;
2978
+ urlParams.append("attrKey", attrKey);
2979
+ urlParams.append("dateTimeFrom", dateTimeFrom);
2980
+ urlParams.append("dateTimeTo", dateTimeTo);
2981
+ yield api.DELETE(`v1/entity/historicData?${urlParams.toString()}`, exports.Api.PrepReqParams(req));
2982
+ // Kill cache for all Entity cached Entity records related to the attrKey.
2983
+ api.Cache.RemoveByContains(exports.Entity.GetHistoricContainsKey(attrKey));
2984
+ // Kill any stats cache that includes any of the Entity IDs.
2985
+ ClearCacheByEntityIds(api, entityIds);
3088
2986
  });
3089
2987
  }
3090
- EntityType.Count = Count;
3091
- /**
3092
- * Returns cache identifier for an entity type.
3093
- * Example: {
3094
- * const api: BruceApi.Api = ...;
3095
- * const key = GetCacheKey("abc");
3096
- * api.Cache.Remove(key);
3097
- * }
3098
- * @param typeId
3099
- * @param expandLODs
3100
- * @returns
3101
- */
3102
- function GetCacheKey(typeId, expandLODs) {
3103
- let key = `${exports.Api.ECacheKey.EntityType}${exports.Api.ECacheKey.Id}${typeId}`;
3104
- if (expandLODs) {
3105
- key += "_LOD_" + expandLODs;
2988
+ EntityHistoricData.Delete = Delete;
2989
+ function GetListCacheKey(entityIds, attrKey, dateTimeFrom, dateTimeTo) {
2990
+ return exports.Api.ECacheKey.EntityHistoricDataRec + exports.Api.ECacheKey.Id + entityIds.join(",") + exports.Api.ECacheKey.Id + attrKey + exports.Api.ECacheKey.Id + dateTimeFrom + exports.Api.ECacheKey.Id + dateTimeTo;
2991
+ }
2992
+ EntityHistoricData.GetListCacheKey = GetListCacheKey;
2993
+ function GetStatsCacheKey(entityIds, typeId) {
2994
+ if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
2995
+ entityIds = [];
3106
2996
  }
3107
- return key;
2997
+ if (!typeId) {
2998
+ typeId = "";
2999
+ }
3000
+ return exports.Api.ECacheKey.EntityHistoricDataStats + exports.Api.ECacheKey.Id + typeId + exports.Api.ECacheKey.Id + entityIds.join(",");
3108
3001
  }
3109
- EntityType.GetCacheKey = GetCacheKey;
3002
+ EntityHistoricData.GetStatsCacheKey = GetStatsCacheKey;
3003
+ function ClearCacheByEntityIds(api, entityIds) {
3004
+ if (!api || !(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3005
+ return;
3006
+ }
3007
+ const REC_KEY_PREFIX = exports.Api.ECacheKey.EntityHistoricDataRec + exports.Api.ECacheKey.Id;
3008
+ const STATS_KEY_PREFIX = exports.Api.ECacheKey.EntityHistoricDataStats + exports.Api.ECacheKey.Id;
3009
+ api.Cache.RemoveByCallback((key) => {
3010
+ let keyStr = String(key);
3011
+ if (!keyStr.startsWith(STATS_KEY_PREFIX) && !keyStr.startsWith(REC_KEY_PREFIX)) {
3012
+ return false;
3013
+ }
3014
+ // Shorten to speed up the next step.
3015
+ keyStr = keyStr.replace(STATS_KEY_PREFIX, "").replace(REC_KEY_PREFIX, "");
3016
+ // Look for any matching Entity IDs.
3017
+ for (let i = 0; i < entityIds.length; i++) {
3018
+ const entityId = entityIds[i];
3019
+ if (keyStr.includes(entityId)) {
3020
+ return true;
3021
+ }
3022
+ }
3023
+ return false;
3024
+ });
3025
+ }
3026
+ EntityHistoricData.ClearCacheByEntityIds = ClearCacheByEntityIds;
3027
+ })(exports.EntityHistoricData || (exports.EntityHistoricData = {}));
3028
+
3029
+ /**
3030
+ * Describes an entity type schema attribute.
3031
+ */
3032
+ (function (EntityAttribute) {
3033
+ let EType;
3034
+ (function (EType) {
3035
+ // Arbitrary text attribute.
3036
+ EType["String"] = "String";
3037
+ // Floating point number attribute.
3038
+ EType["Double"] = "Double";
3039
+ // Whole number attribute.
3040
+ EType["Integer"] = "Integer";
3041
+ // iso8601 date time string.
3042
+ EType["Datetime"] = "Datetime";
3043
+ // Group of attributes.
3044
+ EType["Structure"] = "Structure";
3045
+ // Nextspace vector geometry.
3046
+ EType["Geometry"] = "Geometry";
3047
+ // True/false attribute.
3048
+ EType["Boolean"] = "Boolean";
3049
+ // String User ID.
3050
+ EType["User"] = "User";
3051
+ // String Group ID.
3052
+ EType["UserGroup"] = "UserGroup";
3053
+ // String Entity ID.
3054
+ EType["Entity"] = "Entity";
3055
+ // Url attribute.
3056
+ EType["Url"] = "Url";
3057
+ // Serial number that increments for each new entity/missing-attr-value.
3058
+ EType["Serial"] = "Serial";
3059
+ })(EType = EntityAttribute.EType || (EntityAttribute.EType = {}));
3110
3060
  /**
3111
- * Returns cache identifier for a list of entity types.
3112
- * Example: {
3113
- * const api: BruceApi.Api = ...;
3114
- * const key = GetListCacheKey();
3115
- * api.Cache.Remove(key);
3116
- * }
3117
- * @param typeIds
3061
+ * Describes url open behavior.
3062
+ */
3063
+ let EOpenBehavior;
3064
+ (function (EOpenBehavior) {
3065
+ EOpenBehavior["POPUP"] = "POPUP";
3066
+ EOpenBehavior["NEW_TAB"] = "NEW_TAB";
3067
+ })(EOpenBehavior = EntityAttribute.EOpenBehavior || (EntityAttribute.EOpenBehavior = {}));
3068
+ /**
3069
+ * Returns an attribute from a provided hierarchy of attributes.
3070
+ * Eg: Use the path: ["Bruce", "ID"] to find the "ID" attribute.
3071
+ * @param items
3072
+ * @param path
3118
3073
  * @returns
3119
3074
  */
3120
- function GetListCacheKey(params) {
3121
- if (!params) {
3122
- params = {};
3075
+ function GetAttribute(items, path) {
3076
+ if (!items || !path || !path.length) {
3077
+ return null;
3123
3078
  }
3124
- let { typeIds, expandSettings, parentTypeId, expandLODs, search } = params;
3125
- let key = exports.Api.ECacheKey.EntityType;
3126
- if (!typeIds) {
3127
- typeIds = [];
3079
+ const key = path[0];
3080
+ const item = items.find((i) => i.Key === key);
3081
+ if (!item) {
3082
+ return null;
3128
3083
  }
3129
- key += (typeIds.length ? exports.Api.ECacheKey.Id : "") + typeIds.join(",");
3130
- if (parentTypeId) {
3131
- key += "_PARENT_" + parentTypeId;
3084
+ if (path.length === 1) {
3085
+ return item;
3132
3086
  }
3133
- if (!expandSettings) {
3134
- expandSettings = false;
3087
+ return GetAttribute(item.Structure, path.slice(1));
3088
+ }
3089
+ EntityAttribute.GetAttribute = GetAttribute;
3090
+ /**
3091
+ * Removes an attribute from a provided hierarchy of attributes.
3092
+ * Eg: Use the path: ["Bruce", "ID"] to remove the "ID" attribute.
3093
+ * This will mutate the items array.
3094
+ * @param items
3095
+ * @param path
3096
+ */
3097
+ function RemoveAttribute(items, path) {
3098
+ if (!items || !(path === null || path === void 0 ? void 0 : path.length)) {
3099
+ return;
3135
3100
  }
3136
- if (!expandLODs) {
3137
- expandLODs = false;
3101
+ const key = path[0];
3102
+ if (path.length === 1) {
3103
+ // If we're at the last key in the path, remove the item from the items array.
3104
+ const index = items.findIndex((i) => i.Key === key);
3105
+ if (index !== -1) {
3106
+ items.splice(index, 1);
3107
+ }
3108
+ return;
3138
3109
  }
3139
- key += "_SCHEMA_" + expandSettings;
3140
- key += "_LOD_" + expandLODs;
3141
- if (search) {
3142
- key += "_SEARCH_" + search;
3110
+ // If we're not at the end of the path, dig further.
3111
+ const item = items.find((i) => i.Key === key);
3112
+ if (item && item.Structure) {
3113
+ RemoveAttribute(item.Structure, path.slice(1));
3143
3114
  }
3144
- return key;
3145
- }
3146
- EntityType.GetListCacheKey = GetListCacheKey;
3147
- })(exports.EntityType || (exports.EntityType = {}));
3148
- /**
3149
- * Adds expected internal structure items even if they aren't there.
3150
- * Our API should be including them but this is a safety net.
3151
- * @param type
3152
- */
3153
- function appendInternalAttrSchema(type) {
3154
- // Schema not loaded. We'll ignore.
3155
- if (type == null || type.DataSchema == null) {
3156
- return;
3157
- }
3158
- // Append internal attributes.
3159
- if (!type.DataSchema.Structure) {
3160
- type.DataSchema.Structure = [];
3161
- }
3162
- let bruce = type.DataSchema.Structure.find(a => a.Key == "Bruce");
3163
- if (!bruce) {
3164
- bruce = {
3165
- Key: "Bruce",
3166
- Name: "Bruce",
3167
- Description: "Nextspace internal attributes.",
3168
- Type: exports.EntityAttribute.EType.Structure,
3169
- Structure: [],
3170
- IsIndexed: true,
3171
- IsImportant: false
3172
- };
3173
- type.DataSchema.Structure.push(bruce);
3174
- }
3175
- if (!bruce.Structure) {
3176
- bruce.Structure = [];
3177
- }
3178
- // Append any missing internal attributes.
3179
- if (!bruce.Structure.find(x => x.Key == "ID")) {
3180
- bruce.Structure.push({
3181
- Key: "ID",
3182
- Name: "ID",
3183
- Description: "Unique identifier for the Entity.",
3184
- Type: exports.EntityAttribute.EType.String,
3185
- IsIndexed: true,
3186
- IsImportant: true
3187
- });
3188
- }
3189
- if (!bruce.Structure.find(x => x.Key == "Location")) {
3190
- bruce.Structure.push({
3191
- Key: "Location",
3192
- Name: "Location",
3193
- Description: "Location data.",
3194
- Type: exports.EntityAttribute.EType.Structure,
3195
- Structure: [
3196
- {
3197
- Key: "latitude",
3198
- Name: "Latitude",
3199
- Type: exports.EntityAttribute.EType.Double,
3200
- IsIndexed: true,
3201
- IsImportant: false
3202
- },
3203
- {
3204
- Key: "longitude",
3205
- Name: "Longitude",
3206
- Type: exports.EntityAttribute.EType.Double,
3207
- IsIndexed: true,
3208
- IsImportant: false
3209
- },
3210
- {
3211
- Key: "altitude",
3212
- Name: "Altitude",
3213
- Type: exports.EntityAttribute.EType.Double,
3214
- IsIndexed: true,
3215
- IsImportant: false
3216
- }
3217
- ]
3218
- });
3219
- }
3220
- if (!bruce.Structure.find(x => x.Key == "Boundaries")) {
3221
- bruce.Structure.push({
3222
- Key: "Boundaries",
3223
- Name: "Boundaries",
3224
- Description: "Boundaries data.",
3225
- Type: exports.EntityAttribute.EType.Structure,
3226
- Structure: [
3227
- {
3228
- Key: "minLongitude",
3229
- Name: "Min Longitude",
3230
- Type: exports.EntityAttribute.EType.Double,
3231
- IsIndexed: true,
3232
- IsImportant: false
3233
- },
3234
- {
3235
- Key: "maxLongitude",
3236
- Name: "Max Longitude",
3237
- Type: exports.EntityAttribute.EType.Double,
3238
- IsIndexed: true,
3239
- IsImportant: false
3240
- },
3241
- {
3242
- Key: "minLatitude",
3243
- Name: "Min Latitude",
3244
- Type: exports.EntityAttribute.EType.Double,
3245
- IsIndexed: true,
3246
- IsImportant: false
3247
- },
3248
- {
3249
- Key: "maxLatitude",
3250
- Name: "Max Latitude",
3251
- Type: exports.EntityAttribute.EType.Double,
3252
- IsIndexed: true,
3253
- IsImportant: false
3254
- },
3255
- {
3256
- Key: "minAltitude",
3257
- Name: "Min Altitude",
3258
- Type: exports.EntityAttribute.EType.Double,
3259
- IsIndexed: true,
3260
- IsImportant: false
3261
- },
3262
- {
3263
- Key: "maxAltitude",
3264
- Name: "Max Altitude",
3265
- Type: exports.EntityAttribute.EType.Double,
3266
- IsIndexed: true,
3267
- IsImportant: false
3268
- }
3269
- ]
3270
- });
3271
3115
  }
3272
- if (!bruce.Structure.find(x => x.Key == "Transform")) {
3273
- bruce.Structure.push({
3274
- Key: "Transform",
3275
- Name: "Transform",
3276
- Description: "Transform data.",
3277
- IsIndexed: true,
3278
- IsImportant: false,
3279
- Type: exports.EntityAttribute.EType.Structure,
3280
- Structure: [
3281
- {
3282
- Key: "heading",
3283
- Name: "Heading",
3284
- IsIndexed: true,
3285
- IsImportant: false,
3286
- Type: exports.EntityAttribute.EType.Double
3287
- },
3288
- {
3289
- Key: "pitch",
3290
- Name: "Pitch",
3291
- IsIndexed: true,
3292
- IsImportant: false,
3293
- Type: exports.EntityAttribute.EType.Double
3294
- },
3295
- {
3296
- Key: "roll",
3297
- Name: "Roll",
3298
- IsIndexed: true,
3299
- IsImportant: false,
3300
- Type: exports.EntityAttribute.EType.Double
3301
- },
3302
- {
3303
- Key: "scale",
3304
- Name: "Scale",
3305
- IsIndexed: true,
3306
- IsImportant: false,
3307
- Type: exports.EntityAttribute.EType.Double
3308
- }
3309
- ]
3310
- });
3311
- }
3312
- if (!bruce.Structure.find(x => x.Key == "VectorGeometry")) {
3313
- bruce.Structure.push({
3314
- Key: "VectorGeometry",
3315
- Name: "Geometry",
3316
- Description: "Geometry data.",
3317
- Type: exports.EntityAttribute.EType.Geometry,
3318
- IsIndexed: true,
3319
- IsImportant: false
3320
- });
3321
- }
3322
- // Filter out migrated/outdated ones.
3323
- // Removed from root and the internal structure.
3324
- const OUTDATED_INTERNAL = ["position", "geometry", "location", "boundaries", "transform"];
3325
- bruce.Structure = bruce.Structure.filter(a => !OUTDATED_INTERNAL.includes(a.Key));
3326
- type.DataSchema.Structure = type.DataSchema.Structure.filter(a => !OUTDATED_INTERNAL.includes(a.Key));
3327
- }
3328
-
3329
- /**
3330
- * Utility to help with parsing and wrapping Nextspace paths.
3331
- */
3332
- (function (PathUtils) {
3116
+ EntityAttribute.RemoveAttribute = RemoveAttribute;
3333
3117
  /**
3334
- * Parses a Bruce string path into an array of strings.
3335
- * Example of path: "\"location\"/\"latitude\"" or "location/latitude".
3336
- * @param str
3337
- * @returns
3118
+ * Adds an attribute to a provided hierarchy of attributes.
3119
+ * Eg: Use the path: ["Bruce", "ID"] to add the "ID" attribute.
3120
+ * This will mutate the items array.
3121
+ * This requires the path to be valid and for a parent attribute to exist.
3122
+ * @param items
3123
+ * @param path
3124
+ * @param attribute
3338
3125
  */
3339
- function Parse(str) {
3340
- if (!(str === null || str === void 0 ? void 0 : str.length)) {
3341
- return [];
3126
+ function AddAttribute(items, path, attribute) {
3127
+ if (!items || !(path === null || path === void 0 ? void 0 : path.length)) {
3128
+ return;
3342
3129
  }
3343
- const broken = str.split("/");
3344
- // Remove quotes from the first and last chars.
3345
- for (let i = 0; i < broken.length; i++) {
3346
- let piece = broken[i];
3347
- if (piece.startsWith("\"")) {
3348
- piece = piece.substring(1);
3130
+ const key = path[0];
3131
+ if (path.length === 1) {
3132
+ // If we're at the last key in the path, add the attribute to the items array.
3133
+ const index = items.findIndex((i) => i.Key === key);
3134
+ if (index !== -1) {
3135
+ // Overwrite existing attribute if it already exists.
3136
+ items[index] = attribute;
3349
3137
  }
3350
- if (piece.endsWith("\"")) {
3351
- piece = piece.substring(0, piece.length - 1);
3138
+ else {
3139
+ // Add new attribute if it doesn't exist.
3140
+ items.push(attribute);
3352
3141
  }
3353
- broken[i] = piece;
3142
+ return;
3354
3143
  }
3355
- return broken;
3144
+ // If we're not at the end of the path, dig further.
3145
+ let item = items.find((i) => i.Key === key);
3146
+ if (!item) {
3147
+ item = { Key: key, Structure: [] };
3148
+ items.push(item);
3149
+ }
3150
+ if (!item.Structure) {
3151
+ item.Structure = [];
3152
+ }
3153
+ AddAttribute(item.Structure, path.slice(1), attribute);
3356
3154
  }
3357
- PathUtils.Parse = Parse;
3155
+ EntityAttribute.AddAttribute = AddAttribute;
3156
+ })(exports.EntityAttribute || (exports.EntityAttribute = {}));
3157
+
3158
+ (function (EntityType) {
3358
3159
  /**
3359
- * Wraps an array of strings into a Nextspace string path.
3360
- * @param path
3160
+ * Gets an entity type record.
3161
+ * @param params
3361
3162
  * @returns
3362
3163
  */
3363
- function Wrap(path) {
3364
- if (!(path === null || path === void 0 ? void 0 : path.length)) {
3365
- return "";
3366
- }
3367
- let tmp = "\"";
3368
- for (let i = 0; i < path.length; i++) {
3369
- let section = path[i];
3370
- tmp += section;
3371
- if (i < path.length - 1) {
3372
- tmp += "\"/\"";
3164
+ function Get(params) {
3165
+ return __awaiter(this, void 0, void 0, function* () {
3166
+ let { api, entityTypeId: typeId, req: reqParams, expandLODs } = params;
3167
+ if (!typeId) {
3168
+ throw ("Type ID is required.");
3169
+ }
3170
+ if (!api) {
3171
+ api = exports.ENVIRONMENT.Api().GetBruceApi();
3172
+ }
3173
+ const key = GetCacheKey(typeId, expandLODs);
3174
+ const cache = api.GetCacheItem(key, reqParams);
3175
+ if (cache === null || cache === void 0 ? void 0 : cache.found) {
3176
+ return cache.data;
3373
3177
  }
3374
- }
3375
- tmp += "\"";
3376
- return tmp;
3178
+ const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
3179
+ try {
3180
+ const urlParams = new URLSearchParams();
3181
+ if (expandLODs) {
3182
+ urlParams.append("Expand", "LOD");
3183
+ }
3184
+ const url = `entitytype/${typeId}?${urlParams.toString()}`;
3185
+ const data = yield api.GET(url, exports.Api.PrepReqParams(reqParams));
3186
+ appendInternalAttrSchema(data);
3187
+ res({
3188
+ entityType: data
3189
+ });
3190
+ }
3191
+ catch (e) {
3192
+ rej(e);
3193
+ }
3194
+ }));
3195
+ api.SetCacheItem({
3196
+ key,
3197
+ value: prom,
3198
+ req: reqParams
3199
+ });
3200
+ return prom;
3201
+ });
3377
3202
  }
3378
- PathUtils.Wrap = Wrap;
3203
+ EntityType.Get = Get;
3379
3204
  /**
3380
- * Parses a Nextspace legacy string path into an array of strings.
3381
- * @param str
3382
- * @returns
3205
+ * Deletes an entity type record and all corresponding entities.
3206
+ * @param params
3383
3207
  */
3384
- function ParseLegacy(str) {
3385
- if (!(str === null || str === void 0 ? void 0 : str.length)) {
3386
- return [];
3387
- }
3388
- const broken = str.split(".");
3389
- for (let i = 0; i < broken.length; i++) {
3390
- let piece = broken[i];
3391
- if (piece.startsWith("\"")) {
3392
- piece = piece.substring(1);
3208
+ function Delete(params) {
3209
+ return __awaiter(this, void 0, void 0, function* () {
3210
+ let { api, entityTypeId: typeId, req: reqParams } = params;
3211
+ if (!typeId) {
3212
+ throw ("Type ID is required.");
3393
3213
  }
3394
- if (piece.endsWith("\"")) {
3395
- piece = piece.substring(0, piece.length - 1);
3214
+ if (!api) {
3215
+ api = exports.ENVIRONMENT.Api().GetBruceApi();
3396
3216
  }
3397
- broken[i] = piece;
3398
- }
3399
- return broken;
3217
+ yield api.DELETE(`entitytype/${typeId}`, exports.Api.PrepReqParams(reqParams));
3218
+ api.Cache.RemoveByStartsWith(GetCacheKey(typeId));
3219
+ api.Cache.RemoveByStartsWith(GetListCacheKey());
3220
+ });
3400
3221
  }
3401
- PathUtils.ParseLegacy = ParseLegacy;
3402
- })(exports.PathUtils || (exports.PathUtils = {}));
3403
-
3404
- (function (EntityHistoricData) {
3222
+ EntityType.Delete = Delete;
3405
3223
  /**
3406
- * Returns historic data for an array of Entity IDs.
3407
- * A maximum number of records will be returned per Entity ID, this information is returned in the response.
3224
+ * Gets a list of entity types.
3408
3225
  * @param params
3409
3226
  * @returns
3410
3227
  */
3411
3228
  function GetList(params) {
3412
3229
  return __awaiter(this, void 0, void 0, function* () {
3413
- let { entityIds, attrKey, dateTimeFrom, dateTimeTo, api, req } = params;
3414
- // Save time and just return a none response if no entity IDs are provided.
3415
- if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3416
- return {
3417
- limitPerEntity: 0,
3418
- recordsByIds: {}
3419
- };
3420
- }
3230
+ let { entityTypeIds, api, req: reqParams, parentTypeId, expandSettings, search, expandLODs } = params;
3421
3231
  if (!api) {
3422
3232
  api = exports.ENVIRONMENT.Api().GetBruceApi();
3423
3233
  }
3424
- let attrKeyStr = null;
3425
- if (attrKey) {
3426
- if (typeof attrKey != "string") {
3427
- attrKeyStr = exports.PathUtils.Wrap(attrKey);
3428
- }
3429
- else {
3430
- attrKeyStr = attrKey;
3431
- }
3234
+ const cache = api.GetCacheItem(GetListCacheKey({
3235
+ typeIds: entityTypeIds,
3236
+ parentTypeId,
3237
+ expandLODs,
3238
+ expandSettings,
3239
+ search
3240
+ }), reqParams);
3241
+ if (cache === null || cache === void 0 ? void 0 : cache.found) {
3242
+ return cache.data;
3432
3243
  }
3433
- // If we have more than 100 Entity IDs we'll have to split the request to avoid a URL that is too long.
3434
- const MAX_IDS = 100;
3435
- // We will recursively call this function to get all the data.
3436
- // Then merge at the end and return.
3437
- if (entityIds.length > MAX_IDS) {
3438
- const reqs = [];
3439
- // Making the ID batches.
3440
- // If this is too long we can end up in a loop.
3441
- const splitEntityIds = [];
3442
- for (let i = 0; i < entityIds.length; i += MAX_IDS) {
3443
- const batchIds = entityIds.slice(i, i + MAX_IDS);
3444
- // Detecting this early to avoid infinite loops.
3445
- if (batchIds.length > MAX_IDS) {
3446
- throw new Error("Nextspace Developer Error: EntityHistoricData.GetList() has too many Entity IDs. Please contact support.");
3244
+ const req = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
3245
+ try {
3246
+ // If we have an array of typeIds then we'll request in batches to avoid overflowing the URL.
3247
+ const BATCH_SIZE = 20;
3248
+ const reqs = [];
3249
+ if (entityTypeIds) {
3250
+ for (let i = 0; i < entityTypeIds.length; i += BATCH_SIZE) {
3251
+ const batch = entityTypeIds.slice(i, i + BATCH_SIZE);
3252
+ const urlParams = new URLSearchParams();
3253
+ for (const id of batch) {
3254
+ urlParams.append("ID", id);
3255
+ }
3256
+ if (parentTypeId) {
3257
+ urlParams.append("ParentTypeID", parentTypeId);
3258
+ }
3259
+ if (expandSettings && expandLODs) {
3260
+ urlParams.append("Expand", "true");
3261
+ }
3262
+ else if (expandSettings) {
3263
+ urlParams.append("Expand", "Schema");
3264
+ }
3265
+ else if (expandLODs) {
3266
+ urlParams.append("Expand", "LOD");
3267
+ }
3268
+ if (search) {
3269
+ urlParams.append("Search", search);
3270
+ }
3271
+ reqs.push(api.GET("entitytypes?" + urlParams.toString(), exports.Api.PrepReqParams(reqParams)));
3272
+ }
3447
3273
  }
3448
- splitEntityIds.push(batchIds);
3449
- }
3450
- for (const splitEntityId of splitEntityIds) {
3451
- reqs.push(GetList({
3452
- entityIds: splitEntityId,
3453
- attrKey: attrKeyStr,
3454
- dateTimeFrom: dateTimeFrom,
3455
- dateTimeTo: dateTimeTo,
3456
- api: api,
3457
- req: req
3458
- }));
3459
- }
3460
- const res = yield Promise.all(reqs);
3461
- const recordsByIds = {};
3462
- let limitPerEntity = 0;
3463
- for (const r of res) {
3464
- limitPerEntity = r.limitPerEntity;
3465
- for (const entityId in r.recordsByIds) {
3466
- recordsByIds[entityId] = r.recordsByIds[entityId];
3274
+ else {
3275
+ const urlParams = new URLSearchParams();
3276
+ if (parentTypeId) {
3277
+ urlParams.append("ParentTypeID", parentTypeId);
3278
+ }
3279
+ if (expandSettings && expandLODs) {
3280
+ urlParams.append("Expand", "true");
3281
+ }
3282
+ else if (expandSettings) {
3283
+ urlParams.append("Expand", "Schema");
3284
+ }
3285
+ else if (expandLODs) {
3286
+ urlParams.append("Expand", "LOD");
3287
+ }
3288
+ if (search) {
3289
+ urlParams.append("Search", search);
3290
+ }
3291
+ reqs.push(api.GET("entitytypes?" + urlParams.toString(), exports.Api.PrepReqParams(reqParams)));
3292
+ }
3293
+ const data = yield Promise.all(reqs);
3294
+ // Populate array, while checking for already added types.
3295
+ const types = [];
3296
+ for (const item of data) {
3297
+ for (const type of item.Items) {
3298
+ appendInternalAttrSchema(type);
3299
+ if (!types.find(x => x.ID == type.ID)) {
3300
+ types.push(type);
3301
+ }
3302
+ }
3467
3303
  }
3304
+ res({
3305
+ entityTypes: types
3306
+ });
3468
3307
  }
3469
- // Returning merged data.
3470
- return {
3471
- recordsByIds: recordsByIds,
3472
- limitPerEntity: limitPerEntity
3473
- };
3308
+ catch (e) {
3309
+ rej(e);
3310
+ }
3311
+ }));
3312
+ if (!parentTypeId) {
3313
+ api.SetCacheItem({
3314
+ key: GetListCacheKey({
3315
+ typeIds: entityTypeIds,
3316
+ parentTypeId,
3317
+ expandSettings,
3318
+ expandLODs,
3319
+ search
3320
+ }),
3321
+ value: req,
3322
+ req: reqParams,
3323
+ duration: 60 * 5 // 5 minutes.
3324
+ });
3474
3325
  }
3475
- const cacheKey = GetListCacheKey(entityIds, attrKeyStr, dateTimeFrom, dateTimeTo);
3476
- const cached = api.GetCacheItem(cacheKey, req);
3477
- if (cached === null || cached === void 0 ? void 0 : cached.found) {
3478
- return cached.data;
3326
+ return req;
3327
+ });
3328
+ }
3329
+ EntityType.GetList = GetList;
3330
+ /**
3331
+ * Updates or creates an entity type record.
3332
+ * @param params
3333
+ * @returns
3334
+ */
3335
+ function Update(params) {
3336
+ return __awaiter(this, void 0, void 0, function* () {
3337
+ let { api, entityType: data, req: reqParams } = params;
3338
+ if (!api) {
3339
+ api = exports.ENVIRONMENT.Api().GetBruceApi();
3479
3340
  }
3480
- const urlParams = new URLSearchParams();
3481
- for (const entityId of entityIds) {
3482
- urlParams.append("entityId", entityId);
3341
+ if (!data) {
3342
+ data = {};
3483
3343
  }
3484
- if (attrKeyStr) {
3485
- urlParams.append("attrKey", attrKeyStr);
3344
+ if (!data.ID) {
3345
+ data.ID = exports.ObjectUtils.UId();
3486
3346
  }
3487
- urlParams.append("dateTimeFrom", dateTimeFrom);
3488
- urlParams.append("dateTimeTo", dateTimeTo);
3489
- const prom = api.GET(`v1/entity/historicData?${urlParams.toString()}`, exports.Api.PrepReqParams(req));
3490
- api.SetCacheItem({
3491
- key: cacheKey,
3492
- value: prom,
3493
- req: req,
3494
- // Short cache. 30 seconds.
3495
- duration: 30000
3496
- });
3497
- return prom;
3347
+ if (!data.Name) {
3348
+ data.Name = data.ID;
3349
+ }
3350
+ // Will not append if we're not updating schema (not specified).
3351
+ appendInternalAttrSchema(data);
3352
+ const res = yield api.POST(`entitytype/${data.ID}`, data, exports.Api.PrepReqParams(reqParams));
3353
+ api.Cache.RemoveByStartsWith(GetCacheKey(data.ID));
3354
+ api.Cache.RemoveByStartsWith(GetListCacheKey());
3355
+ // Useful to append afterwards as newly created Entity Types may have it missing.
3356
+ // This makes our UI apps not have to check for default attribute existence.
3357
+ appendInternalAttrSchema(res);
3358
+ return {
3359
+ entityType: res
3360
+ };
3498
3361
  });
3499
3362
  }
3500
- EntityHistoricData.GetList = GetList;
3363
+ EntityType.Update = Update;
3501
3364
  /**
3502
- * Returns historic data statistics for an array of Entity IDs.
3365
+ * Starts a re-index background action on a specified Entity Type.
3366
+ * This will ensure searchable data follows the current schema version.
3367
+ * This will also perform certain data cleanup so that the data is consistent.
3503
3368
  * @param params
3504
3369
  * @returns
3505
3370
  */
3506
- function GetStats(params) {
3371
+ function ReIndex(params) {
3507
3372
  return __awaiter(this, void 0, void 0, function* () {
3508
- let { entityIds, entityTypeId, api, req } = params;
3509
- // Save time and just return a none response if no entity IDs or type ID are provided.
3510
- if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length) && !entityTypeId) {
3511
- return {
3512
- stats: []
3513
- };
3514
- }
3373
+ let { api, entityTypeId: typeId, req, dataTransformId, reSaveAll } = params;
3515
3374
  if (!api) {
3516
3375
  api = exports.ENVIRONMENT.Api().GetBruceApi();
3517
3376
  }
3518
- req = exports.Api.PrepReqParams(req);
3519
- const cacheKey = GetStatsCacheKey(entityIds, entityTypeId);
3520
- const cached = api.GetCacheItem(cacheKey, req);
3521
- if (cached === null || cached === void 0 ? void 0 : cached.found) {
3522
- return cached.data;
3377
+ const urlParams = new URLSearchParams();
3378
+ if (dataTransformId) {
3379
+ urlParams.append("dataTransformID", String(dataTransformId));
3523
3380
  }
3524
- const prom = yield api.POST("v1/entity/historicData/stats", {
3525
- entityIds: entityIds,
3526
- entityTypeId: entityTypeId
3527
- }, req);
3528
- api.SetCacheItem({
3529
- key: cacheKey,
3530
- value: prom,
3531
- req: req,
3532
- // Short cache. 60 seconds.
3533
- duration: 60000
3534
- });
3535
- return prom;
3381
+ if (reSaveAll) {
3382
+ urlParams.append("reSaveAll", "true");
3383
+ }
3384
+ let url = typeId ? `entityType/${typeId}/reindex` : "entities/reindex";
3385
+ url += "?" + urlParams.toString();
3386
+ req = exports.Api.PrepReqParams(req);
3387
+ const res = yield api.POST(url, {}, req);
3388
+ return {
3389
+ pendingActionId: res.PendingActionID
3390
+ };
3536
3391
  });
3537
3392
  }
3538
- EntityHistoricData.GetStats = GetStats;
3393
+ EntityType.ReIndex = ReIndex;
3539
3394
  /**
3540
- * Creates or updates historic data records.
3541
- * Please note that the expected input/output does not include internal fields found inside the "Bruce" attribute.
3395
+ * Counts the total number of Entities in an Entity Type.
3542
3396
  * @param params
3543
3397
  * @returns
3544
3398
  */
3545
- function Update(params) {
3546
- var _a;
3399
+ function Count(params) {
3547
3400
  return __awaiter(this, void 0, void 0, function* () {
3548
- let { records, api, req } = params;
3549
- // Save time and just return a none response if no records are provided.
3550
- if (!(records === null || records === void 0 ? void 0 : records.length)) {
3551
- return {
3552
- records: []
3553
- };
3401
+ let { entityTypeId, api, req } = params;
3402
+ if (!entityTypeId) {
3403
+ throw ("Type ID is required.");
3554
3404
  }
3555
3405
  if (!api) {
3556
3406
  api = exports.ENVIRONMENT.Api().GetBruceApi();
3557
3407
  }
3558
- const res = yield api.POST("v1/entity/historicData", {
3559
- records: records
3560
- }, exports.Api.PrepReqParams(req));
3561
- // Kill cache for every unique attrKey.
3562
- let attrKeys = records.map(r => r.attrKey);
3563
- attrKeys = attrKeys.filter((v, i) => attrKeys.indexOf(v) === i);
3564
- for (const attrKey of attrKeys) {
3565
- api.Cache.RemoveByContains(exports.Entity.GetHistoricContainsKey(attrKey));
3566
- }
3567
- // Kill any stats cache that includes any of the Entity IDs.
3568
- if ((_a = res.records) === null || _a === void 0 ? void 0 : _a.length) {
3569
- const entityIds = res.records.map(r => r.entityId).filter((v, i) => v && res.records.indexOf(v) === i);
3570
- ClearCacheByEntityIds(api, entityIds);
3571
- }
3572
- return res;
3408
+ const url = `entityType/${entityTypeId}/entitiesCount`;
3409
+ const { TotalEntities } = yield api.GET(url, exports.Api.PrepReqParams(req));
3410
+ return TotalEntities;
3411
+ });
3412
+ }
3413
+ EntityType.Count = Count;
3414
+ /**
3415
+ * Returns cache identifier for an entity type.
3416
+ * Example: {
3417
+ * const api: BruceApi.Api = ...;
3418
+ * const key = GetCacheKey("abc");
3419
+ * api.Cache.Remove(key);
3420
+ * }
3421
+ * @param typeId
3422
+ * @param expandLODs
3423
+ * @returns
3424
+ */
3425
+ function GetCacheKey(typeId, expandLODs) {
3426
+ let key = `${exports.Api.ECacheKey.EntityType}${exports.Api.ECacheKey.Id}${typeId}`;
3427
+ if (expandLODs) {
3428
+ key += "_LOD_" + expandLODs;
3429
+ }
3430
+ return key;
3431
+ }
3432
+ EntityType.GetCacheKey = GetCacheKey;
3433
+ /**
3434
+ * Returns cache identifier for a list of entity types.
3435
+ * Example: {
3436
+ * const api: BruceApi.Api = ...;
3437
+ * const key = GetListCacheKey();
3438
+ * api.Cache.Remove(key);
3439
+ * }
3440
+ * @param typeIds
3441
+ * @returns
3442
+ */
3443
+ function GetListCacheKey(params) {
3444
+ if (!params) {
3445
+ params = {};
3446
+ }
3447
+ let { typeIds, expandSettings, parentTypeId, expandLODs, search } = params;
3448
+ let key = exports.Api.ECacheKey.EntityType;
3449
+ if (!typeIds) {
3450
+ typeIds = [];
3451
+ }
3452
+ key += (typeIds.length ? exports.Api.ECacheKey.Id : "") + typeIds.join(",");
3453
+ if (parentTypeId) {
3454
+ key += "_PARENT_" + parentTypeId;
3455
+ }
3456
+ if (!expandSettings) {
3457
+ expandSettings = false;
3458
+ }
3459
+ if (!expandLODs) {
3460
+ expandLODs = false;
3461
+ }
3462
+ key += "_SCHEMA_" + expandSettings;
3463
+ key += "_LOD_" + expandLODs;
3464
+ if (search) {
3465
+ key += "_SEARCH_" + search;
3466
+ }
3467
+ return key;
3468
+ }
3469
+ EntityType.GetListCacheKey = GetListCacheKey;
3470
+ })(exports.EntityType || (exports.EntityType = {}));
3471
+ /**
3472
+ * Adds expected internal structure items even if they aren't there.
3473
+ * Our API should be including them but this is a safety net.
3474
+ * @param type
3475
+ */
3476
+ function appendInternalAttrSchema(type) {
3477
+ // Schema not loaded. We'll ignore.
3478
+ if (type == null || type.DataSchema == null) {
3479
+ return;
3480
+ }
3481
+ // Append internal attributes.
3482
+ if (!type.DataSchema.Structure) {
3483
+ type.DataSchema.Structure = [];
3484
+ }
3485
+ let bruce = type.DataSchema.Structure.find(a => a.Key == "Bruce");
3486
+ if (!bruce) {
3487
+ bruce = {
3488
+ Key: "Bruce",
3489
+ Name: "Bruce",
3490
+ Description: "Nextspace internal attributes.",
3491
+ Type: exports.EntityAttribute.EType.Structure,
3492
+ Structure: [],
3493
+ IsIndexed: true,
3494
+ IsImportant: false
3495
+ };
3496
+ type.DataSchema.Structure.push(bruce);
3497
+ }
3498
+ if (!bruce.Structure) {
3499
+ bruce.Structure = [];
3500
+ }
3501
+ // Append any missing internal attributes.
3502
+ if (!bruce.Structure.find(x => x.Key == "ID")) {
3503
+ bruce.Structure.push({
3504
+ Key: "ID",
3505
+ Name: "ID",
3506
+ Description: "Unique identifier for the Entity.",
3507
+ Type: exports.EntityAttribute.EType.String,
3508
+ IsIndexed: true,
3509
+ IsImportant: true
3510
+ });
3511
+ }
3512
+ if (!bruce.Structure.find(x => x.Key == "Location")) {
3513
+ bruce.Structure.push({
3514
+ Key: "Location",
3515
+ Name: "Location",
3516
+ Description: "Location data.",
3517
+ Type: exports.EntityAttribute.EType.Structure,
3518
+ Structure: [
3519
+ {
3520
+ Key: "latitude",
3521
+ Name: "Latitude",
3522
+ Type: exports.EntityAttribute.EType.Double,
3523
+ IsIndexed: true,
3524
+ IsImportant: false
3525
+ },
3526
+ {
3527
+ Key: "longitude",
3528
+ Name: "Longitude",
3529
+ Type: exports.EntityAttribute.EType.Double,
3530
+ IsIndexed: true,
3531
+ IsImportant: false
3532
+ },
3533
+ {
3534
+ Key: "altitude",
3535
+ Name: "Altitude",
3536
+ Type: exports.EntityAttribute.EType.Double,
3537
+ IsIndexed: true,
3538
+ IsImportant: false
3539
+ }
3540
+ ]
3541
+ });
3542
+ }
3543
+ if (!bruce.Structure.find(x => x.Key == "Boundaries")) {
3544
+ bruce.Structure.push({
3545
+ Key: "Boundaries",
3546
+ Name: "Boundaries",
3547
+ Description: "Boundaries data.",
3548
+ Type: exports.EntityAttribute.EType.Structure,
3549
+ Structure: [
3550
+ {
3551
+ Key: "minLongitude",
3552
+ Name: "Min Longitude",
3553
+ Type: exports.EntityAttribute.EType.Double,
3554
+ IsIndexed: true,
3555
+ IsImportant: false
3556
+ },
3557
+ {
3558
+ Key: "maxLongitude",
3559
+ Name: "Max Longitude",
3560
+ Type: exports.EntityAttribute.EType.Double,
3561
+ IsIndexed: true,
3562
+ IsImportant: false
3563
+ },
3564
+ {
3565
+ Key: "minLatitude",
3566
+ Name: "Min Latitude",
3567
+ Type: exports.EntityAttribute.EType.Double,
3568
+ IsIndexed: true,
3569
+ IsImportant: false
3570
+ },
3571
+ {
3572
+ Key: "maxLatitude",
3573
+ Name: "Max Latitude",
3574
+ Type: exports.EntityAttribute.EType.Double,
3575
+ IsIndexed: true,
3576
+ IsImportant: false
3577
+ },
3578
+ {
3579
+ Key: "minAltitude",
3580
+ Name: "Min Altitude",
3581
+ Type: exports.EntityAttribute.EType.Double,
3582
+ IsIndexed: true,
3583
+ IsImportant: false
3584
+ },
3585
+ {
3586
+ Key: "maxAltitude",
3587
+ Name: "Max Altitude",
3588
+ Type: exports.EntityAttribute.EType.Double,
3589
+ IsIndexed: true,
3590
+ IsImportant: false
3591
+ }
3592
+ ]
3573
3593
  });
3574
3594
  }
3575
- EntityHistoricData.Update = Update;
3576
- /**
3577
- * Deletes historic data records for an array of Entity IDs.
3578
- * This deletes all records within a provided key + range.
3579
- * @param params
3580
- * @returns
3581
- */
3582
- function Delete(params) {
3583
- return __awaiter(this, void 0, void 0, function* () {
3584
- let { entityIds, attrKey, dateTimeFrom, dateTimeTo, api, req } = params;
3585
- if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3586
- return;
3587
- }
3588
- if (!api) {
3589
- api = exports.ENVIRONMENT.Api().GetBruceApi();
3590
- }
3591
- if (!attrKey || !dateTimeFrom || !dateTimeTo) {
3592
- throw new Error("Invalid parameters provided.");
3593
- }
3594
- if (typeof attrKey != "string") {
3595
- attrKey = exports.PathUtils.Wrap(attrKey);
3596
- }
3597
- const urlParams = new URLSearchParams();
3598
- for (const entityId of entityIds) {
3599
- urlParams.append("entityId", entityId);
3600
- }
3601
- urlParams.append("attrKey", attrKey);
3602
- urlParams.append("dateTimeFrom", dateTimeFrom);
3603
- urlParams.append("dateTimeTo", dateTimeTo);
3604
- yield api.DELETE(`v1/entity/historicData?${urlParams.toString()}`, exports.Api.PrepReqParams(req));
3605
- // Kill cache for all Entity cached Entity records related to the attrKey.
3606
- api.Cache.RemoveByContains(exports.Entity.GetHistoricContainsKey(attrKey));
3607
- // Kill any stats cache that includes any of the Entity IDs.
3608
- ClearCacheByEntityIds(api, entityIds);
3595
+ if (!bruce.Structure.find(x => x.Key == "Transform")) {
3596
+ bruce.Structure.push({
3597
+ Key: "Transform",
3598
+ Name: "Transform",
3599
+ Description: "Transform data.",
3600
+ IsIndexed: true,
3601
+ IsImportant: false,
3602
+ Type: exports.EntityAttribute.EType.Structure,
3603
+ Structure: [
3604
+ {
3605
+ Key: "heading",
3606
+ Name: "Heading",
3607
+ IsIndexed: true,
3608
+ IsImportant: false,
3609
+ Type: exports.EntityAttribute.EType.Double
3610
+ },
3611
+ {
3612
+ Key: "pitch",
3613
+ Name: "Pitch",
3614
+ IsIndexed: true,
3615
+ IsImportant: false,
3616
+ Type: exports.EntityAttribute.EType.Double
3617
+ },
3618
+ {
3619
+ Key: "roll",
3620
+ Name: "Roll",
3621
+ IsIndexed: true,
3622
+ IsImportant: false,
3623
+ Type: exports.EntityAttribute.EType.Double
3624
+ },
3625
+ {
3626
+ Key: "scale",
3627
+ Name: "Scale",
3628
+ IsIndexed: true,
3629
+ IsImportant: false,
3630
+ Type: exports.EntityAttribute.EType.Double
3631
+ }
3632
+ ]
3609
3633
  });
3610
3634
  }
3611
- EntityHistoricData.Delete = Delete;
3612
- function GetListCacheKey(entityIds, attrKey, dateTimeFrom, dateTimeTo) {
3613
- return exports.Api.ECacheKey.EntityHistoricDataRec + exports.Api.ECacheKey.Id + entityIds.join(",") + exports.Api.ECacheKey.Id + attrKey + exports.Api.ECacheKey.Id + dateTimeFrom + exports.Api.ECacheKey.Id + dateTimeTo;
3614
- }
3615
- EntityHistoricData.GetListCacheKey = GetListCacheKey;
3616
- function GetStatsCacheKey(entityIds, typeId) {
3617
- if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3618
- entityIds = [];
3619
- }
3620
- if (!typeId) {
3621
- typeId = "";
3622
- }
3623
- return exports.Api.ECacheKey.EntityHistoricDataStats + exports.Api.ECacheKey.Id + typeId + exports.Api.ECacheKey.Id + entityIds.join(",");
3624
- }
3625
- EntityHistoricData.GetStatsCacheKey = GetStatsCacheKey;
3626
- function ClearCacheByEntityIds(api, entityIds) {
3627
- if (!api || !(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3628
- return;
3629
- }
3630
- const REC_KEY_PREFIX = exports.Api.ECacheKey.EntityHistoricDataRec + exports.Api.ECacheKey.Id;
3631
- const STATS_KEY_PREFIX = exports.Api.ECacheKey.EntityHistoricDataStats + exports.Api.ECacheKey.Id;
3632
- api.Cache.RemoveByCallback((key) => {
3633
- let keyStr = String(key);
3634
- if (!keyStr.startsWith(STATS_KEY_PREFIX) && !keyStr.startsWith(REC_KEY_PREFIX)) {
3635
- return false;
3636
- }
3637
- // Shorten to speed up the next step.
3638
- keyStr = keyStr.replace(STATS_KEY_PREFIX, "").replace(REC_KEY_PREFIX, "");
3639
- // Look for any matching Entity IDs.
3640
- for (let i = 0; i < entityIds.length; i++) {
3641
- const entityId = entityIds[i];
3642
- if (keyStr.includes(entityId)) {
3643
- return true;
3644
- }
3645
- }
3646
- return false;
3635
+ if (!bruce.Structure.find(x => x.Key == "VectorGeometry")) {
3636
+ bruce.Structure.push({
3637
+ Key: "VectorGeometry",
3638
+ Name: "Geometry",
3639
+ Description: "Geometry data.",
3640
+ Type: exports.EntityAttribute.EType.Geometry,
3641
+ IsIndexed: true,
3642
+ IsImportant: false
3647
3643
  });
3648
3644
  }
3649
- EntityHistoricData.ClearCacheByEntityIds = ClearCacheByEntityIds;
3650
- })(exports.EntityHistoricData || (exports.EntityHistoricData = {}));
3645
+ // Filter out migrated/outdated ones.
3646
+ // Removed from root and the internal structure.
3647
+ const OUTDATED_INTERNAL = ["position", "geometry", "location", "boundaries", "transform"];
3648
+ bruce.Structure = bruce.Structure.filter(a => !OUTDATED_INTERNAL.includes(a.Key));
3649
+ type.DataSchema.Structure = type.DataSchema.Structure.filter(a => !OUTDATED_INTERNAL.includes(a.Key));
3650
+ }
3651
3651
 
3652
3652
  (function (Entity) {
3653
3653
  let EOutlineKind;
@@ -3731,38 +3731,48 @@
3731
3731
  }
3732
3732
  expand += expandStr;
3733
3733
  }
3734
- if (expand) {
3734
+ if (expand === null || expand === void 0 ? void 0 : expand.length) {
3735
3735
  urlParams.append("Expand", expand);
3736
3736
  }
3737
3737
  if (expandLODs) {
3738
3738
  urlParams.append("LODType", "*");
3739
3739
  }
3740
3740
  if (entityTypeId) {
3741
- urlParams.append("BruceEntityType", entityTypeId);
3741
+ urlParams.append("Type", entityTypeId);
3742
3742
  }
3743
3743
  if (historicKey) {
3744
- urlParams.set("historicKey", historicKey);
3744
+ urlParams.set("HistoricKey", historicKey);
3745
3745
  }
3746
3746
  if (historicFrom) {
3747
- urlParams.set("historicFrom", historicFrom);
3747
+ urlParams.set("HistoricFrom", historicFrom);
3748
3748
  }
3749
3749
  if (historicTo) {
3750
- urlParams.set("historicTo", historicTo);
3750
+ urlParams.set("HistoricTo", historicTo);
3751
3751
  }
3752
3752
  if (historicPoint) {
3753
- urlParams.set("historicPoint", historicPoint);
3753
+ urlParams.set("HistoricPoint", historicPoint);
3754
3754
  }
3755
3755
  if (schemaId) {
3756
- urlParams.set("schema", schemaId);
3756
+ urlParams.set("Schema", schemaId);
3757
3757
  }
3758
3758
  if (scenario && String(scenario) != "0") {
3759
3759
  urlParams.set("Scenario", String(scenario));
3760
3760
  }
3761
- urlParams.set("hasMigrated", String(Boolean(migrated)));
3762
- const data = yield api.GET(`entity/${entityId}?${urlParams.toString()}`, exports.Api.PrepReqParams(reqParams));
3763
- res({
3764
- entity: data
3765
- });
3761
+ // v3 endpoint.
3762
+ if (migrated) {
3763
+ const data = yield api.GET(`v3/entity/${entityId}?${urlParams.toString()}`, exports.Api.PrepReqParams(reqParams));
3764
+ res({
3765
+ entity: data
3766
+ });
3767
+ }
3768
+ // v1 endpoint.
3769
+ else {
3770
+ urlParams.set("hasMigrated", "false");
3771
+ const data = yield api.GET(`entity/${entityId}?${urlParams.toString()}`, exports.Api.PrepReqParams(reqParams));
3772
+ res({
3773
+ entity: data
3774
+ });
3775
+ }
3766
3776
  }
3767
3777
  catch (e) {
3768
3778
  rej(e);
@@ -3877,6 +3887,14 @@
3877
3887
  reqData["Expand"] = "comment";
3878
3888
  }
3879
3889
  }
3890
+ if (expandSources) {
3891
+ if (reqData["Expand"]) {
3892
+ reqData["Expand"] += ",source";
3893
+ }
3894
+ else {
3895
+ reqData["Expand"] = "source";
3896
+ }
3897
+ }
3880
3898
  if (expandStr) {
3881
3899
  if (reqData["Expand"]) {
3882
3900
  reqData["Expand"] += `,${expandStr}`;
@@ -3888,33 +3906,38 @@
3888
3906
  if (expandLODs) {
3889
3907
  reqData["LODType"] = "*";
3890
3908
  }
3891
- if (expandSources) {
3892
- reqData["ExpandSources"] = true;
3893
- }
3894
3909
  if (historicKey) {
3895
- reqData["historicKey"] = historicKey;
3910
+ reqData["HistoricKey"] = historicKey;
3896
3911
  }
3897
3912
  if (historicFrom) {
3898
- reqData["historicFrom"] = historicFrom;
3913
+ reqData["HistoricFrom"] = historicFrom;
3899
3914
  }
3900
3915
  if (historicTo) {
3901
- reqData["historicTo"] = historicTo;
3916
+ reqData["HistoricTo"] = historicTo;
3902
3917
  }
3903
3918
  if (historicPoint) {
3904
- reqData["historicPoint"] = historicPoint;
3919
+ reqData["HistoricPoint"] = historicPoint;
3905
3920
  }
3906
3921
  if (scenario) {
3907
3922
  reqData["Scenario"] = scenario;
3908
3923
  }
3909
3924
  const urlParams = new URLSearchParams();
3910
3925
  if (schemaId) {
3911
- urlParams.set("schema", schemaId);
3926
+ urlParams.set("Schema", schemaId);
3912
3927
  }
3913
3928
  if (maxSearchTimeSec) {
3914
3929
  urlParams.set("MaxSearchTimeSec", String(Math.ceil(maxSearchTimeSec)));
3915
3930
  }
3916
- urlParams.set("hasMigrated", String(Boolean(migrated)));
3917
- const url = `entities?${urlParams.toString()}`;
3931
+ let url = null;
3932
+ // v3 endpoint.
3933
+ if (migrated) {
3934
+ url = `v3/getEntities?${urlParams.toString()}`;
3935
+ }
3936
+ // v1 endpoint.
3937
+ else {
3938
+ urlParams.set("hasMigrated", "false");
3939
+ url = `entities?${urlParams.toString()}`;
3940
+ }
3918
3941
  const reqs = [];
3919
3942
  if (reqIds.length > 0) {
3920
3943
  const req = api.POST(url, reqData, exports.Api.PrepReqParams(reqParams));
@@ -3975,7 +3998,7 @@
3975
3998
  if (!api) {
3976
3999
  api = exports.ENVIRONMENT.Api().GetBruceApi();
3977
4000
  }
3978
- yield api.DELETE(`entity/${entityId}`, exports.Api.PrepReqParams(reqParams));
4001
+ yield api.DELETE(`v3/entity/${entityId}`, exports.Api.PrepReqParams(reqParams));
3979
4002
  api.Cache.RemoveByContains(GetContainsKey(entityId));
3980
4003
  exports.EntityHistoricData.ClearCacheByEntityIds(api, [entityId]);
3981
4004
  });
@@ -3994,7 +4017,7 @@
3994
4017
  if (!api) {
3995
4018
  api = exports.ENVIRONMENT.Api().GetBruceApi();
3996
4019
  }
3997
- yield api.POST("deleteEntities", {
4020
+ yield api.POST("v3/deleteEntities", {
3998
4021
  Items: entityIds
3999
4022
  }, exports.Api.PrepReqParams(reqParams));
4000
4023
  for (let i = 0; i < entityIds.length; i++) {
@@ -4011,18 +4034,20 @@
4011
4034
  * @returns
4012
4035
  */
4013
4036
  function Update(params) {
4014
- var _a, _b, _c, _d, _e;
4037
+ var _a, _b, _c, _d, _e, _f, _g;
4015
4038
  return __awaiter(this, void 0, void 0, function* () {
4016
4039
  let { api, entity: data, entities, override, req: reqParams, migrated } = params;
4017
4040
  if (migrated == null || migrated == undefined) {
4018
4041
  // Changed to default = true. 18th April 2025.
4019
4042
  migrated = true;
4020
4043
  }
4021
- // Bulk save.
4044
+ // Bulk save. Always using a v3 endpoint as v1 did not have a bulk save.
4022
4045
  if (entities === null || entities === void 0 ? void 0 : entities.length) {
4023
4046
  // If the Entities don't have IDs, then they must have a Type ID.
4024
4047
  for (let i = 0; i < entities.length; i++) {
4025
4048
  const entity = entities[i];
4049
+ // If ID is missing then we can assume we're making a new record.
4050
+ // This means a type ID must be supplied.
4026
4051
  if (!((_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID) && !((_b = entity.Bruce) === null || _b === void 0 ? void 0 : _b["EntityType.ID"])) {
4027
4052
  throw ("Entity Type ID is required for new Entity records.");
4028
4053
  }
@@ -4052,18 +4077,43 @@
4052
4077
  if (!data && (entities === null || entities === void 0 ? void 0 : entities.length)) {
4053
4078
  data = entities[0];
4054
4079
  }
4055
- if (!((_d = data === null || data === void 0 ? void 0 : data.Bruce) === null || _d === void 0 ? void 0 : _d["EntityType.ID"])) {
4056
- throw ("Entity Type ID is required.");
4080
+ // If ID is missing then we can assume we're making a new record.
4081
+ // This means a type ID must be supplied.
4082
+ if (!((_d = data === null || data === void 0 ? void 0 : data.Bruce) === null || _d === void 0 ? void 0 : _d["EntityType.ID"]) && !((_e = data === null || data === void 0 ? void 0 : data.Bruce) === null || _e === void 0 ? void 0 : _e.ID)) {
4083
+ throw ("Entity Type ID is required for new records.");
4057
4084
  }
4058
4085
  if (!api) {
4059
4086
  api = exports.ENVIRONMENT.Api().GetBruceApi();
4060
4087
  }
4061
- if (!((_e = data === null || data === void 0 ? void 0 : data.Bruce) === null || _e === void 0 ? void 0 : _e.ID)) {
4062
- data.Bruce = Object.assign(Object.assign({}, data.Bruce), { ID: exports.ObjectUtils.UId() });
4088
+ /*
4089
+ Getting the API to always generate IDs when UI hasn't pre-generated them :)
4090
+ if (!data?.Bruce?.ID) {
4091
+ data.Bruce = {
4092
+ ...data.Bruce,
4093
+ ID: ObjectUtils.UId()
4094
+ };
4095
+ }
4096
+ */
4097
+ const entityId = (_f = data.Bruce) === null || _f === void 0 ? void 0 : _f.ID;
4098
+ const typeId = (_g = data.Bruce) === null || _g === void 0 ? void 0 : _g["EntityType.ID"];
4099
+ let reqUrl = null;
4100
+ // Create or update.
4101
+ // Though API also looks for ID in body...
4102
+ if (entityId) {
4103
+ reqUrl = migrated ? `v3/entity/${data.Bruce.ID}` : `entity/${data.Bruce.ID}`;
4063
4104
  }
4064
- let reqUrl = `entity/${data.Bruce.ID}/?dataoverride=${override}&BruceEntityType=${data.Bruce["EntityType.ID"]}`;
4065
- if (migrated) {
4066
- reqUrl += "&hasMigrated=true";
4105
+ else {
4106
+ reqUrl = migrated ? "v3/entity" : "entity";
4107
+ }
4108
+ // Override = Are we doing an update or replace?
4109
+ reqUrl += `?Override=${override}`;
4110
+ // Updating through a known type.
4111
+ if (typeId) {
4112
+ reqUrl += `&Type=${data.Bruce["EntityType.ID"]}`;
4113
+ }
4114
+ // Explicit in case API changes default logic for v1 endpoint.
4115
+ if (!migrated) {
4116
+ reqUrl += "&hasMigrated=false";
4067
4117
  }
4068
4118
  const res = yield api.POST(reqUrl, data, exports.Api.PrepReqParams(reqParams));
4069
4119
  api.Cache.RemoveByContains(GetContainsKey(data.Bruce.ID));
@@ -4395,18 +4445,17 @@
4395
4445
  OrderBy: filter.orderBy,
4396
4446
  Filter: requestFilter,
4397
4447
  LODType: filter.lodCategoryId,
4398
- BruceEntityType: (!filter.entityTypeId ? null : filter.entityTypeId),
4448
+ Type: (!filter.entityTypeId ? null : filter.entityTypeId),
4399
4449
  PageIndex: filter.pageIndex,
4400
4450
  PageSize: filter.pageSize,
4401
- historicKey: historicKey,
4402
- historicFrom: historicFrom,
4403
- historicTo: historicTo,
4404
- historicPoint: historicPoint,
4405
- ExpandSources: expandSources,
4451
+ HistoricKey: historicKey,
4452
+ HistoricFrom: historicFrom,
4453
+ HistoricTo: historicTo,
4454
+ HistoricPoint: historicPoint,
4406
4455
  Scenario: scenario
4407
4456
  };
4408
- if (expandLocation || expandRelations || expandImports || expandEntityType || expandComments || expandStr || expandAttachments) {
4409
- let expand = "";
4457
+ let expand = "";
4458
+ {
4410
4459
  if (expandLocation) {
4411
4460
  expand += "location";
4412
4461
  }
@@ -4426,7 +4475,7 @@
4426
4475
  if (expand) {
4427
4476
  expand += ",";
4428
4477
  }
4429
- expand += "EntityType";
4478
+ expand += "entityType";
4430
4479
  }
4431
4480
  if (expandComments) {
4432
4481
  if (expand) {
@@ -4440,15 +4489,21 @@
4440
4489
  }
4441
4490
  expand += "attachment";
4442
4491
  }
4492
+ if (expandSources) {
4493
+ if (expand) {
4494
+ expand += ",";
4495
+ }
4496
+ expand += "source";
4497
+ }
4443
4498
  if (expandStr) {
4444
4499
  if (expand) {
4445
4500
  expand += ",";
4446
4501
  }
4447
4502
  expand += expandStr;
4448
4503
  }
4449
- if (expand) {
4450
- body["Expand"] = expand;
4451
- }
4504
+ }
4505
+ if (expand) {
4506
+ body["Expand"] = expand;
4452
4507
  }
4453
4508
  let totalCount;
4454
4509
  let entities = [];
@@ -4473,8 +4528,8 @@
4473
4528
  if (body.LODType) {
4474
4529
  urlParams.set("LODType", body.LODType);
4475
4530
  }
4476
- if (body.BruceEntityType) {
4477
- urlParams.set("BruceEntityType", typeof body.BruceEntityType == "string" ? body.BruceEntityType : body.BruceEntityType.join(","));
4531
+ if (body.Type) {
4532
+ urlParams.set("Type", typeof body.Type == "string" ? body.Type : body.Type.join(","));
4478
4533
  }
4479
4534
  if (body.PageIndex) {
4480
4535
  urlParams.set("PageIndex", String(body.PageIndex));
@@ -4482,72 +4537,23 @@
4482
4537
  if (body.PageSize) {
4483
4538
  urlParams.set("PageSize", String(body.PageSize));
4484
4539
  }
4485
- let expand = "";
4486
- if (expandRelations) {
4487
- if (expand.length) {
4488
- expand += ",";
4489
- }
4490
- expand += "Relation";
4491
- }
4492
- if (expandLocation) {
4493
- if (expand.length) {
4494
- expand += ",";
4495
- }
4496
- expand += "Location";
4497
- }
4498
- if (expandImports) {
4499
- if (expand.length) {
4500
- expand += ",";
4501
- }
4502
- expand += "Import";
4503
- }
4504
- if (expandSources) {
4505
- if (expand.length) {
4506
- expand += ",";
4507
- }
4508
- expand += "Source";
4509
- }
4510
- if (expandEntityType) {
4511
- if (expand.length) {
4512
- expand += ",";
4513
- }
4514
- expand += "EntityType";
4515
- }
4516
- if (expandComments) {
4517
- if (expand.length) {
4518
- expand += ",";
4519
- }
4520
- expand += "Comment";
4521
- }
4522
- if (expandAttachments) {
4523
- if (expand.length) {
4524
- expand += ",";
4525
- }
4526
- expand += "Attachment";
4527
- }
4528
- if (expandStr) {
4529
- if (expand.length) {
4530
- expand += ",";
4531
- }
4532
- expand += expandStr;
4533
- }
4534
- if (expand.length) {
4540
+ if (expand === null || expand === void 0 ? void 0 : expand.length) {
4535
4541
  urlParams.append("Expand", expand);
4536
4542
  }
4537
4543
  if (historicKey) {
4538
- urlParams.set("historicKey", historicKey);
4544
+ urlParams.set("HistoricKey", historicKey);
4539
4545
  }
4540
4546
  if (historicFrom) {
4541
- urlParams.set("historicFrom", historicFrom);
4547
+ urlParams.set("HistoricFrom", historicFrom);
4542
4548
  }
4543
4549
  if (historicTo) {
4544
- urlParams.set("historicTo", historicTo);
4550
+ urlParams.set("HistoricTo", historicTo);
4545
4551
  }
4546
4552
  if (historicPoint) {
4547
- urlParams.set("historicPoint", historicPoint);
4553
+ urlParams.set("HistoricPoint", historicPoint);
4548
4554
  }
4549
4555
  if (schemaId) {
4550
- urlParams.set("schema", schemaId);
4556
+ urlParams.set("Schema", schemaId);
4551
4557
  }
4552
4558
  if (scenario && String(scenario) != "0") {
4553
4559
  urlParams.set("Scenario", String(scenario));
@@ -4555,8 +4561,22 @@
4555
4561
  if (maxSearchTimeSec) {
4556
4562
  urlParams.set("MaxSearchTimeSec", String(Math.ceil(maxSearchTimeSec)));
4557
4563
  }
4558
- urlParams.set("hasMigrated", String(Boolean(migrated)));
4559
- let url = analysis ? "entities/summary" : "entities";
4564
+ let url = null;
4565
+ // v3 endpoint.
4566
+ if (migrated) {
4567
+ url = analysis ? "v3/entities" : "v3/entities";
4568
+ if (analysis) {
4569
+ urlParams.delete("PageIndex");
4570
+ urlParams.delete("PageSize");
4571
+ urlParams.append("PageIndex", "-1");
4572
+ urlParams.append("PageSize", "-1");
4573
+ }
4574
+ }
4575
+ // v1 endpoint.
4576
+ else {
4577
+ urlParams.set("hasMigrated", "false");
4578
+ url = analysis ? "entities/summary" : "entities";
4579
+ }
4560
4580
  url += "?" + urlParams.toString();
4561
4581
  const urlStr = api.ConstructUrl({
4562
4582
  cdn: !analysis && viaCdn,
@@ -4576,56 +4596,7 @@
4576
4596
  }
4577
4597
  else {
4578
4598
  const urlParams = new URLSearchParams();
4579
- let expand = "";
4580
- if (expandRelations) {
4581
- if (expand.length) {
4582
- expand += ",";
4583
- }
4584
- expand += "Relation";
4585
- }
4586
- if (expandLocation) {
4587
- if (expand.length) {
4588
- expand += ",";
4589
- }
4590
- expand += "Location";
4591
- }
4592
- if (expandImports) {
4593
- if (expand.length) {
4594
- expand += ",";
4595
- }
4596
- expand += "Import";
4597
- }
4598
- if (expandSources) {
4599
- if (expand.length) {
4600
- expand += ",";
4601
- }
4602
- expand += "Source";
4603
- }
4604
- if (expandEntityType) {
4605
- if (expand.length) {
4606
- expand += ",";
4607
- }
4608
- expand += "EntityType";
4609
- }
4610
- if (expandComments) {
4611
- if (expand.length) {
4612
- expand += ",";
4613
- }
4614
- expand += "Comment";
4615
- }
4616
- if (expandAttachments) {
4617
- if (expand.length) {
4618
- expand += ",";
4619
- }
4620
- expand += "Attachment";
4621
- }
4622
- if (expandStr) {
4623
- if (expand.length) {
4624
- expand += ",";
4625
- }
4626
- expand += expandStr;
4627
- }
4628
- if (expand.length) {
4599
+ if (expand === null || expand === void 0 ? void 0 : expand.length) {
4629
4600
  urlParams.append("Expand", expand);
4630
4601
  }
4631
4602
  if (schemaId) {
@@ -4634,8 +4605,20 @@
4634
4605
  if (maxSearchTimeSec) {
4635
4606
  urlParams.set("MaxSearchTimeSec", String(Math.ceil(maxSearchTimeSec)));
4636
4607
  }
4637
- urlParams.set("hasMigrated", String(Boolean(migrated)));
4638
- let url = analysis ? "entities/summary" : "entities";
4608
+ let url = null;
4609
+ // v3 endpoint.
4610
+ if (migrated) {
4611
+ url = "v3/getEntities";
4612
+ if (analysis) {
4613
+ body.PageIndex = -1;
4614
+ body.PageSize = -1;
4615
+ }
4616
+ }
4617
+ // v1 endpoint.
4618
+ else {
4619
+ url = analysis ? "entities/summary" : "entities";
4620
+ urlParams.set("hasMigrated", "false");
4621
+ }
4639
4622
  // Adding url params here because this will avoid making them encoded.
4640
4623
  // Our API isn't decoding them properly so $expand is not being recognized.
4641
4624
  url += "?" + urlParams.toString();
@@ -16732,7 +16715,7 @@
16732
16715
  }
16733
16716
 
16734
16717
  // This is updated with the package.json version on build.
16735
- const VERSION = "7.0.7";
16718
+ const VERSION = "7.0.8";
16736
16719
 
16737
16720
  exports.VERSION = VERSION;
16738
16721
  exports.AbstractApi = AbstractApi;