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