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.
@@ -1849,7 +1849,18 @@ var ENVIRONMENT;
1849
1849
  _getters.SetEnv(params.env);
1850
1850
  }
1851
1851
  }
1852
- ENVIRONMENT.PARAMS = Object.assign(Object.assign({}, ENVIRONMENT.PARAMS), params);
1852
+ if (params.dereference) {
1853
+ ENVIRONMENT.PARAMS = Object.assign(Object.assign({}, ENVIRONMENT.PARAMS), params);
1854
+ }
1855
+ else {
1856
+ const keys = Object.keys(params);
1857
+ for (const key of keys) {
1858
+ const value = params[key];
1859
+ if (value !== undefined) {
1860
+ ENVIRONMENT.PARAMS[key] = value;
1861
+ }
1862
+ }
1863
+ }
1853
1864
  (_a = ENVIRONMENT.OnParamsChange) === null || _a === void 0 ? void 0 : _a.Trigger();
1854
1865
  }
1855
1866
  ENVIRONMENT.Reset = Reset;
@@ -2727,959 +2738,959 @@ var ObjectUtils;
2727
2738
  })(ObjectUtils || (ObjectUtils = {}));
2728
2739
 
2729
2740
  /**
2730
- * Describes an entity type schema attribute.
2741
+ * Utility to help with parsing and wrapping Nextspace paths.
2731
2742
  */
2732
- var EntityAttribute;
2733
- (function (EntityAttribute) {
2734
- let EType;
2735
- (function (EType) {
2736
- // Arbitrary text attribute.
2737
- EType["String"] = "String";
2738
- // Floating point number attribute.
2739
- EType["Double"] = "Double";
2740
- // Whole number attribute.
2741
- EType["Integer"] = "Integer";
2742
- // iso8601 date time string.
2743
- EType["Datetime"] = "Datetime";
2744
- // Group of attributes.
2745
- EType["Structure"] = "Structure";
2746
- // Nextspace vector geometry.
2747
- EType["Geometry"] = "Geometry";
2748
- // True/false attribute.
2749
- EType["Boolean"] = "Boolean";
2750
- // String User ID.
2751
- EType["User"] = "User";
2752
- // String Group ID.
2753
- EType["UserGroup"] = "UserGroup";
2754
- // String Entity ID.
2755
- EType["Entity"] = "Entity";
2756
- // Url attribute.
2757
- EType["Url"] = "Url";
2758
- // Serial number that increments for each new entity/missing-attr-value.
2759
- EType["Serial"] = "Serial";
2760
- })(EType = EntityAttribute.EType || (EntityAttribute.EType = {}));
2761
- /**
2762
- * Describes url open behavior.
2763
- */
2764
- let EOpenBehavior;
2765
- (function (EOpenBehavior) {
2766
- EOpenBehavior["POPUP"] = "POPUP";
2767
- EOpenBehavior["NEW_TAB"] = "NEW_TAB";
2768
- })(EOpenBehavior = EntityAttribute.EOpenBehavior || (EntityAttribute.EOpenBehavior = {}));
2743
+ var PathUtils;
2744
+ (function (PathUtils) {
2769
2745
  /**
2770
- * Returns an attribute from a provided hierarchy of attributes.
2771
- * Eg: Use the path: ["Bruce", "ID"] to find the "ID" attribute.
2772
- * @param items
2773
- * @param path
2746
+ * Parses a Bruce string path into an array of strings.
2747
+ * Example of path: "\"location\"/\"latitude\"" or "location/latitude".
2748
+ * @param str
2774
2749
  * @returns
2775
2750
  */
2776
- function GetAttribute(items, path) {
2777
- if (!items || !path || !path.length) {
2778
- return null;
2779
- }
2780
- const key = path[0];
2781
- const item = items.find((i) => i.Key === key);
2782
- if (!item) {
2783
- return null;
2751
+ function Parse(str) {
2752
+ if (!(str === null || str === void 0 ? void 0 : str.length)) {
2753
+ return [];
2784
2754
  }
2785
- if (path.length === 1) {
2786
- return item;
2755
+ const broken = str.split("/");
2756
+ // Remove quotes from the first and last chars.
2757
+ for (let i = 0; i < broken.length; i++) {
2758
+ let piece = broken[i];
2759
+ if (piece.startsWith("\"")) {
2760
+ piece = piece.substring(1);
2761
+ }
2762
+ if (piece.endsWith("\"")) {
2763
+ piece = piece.substring(0, piece.length - 1);
2764
+ }
2765
+ broken[i] = piece;
2787
2766
  }
2788
- return GetAttribute(item.Structure, path.slice(1));
2767
+ return broken;
2789
2768
  }
2790
- EntityAttribute.GetAttribute = GetAttribute;
2769
+ PathUtils.Parse = Parse;
2791
2770
  /**
2792
- * Removes an attribute from a provided hierarchy of attributes.
2793
- * Eg: Use the path: ["Bruce", "ID"] to remove the "ID" attribute.
2794
- * This will mutate the items array.
2795
- * @param items
2771
+ * Wraps an array of strings into a Nextspace string path.
2796
2772
  * @param path
2773
+ * @returns
2797
2774
  */
2798
- function RemoveAttribute(items, path) {
2799
- if (!items || !(path === null || path === void 0 ? void 0 : path.length)) {
2800
- return;
2775
+ function Wrap(path) {
2776
+ if (!(path === null || path === void 0 ? void 0 : path.length)) {
2777
+ return "";
2801
2778
  }
2802
- const key = path[0];
2803
- if (path.length === 1) {
2804
- // If we're at the last key in the path, remove the item from the items array.
2805
- const index = items.findIndex((i) => i.Key === key);
2806
- if (index !== -1) {
2807
- items.splice(index, 1);
2779
+ let tmp = "\"";
2780
+ for (let i = 0; i < path.length; i++) {
2781
+ let section = path[i];
2782
+ tmp += section;
2783
+ if (i < path.length - 1) {
2784
+ tmp += "\"/\"";
2808
2785
  }
2809
- return;
2810
- }
2811
- // If we're not at the end of the path, dig further.
2812
- const item = items.find((i) => i.Key === key);
2813
- if (item && item.Structure) {
2814
- RemoveAttribute(item.Structure, path.slice(1));
2815
2786
  }
2787
+ tmp += "\"";
2788
+ return tmp;
2816
2789
  }
2817
- EntityAttribute.RemoveAttribute = RemoveAttribute;
2790
+ PathUtils.Wrap = Wrap;
2818
2791
  /**
2819
- * Adds an attribute to a provided hierarchy of attributes.
2820
- * Eg: Use the path: ["Bruce", "ID"] to add the "ID" attribute.
2821
- * This will mutate the items array.
2822
- * This requires the path to be valid and for a parent attribute to exist.
2823
- * @param items
2824
- * @param path
2825
- * @param attribute
2792
+ * Parses a Nextspace legacy string path into an array of strings.
2793
+ * @param str
2794
+ * @returns
2826
2795
  */
2827
- function AddAttribute(items, path, attribute) {
2828
- if (!items || !(path === null || path === void 0 ? void 0 : path.length)) {
2829
- return;
2796
+ function ParseLegacy(str) {
2797
+ if (!(str === null || str === void 0 ? void 0 : str.length)) {
2798
+ return [];
2830
2799
  }
2831
- const key = path[0];
2832
- if (path.length === 1) {
2833
- // If we're at the last key in the path, add the attribute to the items array.
2834
- const index = items.findIndex((i) => i.Key === key);
2835
- if (index !== -1) {
2836
- // Overwrite existing attribute if it already exists.
2837
- items[index] = attribute;
2800
+ const broken = str.split(".");
2801
+ for (let i = 0; i < broken.length; i++) {
2802
+ let piece = broken[i];
2803
+ if (piece.startsWith("\"")) {
2804
+ piece = piece.substring(1);
2838
2805
  }
2839
- else {
2840
- // Add new attribute if it doesn't exist.
2841
- items.push(attribute);
2806
+ if (piece.endsWith("\"")) {
2807
+ piece = piece.substring(0, piece.length - 1);
2842
2808
  }
2843
- return;
2844
- }
2845
- // If we're not at the end of the path, dig further.
2846
- let item = items.find((i) => i.Key === key);
2847
- if (!item) {
2848
- item = { Key: key, Structure: [] };
2849
- items.push(item);
2850
- }
2851
- if (!item.Structure) {
2852
- item.Structure = [];
2809
+ broken[i] = piece;
2853
2810
  }
2854
- AddAttribute(item.Structure, path.slice(1), attribute);
2811
+ return broken;
2855
2812
  }
2856
- EntityAttribute.AddAttribute = AddAttribute;
2857
- })(EntityAttribute || (EntityAttribute = {}));
2813
+ PathUtils.ParseLegacy = ParseLegacy;
2814
+ })(PathUtils || (PathUtils = {}));
2858
2815
 
2859
- /**
2860
- * Describes the "Entity Type" concept within Nextspace.
2861
- * An entity type is an "expectation" of what data "should" look like in a particular entity record.
2862
- * The schema is stencils onto entity data to filter out what we should display or search against.
2863
- */
2864
- var EntityType;
2865
- (function (EntityType) {
2816
+ var EntityHistoricData;
2817
+ (function (EntityHistoricData) {
2866
2818
  /**
2867
- * Gets an entity type record.
2819
+ * Returns historic data for an array of Entity IDs.
2820
+ * A maximum number of records will be returned per Entity ID, this information is returned in the response.
2868
2821
  * @param params
2869
2822
  * @returns
2870
2823
  */
2871
- function Get(params) {
2824
+ function GetList(params) {
2872
2825
  return __awaiter(this, void 0, void 0, function* () {
2873
- let { api, entityTypeId: typeId, req: reqParams, expandLODs } = params;
2874
- if (!typeId) {
2875
- throw ("Type ID is required.");
2826
+ let { entityIds, attrKey, dateTimeFrom, dateTimeTo, api, req } = params;
2827
+ // Save time and just return a none response if no entity IDs are provided.
2828
+ if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
2829
+ return {
2830
+ limitPerEntity: 0,
2831
+ recordsByIds: {}
2832
+ };
2876
2833
  }
2877
2834
  if (!api) {
2878
2835
  api = ENVIRONMENT.Api().GetBruceApi();
2879
2836
  }
2880
- const key = GetCacheKey(typeId, expandLODs);
2881
- const cache = api.GetCacheItem(key, reqParams);
2882
- if (cache === null || cache === void 0 ? void 0 : cache.found) {
2883
- return cache.data;
2837
+ let attrKeyStr = null;
2838
+ if (attrKey) {
2839
+ if (typeof attrKey != "string") {
2840
+ attrKeyStr = PathUtils.Wrap(attrKey);
2841
+ }
2842
+ else {
2843
+ attrKeyStr = attrKey;
2844
+ }
2884
2845
  }
2885
- const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
2886
- try {
2887
- const urlParams = new URLSearchParams();
2888
- if (expandLODs) {
2889
- urlParams.append("Expand", "LOD");
2846
+ // If we have more than 100 Entity IDs we'll have to split the request to avoid a URL that is too long.
2847
+ const MAX_IDS = 100;
2848
+ // We will recursively call this function to get all the data.
2849
+ // Then merge at the end and return.
2850
+ if (entityIds.length > MAX_IDS) {
2851
+ const reqs = [];
2852
+ // Making the ID batches.
2853
+ // If this is too long we can end up in a loop.
2854
+ const splitEntityIds = [];
2855
+ for (let i = 0; i < entityIds.length; i += MAX_IDS) {
2856
+ const batchIds = entityIds.slice(i, i + MAX_IDS);
2857
+ // Detecting this early to avoid infinite loops.
2858
+ if (batchIds.length > MAX_IDS) {
2859
+ throw new Error("Nextspace Developer Error: EntityHistoricData.GetList() has too many Entity IDs. Please contact support.");
2890
2860
  }
2891
- const url = `entitytype/${typeId}?${urlParams.toString()}`;
2892
- const data = yield api.GET(url, Api.PrepReqParams(reqParams));
2893
- appendInternalAttrSchema(data);
2894
- res({
2895
- entityType: data
2896
- });
2861
+ splitEntityIds.push(batchIds);
2897
2862
  }
2898
- catch (e) {
2899
- rej(e);
2863
+ for (const splitEntityId of splitEntityIds) {
2864
+ reqs.push(GetList({
2865
+ entityIds: splitEntityId,
2866
+ attrKey: attrKeyStr,
2867
+ dateTimeFrom: dateTimeFrom,
2868
+ dateTimeTo: dateTimeTo,
2869
+ api: api,
2870
+ req: req
2871
+ }));
2900
2872
  }
2901
- }));
2902
- api.SetCacheItem({
2903
- key,
2904
- value: prom,
2905
- req: reqParams
2906
- });
2907
- return prom;
2908
- });
2909
- }
2910
- EntityType.Get = Get;
2911
- /**
2912
- * Deletes an entity type record and all corresponding entities.
2913
- * @param params
2914
- */
2915
- function Delete(params) {
2916
- return __awaiter(this, void 0, void 0, function* () {
2917
- let { api, entityTypeId: typeId, req: reqParams } = params;
2918
- if (!typeId) {
2919
- throw ("Type ID is required.");
2873
+ const res = yield Promise.all(reqs);
2874
+ const recordsByIds = {};
2875
+ let limitPerEntity = 0;
2876
+ for (const r of res) {
2877
+ limitPerEntity = r.limitPerEntity;
2878
+ for (const entityId in r.recordsByIds) {
2879
+ recordsByIds[entityId] = r.recordsByIds[entityId];
2880
+ }
2881
+ }
2882
+ // Returning merged data.
2883
+ return {
2884
+ recordsByIds: recordsByIds,
2885
+ limitPerEntity: limitPerEntity
2886
+ };
2920
2887
  }
2921
- if (!api) {
2922
- api = ENVIRONMENT.Api().GetBruceApi();
2888
+ const cacheKey = GetListCacheKey(entityIds, attrKeyStr, dateTimeFrom, dateTimeTo);
2889
+ const cached = api.GetCacheItem(cacheKey, req);
2890
+ if (cached === null || cached === void 0 ? void 0 : cached.found) {
2891
+ return cached.data;
2923
2892
  }
2924
- yield api.DELETE(`entitytype/${typeId}`, Api.PrepReqParams(reqParams));
2925
- api.Cache.RemoveByStartsWith(GetCacheKey(typeId));
2926
- api.Cache.RemoveByStartsWith(GetListCacheKey());
2893
+ const urlParams = new URLSearchParams();
2894
+ for (const entityId of entityIds) {
2895
+ urlParams.append("entityId", entityId);
2896
+ }
2897
+ if (attrKeyStr) {
2898
+ urlParams.append("attrKey", attrKeyStr);
2899
+ }
2900
+ urlParams.append("dateTimeFrom", dateTimeFrom);
2901
+ urlParams.append("dateTimeTo", dateTimeTo);
2902
+ const prom = api.GET(`v1/entity/historicData?${urlParams.toString()}`, Api.PrepReqParams(req));
2903
+ api.SetCacheItem({
2904
+ key: cacheKey,
2905
+ value: prom,
2906
+ req: req,
2907
+ // Short cache. 30 seconds.
2908
+ duration: 30000
2909
+ });
2910
+ return prom;
2927
2911
  });
2928
2912
  }
2929
- EntityType.Delete = Delete;
2913
+ EntityHistoricData.GetList = GetList;
2930
2914
  /**
2931
- * Gets a list of entity types.
2915
+ * Returns historic data statistics for an array of Entity IDs.
2932
2916
  * @param params
2933
2917
  * @returns
2934
2918
  */
2935
- function GetList(params) {
2919
+ function GetStats(params) {
2936
2920
  return __awaiter(this, void 0, void 0, function* () {
2937
- let { entityTypeIds, api, req: reqParams, parentTypeId, expandSettings, search, expandLODs } = params;
2921
+ let { entityIds, entityTypeId, api, req } = params;
2922
+ // Save time and just return a none response if no entity IDs or type ID are provided.
2923
+ if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length) && !entityTypeId) {
2924
+ return {
2925
+ stats: []
2926
+ };
2927
+ }
2938
2928
  if (!api) {
2939
2929
  api = ENVIRONMENT.Api().GetBruceApi();
2940
2930
  }
2941
- const cache = api.GetCacheItem(GetListCacheKey({
2942
- typeIds: entityTypeIds,
2943
- parentTypeId,
2944
- expandLODs,
2945
- expandSettings,
2946
- search
2947
- }), reqParams);
2948
- if (cache === null || cache === void 0 ? void 0 : cache.found) {
2949
- return cache.data;
2950
- }
2951
- const req = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
2952
- try {
2953
- // If we have an array of typeIds then we'll request in batches to avoid overflowing the URL.
2954
- const BATCH_SIZE = 20;
2955
- const reqs = [];
2956
- if (entityTypeIds) {
2957
- for (let i = 0; i < entityTypeIds.length; i += BATCH_SIZE) {
2958
- const batch = entityTypeIds.slice(i, i + BATCH_SIZE);
2959
- const urlParams = new URLSearchParams();
2960
- for (const id of batch) {
2961
- urlParams.append("ID", id);
2962
- }
2963
- if (parentTypeId) {
2964
- urlParams.append("ParentTypeID", parentTypeId);
2965
- }
2966
- if (expandSettings && expandLODs) {
2967
- urlParams.append("Expand", "true");
2968
- }
2969
- else if (expandSettings) {
2970
- urlParams.append("Expand", "Schema");
2971
- }
2972
- else if (expandLODs) {
2973
- urlParams.append("Expand", "LOD");
2974
- }
2975
- if (search) {
2976
- urlParams.append("Search", search);
2977
- }
2978
- reqs.push(api.GET("entitytypes?" + urlParams.toString(), Api.PrepReqParams(reqParams)));
2979
- }
2980
- }
2981
- else {
2982
- const urlParams = new URLSearchParams();
2983
- if (parentTypeId) {
2984
- urlParams.append("ParentTypeID", parentTypeId);
2985
- }
2986
- if (expandSettings && expandLODs) {
2987
- urlParams.append("Expand", "true");
2988
- }
2989
- else if (expandSettings) {
2990
- urlParams.append("Expand", "Schema");
2991
- }
2992
- else if (expandLODs) {
2993
- urlParams.append("Expand", "LOD");
2994
- }
2995
- if (search) {
2996
- urlParams.append("Search", search);
2997
- }
2998
- reqs.push(api.GET("entitytypes?" + urlParams.toString(), Api.PrepReqParams(reqParams)));
2999
- }
3000
- const data = yield Promise.all(reqs);
3001
- // Populate array, while checking for already added types.
3002
- const types = [];
3003
- for (const item of data) {
3004
- for (const type of item.Items) {
3005
- appendInternalAttrSchema(type);
3006
- if (!types.find(x => x.ID == type.ID)) {
3007
- types.push(type);
3008
- }
3009
- }
3010
- }
3011
- res({
3012
- entityTypes: types
3013
- });
3014
- }
3015
- catch (e) {
3016
- rej(e);
3017
- }
3018
- }));
3019
- if (!parentTypeId) {
3020
- api.SetCacheItem({
3021
- key: GetListCacheKey({
3022
- typeIds: entityTypeIds,
3023
- parentTypeId,
3024
- expandSettings,
3025
- expandLODs,
3026
- search
3027
- }),
3028
- value: req,
3029
- req: reqParams,
3030
- duration: 60 * 5 // 5 minutes.
3031
- });
2931
+ req = Api.PrepReqParams(req);
2932
+ const cacheKey = GetStatsCacheKey(entityIds, entityTypeId);
2933
+ const cached = api.GetCacheItem(cacheKey, req);
2934
+ if (cached === null || cached === void 0 ? void 0 : cached.found) {
2935
+ return cached.data;
3032
2936
  }
3033
- return req;
2937
+ const prom = yield api.POST("v1/entity/historicData/stats", {
2938
+ entityIds: entityIds,
2939
+ entityTypeId: entityTypeId
2940
+ }, req);
2941
+ api.SetCacheItem({
2942
+ key: cacheKey,
2943
+ value: prom,
2944
+ req: req,
2945
+ // Short cache. 60 seconds.
2946
+ duration: 60000
2947
+ });
2948
+ return prom;
3034
2949
  });
3035
2950
  }
3036
- EntityType.GetList = GetList;
2951
+ EntityHistoricData.GetStats = GetStats;
3037
2952
  /**
3038
- * Updates or creates an entity type record.
2953
+ * Creates or updates historic data records.
2954
+ * Please note that the expected input/output does not include internal fields found inside the "Bruce" attribute.
3039
2955
  * @param params
3040
2956
  * @returns
3041
2957
  */
3042
2958
  function Update(params) {
2959
+ var _a;
3043
2960
  return __awaiter(this, void 0, void 0, function* () {
3044
- let { api, entityType: data, req: reqParams } = params;
2961
+ let { records, api, req } = params;
2962
+ // Save time and just return a none response if no records are provided.
2963
+ if (!(records === null || records === void 0 ? void 0 : records.length)) {
2964
+ return {
2965
+ records: []
2966
+ };
2967
+ }
3045
2968
  if (!api) {
3046
2969
  api = ENVIRONMENT.Api().GetBruceApi();
3047
2970
  }
3048
- if (!data) {
3049
- data = {};
3050
- }
3051
- if (!data.ID) {
3052
- data.ID = ObjectUtils.UId();
2971
+ const res = yield api.POST("v1/entity/historicData", {
2972
+ records: records
2973
+ }, Api.PrepReqParams(req));
2974
+ // Kill cache for every unique attrKey.
2975
+ let attrKeys = records.map(r => r.attrKey);
2976
+ attrKeys = attrKeys.filter((v, i) => attrKeys.indexOf(v) === i);
2977
+ for (const attrKey of attrKeys) {
2978
+ api.Cache.RemoveByContains(Entity.GetHistoricContainsKey(attrKey));
3053
2979
  }
3054
- if (!data.Name) {
3055
- data.Name = data.ID;
2980
+ // Kill any stats cache that includes any of the Entity IDs.
2981
+ if ((_a = res.records) === null || _a === void 0 ? void 0 : _a.length) {
2982
+ const entityIds = res.records.map(r => r.entityId).filter((v, i) => v && res.records.indexOf(v) === i);
2983
+ ClearCacheByEntityIds(api, entityIds);
3056
2984
  }
3057
- // Will not append if we're not updating schema (not specified).
3058
- appendInternalAttrSchema(data);
3059
- const res = yield api.POST(`entitytype/${data.ID}`, data, Api.PrepReqParams(reqParams));
3060
- api.Cache.RemoveByStartsWith(GetCacheKey(data.ID));
3061
- api.Cache.RemoveByStartsWith(GetListCacheKey());
3062
- // Useful to append afterwards as newly created Entity Types may have it missing.
3063
- // This makes our UI apps not have to check for default attribute existence.
3064
- appendInternalAttrSchema(res);
3065
- return {
3066
- entityType: res
3067
- };
2985
+ return res;
3068
2986
  });
3069
2987
  }
3070
- EntityType.Update = Update;
2988
+ EntityHistoricData.Update = Update;
3071
2989
  /**
3072
- * Starts a re-index background action on a specified Entity Type.
3073
- * This will ensure searchable data follows the current schema version.
3074
- * This will also perform certain data cleanup so that the data is consistent.
2990
+ * Deletes historic data records for an array of Entity IDs.
2991
+ * This deletes all records within a provided key + range.
3075
2992
  * @param params
3076
2993
  * @returns
3077
2994
  */
3078
- function ReIndex(params) {
2995
+ function Delete(params) {
3079
2996
  return __awaiter(this, void 0, void 0, function* () {
3080
- let { api, entityTypeId: typeId, req, dataTransformId, reSaveAll } = params;
2997
+ let { entityIds, attrKey, dateTimeFrom, dateTimeTo, api, req } = params;
2998
+ if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
2999
+ return;
3000
+ }
3081
3001
  if (!api) {
3082
3002
  api = ENVIRONMENT.Api().GetBruceApi();
3083
3003
  }
3084
- const urlParams = new URLSearchParams();
3085
- if (dataTransformId) {
3086
- urlParams.append("dataTransformID", String(dataTransformId));
3004
+ if (!attrKey || !dateTimeFrom || !dateTimeTo) {
3005
+ throw new Error("Invalid parameters provided.");
3087
3006
  }
3088
- if (reSaveAll) {
3089
- urlParams.append("reSaveAll", "true");
3007
+ if (typeof attrKey != "string") {
3008
+ attrKey = PathUtils.Wrap(attrKey);
3090
3009
  }
3091
- let url = typeId ? `entityType/${typeId}/reindex` : "entities/reindex";
3092
- url += "?" + urlParams.toString();
3093
- req = Api.PrepReqParams(req);
3094
- const res = yield api.POST(url, {}, req);
3095
- return {
3096
- pendingActionId: res.PendingActionID
3097
- };
3010
+ const urlParams = new URLSearchParams();
3011
+ for (const entityId of entityIds) {
3012
+ urlParams.append("entityId", entityId);
3013
+ }
3014
+ urlParams.append("attrKey", attrKey);
3015
+ urlParams.append("dateTimeFrom", dateTimeFrom);
3016
+ urlParams.append("dateTimeTo", dateTimeTo);
3017
+ yield api.DELETE(`v1/entity/historicData?${urlParams.toString()}`, Api.PrepReqParams(req));
3018
+ // Kill cache for all Entity cached Entity records related to the attrKey.
3019
+ api.Cache.RemoveByContains(Entity.GetHistoricContainsKey(attrKey));
3020
+ // Kill any stats cache that includes any of the Entity IDs.
3021
+ ClearCacheByEntityIds(api, entityIds);
3098
3022
  });
3099
3023
  }
3100
- EntityType.ReIndex = ReIndex;
3101
- /**
3102
- * Counts the total number of Entities in an Entity Type.
3103
- * @param params
3104
- * @returns
3105
- */
3106
- function Count(params) {
3107
- return __awaiter(this, void 0, void 0, function* () {
3108
- let { entityTypeId, api, req } = params;
3109
- if (!entityTypeId) {
3110
- throw ("Type ID is required.");
3024
+ EntityHistoricData.Delete = Delete;
3025
+ function GetListCacheKey(entityIds, attrKey, dateTimeFrom, dateTimeTo) {
3026
+ return Api.ECacheKey.EntityHistoricDataRec + Api.ECacheKey.Id + entityIds.join(",") + Api.ECacheKey.Id + attrKey + Api.ECacheKey.Id + dateTimeFrom + Api.ECacheKey.Id + dateTimeTo;
3027
+ }
3028
+ EntityHistoricData.GetListCacheKey = GetListCacheKey;
3029
+ function GetStatsCacheKey(entityIds, typeId) {
3030
+ if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3031
+ entityIds = [];
3032
+ }
3033
+ if (!typeId) {
3034
+ typeId = "";
3035
+ }
3036
+ return Api.ECacheKey.EntityHistoricDataStats + Api.ECacheKey.Id + typeId + Api.ECacheKey.Id + entityIds.join(",");
3037
+ }
3038
+ EntityHistoricData.GetStatsCacheKey = GetStatsCacheKey;
3039
+ function ClearCacheByEntityIds(api, entityIds) {
3040
+ if (!api || !(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3041
+ return;
3042
+ }
3043
+ const REC_KEY_PREFIX = Api.ECacheKey.EntityHistoricDataRec + Api.ECacheKey.Id;
3044
+ const STATS_KEY_PREFIX = Api.ECacheKey.EntityHistoricDataStats + Api.ECacheKey.Id;
3045
+ api.Cache.RemoveByCallback((key) => {
3046
+ let keyStr = String(key);
3047
+ if (!keyStr.startsWith(STATS_KEY_PREFIX) && !keyStr.startsWith(REC_KEY_PREFIX)) {
3048
+ return false;
3111
3049
  }
3112
- if (!api) {
3113
- api = ENVIRONMENT.Api().GetBruceApi();
3050
+ // Shorten to speed up the next step.
3051
+ keyStr = keyStr.replace(STATS_KEY_PREFIX, "").replace(REC_KEY_PREFIX, "");
3052
+ // Look for any matching Entity IDs.
3053
+ for (let i = 0; i < entityIds.length; i++) {
3054
+ const entityId = entityIds[i];
3055
+ if (keyStr.includes(entityId)) {
3056
+ return true;
3057
+ }
3114
3058
  }
3115
- const url = `entityType/${entityTypeId}/entitiesCount`;
3116
- const { TotalEntities } = yield api.GET(url, Api.PrepReqParams(req));
3117
- return TotalEntities;
3059
+ return false;
3118
3060
  });
3119
3061
  }
3120
- EntityType.Count = Count;
3062
+ EntityHistoricData.ClearCacheByEntityIds = ClearCacheByEntityIds;
3063
+ })(EntityHistoricData || (EntityHistoricData = {}));
3064
+
3065
+ /**
3066
+ * Describes an entity type schema attribute.
3067
+ */
3068
+ var EntityAttribute;
3069
+ (function (EntityAttribute) {
3070
+ let EType;
3071
+ (function (EType) {
3072
+ // Arbitrary text attribute.
3073
+ EType["String"] = "String";
3074
+ // Floating point number attribute.
3075
+ EType["Double"] = "Double";
3076
+ // Whole number attribute.
3077
+ EType["Integer"] = "Integer";
3078
+ // iso8601 date time string.
3079
+ EType["Datetime"] = "Datetime";
3080
+ // Group of attributes.
3081
+ EType["Structure"] = "Structure";
3082
+ // Nextspace vector geometry.
3083
+ EType["Geometry"] = "Geometry";
3084
+ // True/false attribute.
3085
+ EType["Boolean"] = "Boolean";
3086
+ // String User ID.
3087
+ EType["User"] = "User";
3088
+ // String Group ID.
3089
+ EType["UserGroup"] = "UserGroup";
3090
+ // String Entity ID.
3091
+ EType["Entity"] = "Entity";
3092
+ // Url attribute.
3093
+ EType["Url"] = "Url";
3094
+ // Serial number that increments for each new entity/missing-attr-value.
3095
+ EType["Serial"] = "Serial";
3096
+ })(EType = EntityAttribute.EType || (EntityAttribute.EType = {}));
3121
3097
  /**
3122
- * Returns cache identifier for an entity type.
3123
- * Example: {
3124
- * const api: BruceApi.Api = ...;
3125
- * const key = GetCacheKey("abc");
3126
- * api.Cache.Remove(key);
3127
- * }
3128
- * @param typeId
3129
- * @param expandLODs
3130
- * @returns
3098
+ * Describes url open behavior.
3131
3099
  */
3132
- function GetCacheKey(typeId, expandLODs) {
3133
- let key = `${Api.ECacheKey.EntityType}${Api.ECacheKey.Id}${typeId}`;
3134
- if (expandLODs) {
3135
- key += "_LOD_" + expandLODs;
3136
- }
3137
- return key;
3138
- }
3139
- EntityType.GetCacheKey = GetCacheKey;
3100
+ let EOpenBehavior;
3101
+ (function (EOpenBehavior) {
3102
+ EOpenBehavior["POPUP"] = "POPUP";
3103
+ EOpenBehavior["NEW_TAB"] = "NEW_TAB";
3104
+ })(EOpenBehavior = EntityAttribute.EOpenBehavior || (EntityAttribute.EOpenBehavior = {}));
3140
3105
  /**
3141
- * Returns cache identifier for a list of entity types.
3142
- * Example: {
3143
- * const api: BruceApi.Api = ...;
3144
- * const key = GetListCacheKey();
3145
- * api.Cache.Remove(key);
3146
- * }
3147
- * @param typeIds
3106
+ * Returns an attribute from a provided hierarchy of attributes.
3107
+ * Eg: Use the path: ["Bruce", "ID"] to find the "ID" attribute.
3108
+ * @param items
3109
+ * @param path
3148
3110
  * @returns
3149
3111
  */
3150
- function GetListCacheKey(params) {
3151
- if (!params) {
3152
- params = {};
3112
+ function GetAttribute(items, path) {
3113
+ if (!items || !path || !path.length) {
3114
+ return null;
3153
3115
  }
3154
- let { typeIds, expandSettings, parentTypeId, expandLODs, search } = params;
3155
- let key = Api.ECacheKey.EntityType;
3156
- if (!typeIds) {
3157
- typeIds = [];
3116
+ const key = path[0];
3117
+ const item = items.find((i) => i.Key === key);
3118
+ if (!item) {
3119
+ return null;
3158
3120
  }
3159
- key += (typeIds.length ? Api.ECacheKey.Id : "") + typeIds.join(",");
3160
- if (parentTypeId) {
3161
- key += "_PARENT_" + parentTypeId;
3121
+ if (path.length === 1) {
3122
+ return item;
3162
3123
  }
3163
- if (!expandSettings) {
3164
- expandSettings = false;
3124
+ return GetAttribute(item.Structure, path.slice(1));
3125
+ }
3126
+ EntityAttribute.GetAttribute = GetAttribute;
3127
+ /**
3128
+ * Removes an attribute from a provided hierarchy of attributes.
3129
+ * Eg: Use the path: ["Bruce", "ID"] to remove the "ID" attribute.
3130
+ * This will mutate the items array.
3131
+ * @param items
3132
+ * @param path
3133
+ */
3134
+ function RemoveAttribute(items, path) {
3135
+ if (!items || !(path === null || path === void 0 ? void 0 : path.length)) {
3136
+ return;
3165
3137
  }
3166
- if (!expandLODs) {
3167
- expandLODs = false;
3138
+ const key = path[0];
3139
+ if (path.length === 1) {
3140
+ // If we're at the last key in the path, remove the item from the items array.
3141
+ const index = items.findIndex((i) => i.Key === key);
3142
+ if (index !== -1) {
3143
+ items.splice(index, 1);
3144
+ }
3145
+ return;
3168
3146
  }
3169
- key += "_SCHEMA_" + expandSettings;
3170
- key += "_LOD_" + expandLODs;
3171
- if (search) {
3172
- key += "_SEARCH_" + search;
3147
+ // If we're not at the end of the path, dig further.
3148
+ const item = items.find((i) => i.Key === key);
3149
+ if (item && item.Structure) {
3150
+ RemoveAttribute(item.Structure, path.slice(1));
3173
3151
  }
3174
- return key;
3175
- }
3176
- EntityType.GetListCacheKey = GetListCacheKey;
3177
- })(EntityType || (EntityType = {}));
3178
- /**
3179
- * Adds expected internal structure items even if they aren't there.
3180
- * Our API should be including them but this is a safety net.
3181
- * @param type
3182
- */
3183
- function appendInternalAttrSchema(type) {
3184
- // Schema not loaded. We'll ignore.
3185
- if (type == null || type.DataSchema == null) {
3186
- return;
3187
3152
  }
3188
- // Append internal attributes.
3189
- if (!type.DataSchema.Structure) {
3190
- type.DataSchema.Structure = [];
3191
- }
3192
- let bruce = type.DataSchema.Structure.find(a => a.Key == "Bruce");
3193
- if (!bruce) {
3194
- bruce = {
3195
- Key: "Bruce",
3196
- Name: "Bruce",
3197
- Description: "Nextspace internal attributes.",
3198
- Type: EntityAttribute.EType.Structure,
3199
- Structure: [],
3200
- IsIndexed: true,
3201
- IsImportant: false
3202
- };
3203
- type.DataSchema.Structure.push(bruce);
3204
- }
3205
- if (!bruce.Structure) {
3206
- bruce.Structure = [];
3207
- }
3208
- // Append any missing internal attributes.
3209
- if (!bruce.Structure.find(x => x.Key == "ID")) {
3210
- bruce.Structure.push({
3211
- Key: "ID",
3212
- Name: "ID",
3213
- Description: "Unique identifier for the Entity.",
3214
- Type: EntityAttribute.EType.String,
3215
- IsIndexed: true,
3216
- IsImportant: true
3217
- });
3218
- }
3219
- if (!bruce.Structure.find(x => x.Key == "Location")) {
3220
- bruce.Structure.push({
3221
- Key: "Location",
3222
- Name: "Location",
3223
- Description: "Location data.",
3224
- Type: EntityAttribute.EType.Structure,
3225
- Structure: [
3226
- {
3227
- Key: "latitude",
3228
- Name: "Latitude",
3229
- Type: EntityAttribute.EType.Double,
3230
- IsIndexed: true,
3231
- IsImportant: false
3232
- },
3233
- {
3234
- Key: "longitude",
3235
- Name: "Longitude",
3236
- Type: EntityAttribute.EType.Double,
3237
- IsIndexed: true,
3238
- IsImportant: false
3239
- },
3240
- {
3241
- Key: "altitude",
3242
- Name: "Altitude",
3243
- Type: EntityAttribute.EType.Double,
3244
- IsIndexed: true,
3245
- IsImportant: false
3246
- }
3247
- ]
3248
- });
3249
- }
3250
- if (!bruce.Structure.find(x => x.Key == "Boundaries")) {
3251
- bruce.Structure.push({
3252
- Key: "Boundaries",
3253
- Name: "Boundaries",
3254
- Description: "Boundaries data.",
3255
- Type: EntityAttribute.EType.Structure,
3256
- Structure: [
3257
- {
3258
- Key: "minLongitude",
3259
- Name: "Min Longitude",
3260
- Type: EntityAttribute.EType.Double,
3261
- IsIndexed: true,
3262
- IsImportant: false
3263
- },
3264
- {
3265
- Key: "maxLongitude",
3266
- Name: "Max Longitude",
3267
- Type: EntityAttribute.EType.Double,
3268
- IsIndexed: true,
3269
- IsImportant: false
3270
- },
3271
- {
3272
- Key: "minLatitude",
3273
- Name: "Min Latitude",
3274
- Type: EntityAttribute.EType.Double,
3275
- IsIndexed: true,
3276
- IsImportant: false
3277
- },
3278
- {
3279
- Key: "maxLatitude",
3280
- Name: "Max Latitude",
3281
- Type: EntityAttribute.EType.Double,
3282
- IsIndexed: true,
3283
- IsImportant: false
3284
- },
3285
- {
3286
- Key: "minAltitude",
3287
- Name: "Min Altitude",
3288
- Type: EntityAttribute.EType.Double,
3289
- IsIndexed: true,
3290
- IsImportant: false
3291
- },
3292
- {
3293
- Key: "maxAltitude",
3294
- Name: "Max Altitude",
3295
- Type: EntityAttribute.EType.Double,
3296
- IsIndexed: true,
3297
- IsImportant: false
3298
- }
3299
- ]
3300
- });
3301
- }
3302
- if (!bruce.Structure.find(x => x.Key == "Transform")) {
3303
- bruce.Structure.push({
3304
- Key: "Transform",
3305
- Name: "Transform",
3306
- Description: "Transform data.",
3307
- IsIndexed: true,
3308
- IsImportant: false,
3309
- Type: EntityAttribute.EType.Structure,
3310
- Structure: [
3311
- {
3312
- Key: "heading",
3313
- Name: "Heading",
3314
- IsIndexed: true,
3315
- IsImportant: false,
3316
- Type: EntityAttribute.EType.Double
3317
- },
3318
- {
3319
- Key: "pitch",
3320
- Name: "Pitch",
3321
- IsIndexed: true,
3322
- IsImportant: false,
3323
- Type: EntityAttribute.EType.Double
3324
- },
3325
- {
3326
- Key: "roll",
3327
- Name: "Roll",
3328
- IsIndexed: true,
3329
- IsImportant: false,
3330
- Type: EntityAttribute.EType.Double
3331
- },
3332
- {
3333
- Key: "scale",
3334
- Name: "Scale",
3335
- IsIndexed: true,
3336
- IsImportant: false,
3337
- Type: EntityAttribute.EType.Double
3338
- }
3339
- ]
3340
- });
3341
- }
3342
- if (!bruce.Structure.find(x => x.Key == "VectorGeometry")) {
3343
- bruce.Structure.push({
3344
- Key: "VectorGeometry",
3345
- Name: "Geometry",
3346
- Description: "Geometry data.",
3347
- Type: EntityAttribute.EType.Geometry,
3348
- IsIndexed: true,
3349
- IsImportant: false
3350
- });
3351
- }
3352
- // Filter out migrated/outdated ones.
3353
- // Removed from root and the internal structure.
3354
- const OUTDATED_INTERNAL = ["position", "geometry", "location", "boundaries", "transform"];
3355
- bruce.Structure = bruce.Structure.filter(a => !OUTDATED_INTERNAL.includes(a.Key));
3356
- type.DataSchema.Structure = type.DataSchema.Structure.filter(a => !OUTDATED_INTERNAL.includes(a.Key));
3357
- }
3358
-
3359
- /**
3360
- * Utility to help with parsing and wrapping Nextspace paths.
3361
- */
3362
- var PathUtils;
3363
- (function (PathUtils) {
3153
+ EntityAttribute.RemoveAttribute = RemoveAttribute;
3364
3154
  /**
3365
- * Parses a Bruce string path into an array of strings.
3366
- * Example of path: "\"location\"/\"latitude\"" or "location/latitude".
3367
- * @param str
3368
- * @returns
3155
+ * Adds an attribute to a provided hierarchy of attributes.
3156
+ * Eg: Use the path: ["Bruce", "ID"] to add the "ID" attribute.
3157
+ * This will mutate the items array.
3158
+ * This requires the path to be valid and for a parent attribute to exist.
3159
+ * @param items
3160
+ * @param path
3161
+ * @param attribute
3369
3162
  */
3370
- function Parse(str) {
3371
- if (!(str === null || str === void 0 ? void 0 : str.length)) {
3372
- return [];
3163
+ function AddAttribute(items, path, attribute) {
3164
+ if (!items || !(path === null || path === void 0 ? void 0 : path.length)) {
3165
+ return;
3373
3166
  }
3374
- const broken = str.split("/");
3375
- // Remove quotes from the first and last chars.
3376
- for (let i = 0; i < broken.length; i++) {
3377
- let piece = broken[i];
3378
- if (piece.startsWith("\"")) {
3379
- piece = piece.substring(1);
3167
+ const key = path[0];
3168
+ if (path.length === 1) {
3169
+ // If we're at the last key in the path, add the attribute to the items array.
3170
+ const index = items.findIndex((i) => i.Key === key);
3171
+ if (index !== -1) {
3172
+ // Overwrite existing attribute if it already exists.
3173
+ items[index] = attribute;
3380
3174
  }
3381
- if (piece.endsWith("\"")) {
3382
- piece = piece.substring(0, piece.length - 1);
3175
+ else {
3176
+ // Add new attribute if it doesn't exist.
3177
+ items.push(attribute);
3383
3178
  }
3384
- broken[i] = piece;
3179
+ return;
3385
3180
  }
3386
- return broken;
3181
+ // If we're not at the end of the path, dig further.
3182
+ let item = items.find((i) => i.Key === key);
3183
+ if (!item) {
3184
+ item = { Key: key, Structure: [] };
3185
+ items.push(item);
3186
+ }
3187
+ if (!item.Structure) {
3188
+ item.Structure = [];
3189
+ }
3190
+ AddAttribute(item.Structure, path.slice(1), attribute);
3387
3191
  }
3388
- PathUtils.Parse = Parse;
3192
+ EntityAttribute.AddAttribute = AddAttribute;
3193
+ })(EntityAttribute || (EntityAttribute = {}));
3194
+
3195
+ /**
3196
+ * Describes the "Entity Type" concept within Nextspace.
3197
+ * An entity type is an "expectation" of what data "should" look like in a particular entity record.
3198
+ * The schema is stencils onto entity data to filter out what we should display or search against.
3199
+ */
3200
+ var EntityType;
3201
+ (function (EntityType) {
3389
3202
  /**
3390
- * Wraps an array of strings into a Nextspace string path.
3391
- * @param path
3203
+ * Gets an entity type record.
3204
+ * @param params
3392
3205
  * @returns
3393
3206
  */
3394
- function Wrap(path) {
3395
- if (!(path === null || path === void 0 ? void 0 : path.length)) {
3396
- return "";
3397
- }
3398
- let tmp = "\"";
3399
- for (let i = 0; i < path.length; i++) {
3400
- let section = path[i];
3401
- tmp += section;
3402
- if (i < path.length - 1) {
3403
- tmp += "\"/\"";
3207
+ function Get(params) {
3208
+ return __awaiter(this, void 0, void 0, function* () {
3209
+ let { api, entityTypeId: typeId, req: reqParams, expandLODs } = params;
3210
+ if (!typeId) {
3211
+ throw ("Type ID is required.");
3212
+ }
3213
+ if (!api) {
3214
+ api = ENVIRONMENT.Api().GetBruceApi();
3215
+ }
3216
+ const key = GetCacheKey(typeId, expandLODs);
3217
+ const cache = api.GetCacheItem(key, reqParams);
3218
+ if (cache === null || cache === void 0 ? void 0 : cache.found) {
3219
+ return cache.data;
3404
3220
  }
3405
- }
3406
- tmp += "\"";
3407
- return tmp;
3221
+ const prom = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
3222
+ try {
3223
+ const urlParams = new URLSearchParams();
3224
+ if (expandLODs) {
3225
+ urlParams.append("Expand", "LOD");
3226
+ }
3227
+ const url = `entitytype/${typeId}?${urlParams.toString()}`;
3228
+ const data = yield api.GET(url, Api.PrepReqParams(reqParams));
3229
+ appendInternalAttrSchema(data);
3230
+ res({
3231
+ entityType: data
3232
+ });
3233
+ }
3234
+ catch (e) {
3235
+ rej(e);
3236
+ }
3237
+ }));
3238
+ api.SetCacheItem({
3239
+ key,
3240
+ value: prom,
3241
+ req: reqParams
3242
+ });
3243
+ return prom;
3244
+ });
3408
3245
  }
3409
- PathUtils.Wrap = Wrap;
3246
+ EntityType.Get = Get;
3410
3247
  /**
3411
- * Parses a Nextspace legacy string path into an array of strings.
3412
- * @param str
3413
- * @returns
3248
+ * Deletes an entity type record and all corresponding entities.
3249
+ * @param params
3414
3250
  */
3415
- function ParseLegacy(str) {
3416
- if (!(str === null || str === void 0 ? void 0 : str.length)) {
3417
- return [];
3418
- }
3419
- const broken = str.split(".");
3420
- for (let i = 0; i < broken.length; i++) {
3421
- let piece = broken[i];
3422
- if (piece.startsWith("\"")) {
3423
- piece = piece.substring(1);
3251
+ function Delete(params) {
3252
+ return __awaiter(this, void 0, void 0, function* () {
3253
+ let { api, entityTypeId: typeId, req: reqParams } = params;
3254
+ if (!typeId) {
3255
+ throw ("Type ID is required.");
3424
3256
  }
3425
- if (piece.endsWith("\"")) {
3426
- piece = piece.substring(0, piece.length - 1);
3257
+ if (!api) {
3258
+ api = ENVIRONMENT.Api().GetBruceApi();
3427
3259
  }
3428
- broken[i] = piece;
3429
- }
3430
- return broken;
3260
+ yield api.DELETE(`entitytype/${typeId}`, Api.PrepReqParams(reqParams));
3261
+ api.Cache.RemoveByStartsWith(GetCacheKey(typeId));
3262
+ api.Cache.RemoveByStartsWith(GetListCacheKey());
3263
+ });
3431
3264
  }
3432
- PathUtils.ParseLegacy = ParseLegacy;
3433
- })(PathUtils || (PathUtils = {}));
3434
-
3435
- var EntityHistoricData;
3436
- (function (EntityHistoricData) {
3265
+ EntityType.Delete = Delete;
3437
3266
  /**
3438
- * Returns historic data for an array of Entity IDs.
3439
- * A maximum number of records will be returned per Entity ID, this information is returned in the response.
3267
+ * Gets a list of entity types.
3440
3268
  * @param params
3441
3269
  * @returns
3442
3270
  */
3443
3271
  function GetList(params) {
3444
3272
  return __awaiter(this, void 0, void 0, function* () {
3445
- let { entityIds, attrKey, dateTimeFrom, dateTimeTo, api, req } = params;
3446
- // Save time and just return a none response if no entity IDs are provided.
3447
- if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3448
- return {
3449
- limitPerEntity: 0,
3450
- recordsByIds: {}
3451
- };
3452
- }
3273
+ let { entityTypeIds, api, req: reqParams, parentTypeId, expandSettings, search, expandLODs } = params;
3453
3274
  if (!api) {
3454
3275
  api = ENVIRONMENT.Api().GetBruceApi();
3455
3276
  }
3456
- let attrKeyStr = null;
3457
- if (attrKey) {
3458
- if (typeof attrKey != "string") {
3459
- attrKeyStr = PathUtils.Wrap(attrKey);
3460
- }
3461
- else {
3462
- attrKeyStr = attrKey;
3463
- }
3277
+ const cache = api.GetCacheItem(GetListCacheKey({
3278
+ typeIds: entityTypeIds,
3279
+ parentTypeId,
3280
+ expandLODs,
3281
+ expandSettings,
3282
+ search
3283
+ }), reqParams);
3284
+ if (cache === null || cache === void 0 ? void 0 : cache.found) {
3285
+ return cache.data;
3464
3286
  }
3465
- // If we have more than 100 Entity IDs we'll have to split the request to avoid a URL that is too long.
3466
- const MAX_IDS = 100;
3467
- // We will recursively call this function to get all the data.
3468
- // Then merge at the end and return.
3469
- if (entityIds.length > MAX_IDS) {
3470
- const reqs = [];
3471
- // Making the ID batches.
3472
- // If this is too long we can end up in a loop.
3473
- const splitEntityIds = [];
3474
- for (let i = 0; i < entityIds.length; i += MAX_IDS) {
3475
- const batchIds = entityIds.slice(i, i + MAX_IDS);
3476
- // Detecting this early to avoid infinite loops.
3477
- if (batchIds.length > MAX_IDS) {
3478
- throw new Error("Nextspace Developer Error: EntityHistoricData.GetList() has too many Entity IDs. Please contact support.");
3287
+ const req = new Promise((res, rej) => __awaiter(this, void 0, void 0, function* () {
3288
+ try {
3289
+ // If we have an array of typeIds then we'll request in batches to avoid overflowing the URL.
3290
+ const BATCH_SIZE = 20;
3291
+ const reqs = [];
3292
+ if (entityTypeIds) {
3293
+ for (let i = 0; i < entityTypeIds.length; i += BATCH_SIZE) {
3294
+ const batch = entityTypeIds.slice(i, i + BATCH_SIZE);
3295
+ const urlParams = new URLSearchParams();
3296
+ for (const id of batch) {
3297
+ urlParams.append("ID", id);
3298
+ }
3299
+ if (parentTypeId) {
3300
+ urlParams.append("ParentTypeID", parentTypeId);
3301
+ }
3302
+ if (expandSettings && expandLODs) {
3303
+ urlParams.append("Expand", "true");
3304
+ }
3305
+ else if (expandSettings) {
3306
+ urlParams.append("Expand", "Schema");
3307
+ }
3308
+ else if (expandLODs) {
3309
+ urlParams.append("Expand", "LOD");
3310
+ }
3311
+ if (search) {
3312
+ urlParams.append("Search", search);
3313
+ }
3314
+ reqs.push(api.GET("entitytypes?" + urlParams.toString(), Api.PrepReqParams(reqParams)));
3315
+ }
3479
3316
  }
3480
- splitEntityIds.push(batchIds);
3481
- }
3482
- for (const splitEntityId of splitEntityIds) {
3483
- reqs.push(GetList({
3484
- entityIds: splitEntityId,
3485
- attrKey: attrKeyStr,
3486
- dateTimeFrom: dateTimeFrom,
3487
- dateTimeTo: dateTimeTo,
3488
- api: api,
3489
- req: req
3490
- }));
3491
- }
3492
- const res = yield Promise.all(reqs);
3493
- const recordsByIds = {};
3494
- let limitPerEntity = 0;
3495
- for (const r of res) {
3496
- limitPerEntity = r.limitPerEntity;
3497
- for (const entityId in r.recordsByIds) {
3498
- recordsByIds[entityId] = r.recordsByIds[entityId];
3317
+ else {
3318
+ const urlParams = new URLSearchParams();
3319
+ if (parentTypeId) {
3320
+ urlParams.append("ParentTypeID", parentTypeId);
3321
+ }
3322
+ if (expandSettings && expandLODs) {
3323
+ urlParams.append("Expand", "true");
3324
+ }
3325
+ else if (expandSettings) {
3326
+ urlParams.append("Expand", "Schema");
3327
+ }
3328
+ else if (expandLODs) {
3329
+ urlParams.append("Expand", "LOD");
3330
+ }
3331
+ if (search) {
3332
+ urlParams.append("Search", search);
3333
+ }
3334
+ reqs.push(api.GET("entitytypes?" + urlParams.toString(), Api.PrepReqParams(reqParams)));
3335
+ }
3336
+ const data = yield Promise.all(reqs);
3337
+ // Populate array, while checking for already added types.
3338
+ const types = [];
3339
+ for (const item of data) {
3340
+ for (const type of item.Items) {
3341
+ appendInternalAttrSchema(type);
3342
+ if (!types.find(x => x.ID == type.ID)) {
3343
+ types.push(type);
3344
+ }
3345
+ }
3499
3346
  }
3347
+ res({
3348
+ entityTypes: types
3349
+ });
3500
3350
  }
3501
- // Returning merged data.
3502
- return {
3503
- recordsByIds: recordsByIds,
3504
- limitPerEntity: limitPerEntity
3505
- };
3351
+ catch (e) {
3352
+ rej(e);
3353
+ }
3354
+ }));
3355
+ if (!parentTypeId) {
3356
+ api.SetCacheItem({
3357
+ key: GetListCacheKey({
3358
+ typeIds: entityTypeIds,
3359
+ parentTypeId,
3360
+ expandSettings,
3361
+ expandLODs,
3362
+ search
3363
+ }),
3364
+ value: req,
3365
+ req: reqParams,
3366
+ duration: 60 * 5 // 5 minutes.
3367
+ });
3506
3368
  }
3507
- const cacheKey = GetListCacheKey(entityIds, attrKeyStr, dateTimeFrom, dateTimeTo);
3508
- const cached = api.GetCacheItem(cacheKey, req);
3509
- if (cached === null || cached === void 0 ? void 0 : cached.found) {
3510
- return cached.data;
3369
+ return req;
3370
+ });
3371
+ }
3372
+ EntityType.GetList = GetList;
3373
+ /**
3374
+ * Updates or creates an entity type record.
3375
+ * @param params
3376
+ * @returns
3377
+ */
3378
+ function Update(params) {
3379
+ return __awaiter(this, void 0, void 0, function* () {
3380
+ let { api, entityType: data, req: reqParams } = params;
3381
+ if (!api) {
3382
+ api = ENVIRONMENT.Api().GetBruceApi();
3511
3383
  }
3512
- const urlParams = new URLSearchParams();
3513
- for (const entityId of entityIds) {
3514
- urlParams.append("entityId", entityId);
3384
+ if (!data) {
3385
+ data = {};
3515
3386
  }
3516
- if (attrKeyStr) {
3517
- urlParams.append("attrKey", attrKeyStr);
3387
+ if (!data.ID) {
3388
+ data.ID = ObjectUtils.UId();
3518
3389
  }
3519
- urlParams.append("dateTimeFrom", dateTimeFrom);
3520
- urlParams.append("dateTimeTo", dateTimeTo);
3521
- const prom = api.GET(`v1/entity/historicData?${urlParams.toString()}`, Api.PrepReqParams(req));
3522
- api.SetCacheItem({
3523
- key: cacheKey,
3524
- value: prom,
3525
- req: req,
3526
- // Short cache. 30 seconds.
3527
- duration: 30000
3528
- });
3529
- return prom;
3390
+ if (!data.Name) {
3391
+ data.Name = data.ID;
3392
+ }
3393
+ // Will not append if we're not updating schema (not specified).
3394
+ appendInternalAttrSchema(data);
3395
+ const res = yield api.POST(`entitytype/${data.ID}`, data, Api.PrepReqParams(reqParams));
3396
+ api.Cache.RemoveByStartsWith(GetCacheKey(data.ID));
3397
+ api.Cache.RemoveByStartsWith(GetListCacheKey());
3398
+ // Useful to append afterwards as newly created Entity Types may have it missing.
3399
+ // This makes our UI apps not have to check for default attribute existence.
3400
+ appendInternalAttrSchema(res);
3401
+ return {
3402
+ entityType: res
3403
+ };
3530
3404
  });
3531
3405
  }
3532
- EntityHistoricData.GetList = GetList;
3406
+ EntityType.Update = Update;
3533
3407
  /**
3534
- * Returns historic data statistics for an array of Entity IDs.
3408
+ * Starts a re-index background action on a specified Entity Type.
3409
+ * This will ensure searchable data follows the current schema version.
3410
+ * This will also perform certain data cleanup so that the data is consistent.
3535
3411
  * @param params
3536
3412
  * @returns
3537
3413
  */
3538
- function GetStats(params) {
3414
+ function ReIndex(params) {
3539
3415
  return __awaiter(this, void 0, void 0, function* () {
3540
- let { entityIds, entityTypeId, api, req } = params;
3541
- // Save time and just return a none response if no entity IDs or type ID are provided.
3542
- if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length) && !entityTypeId) {
3543
- return {
3544
- stats: []
3545
- };
3546
- }
3416
+ let { api, entityTypeId: typeId, req, dataTransformId, reSaveAll } = params;
3547
3417
  if (!api) {
3548
3418
  api = ENVIRONMENT.Api().GetBruceApi();
3549
3419
  }
3550
- req = Api.PrepReqParams(req);
3551
- const cacheKey = GetStatsCacheKey(entityIds, entityTypeId);
3552
- const cached = api.GetCacheItem(cacheKey, req);
3553
- if (cached === null || cached === void 0 ? void 0 : cached.found) {
3554
- return cached.data;
3420
+ const urlParams = new URLSearchParams();
3421
+ if (dataTransformId) {
3422
+ urlParams.append("dataTransformID", String(dataTransformId));
3555
3423
  }
3556
- const prom = yield api.POST("v1/entity/historicData/stats", {
3557
- entityIds: entityIds,
3558
- entityTypeId: entityTypeId
3559
- }, req);
3560
- api.SetCacheItem({
3561
- key: cacheKey,
3562
- value: prom,
3563
- req: req,
3564
- // Short cache. 60 seconds.
3565
- duration: 60000
3566
- });
3567
- return prom;
3424
+ if (reSaveAll) {
3425
+ urlParams.append("reSaveAll", "true");
3426
+ }
3427
+ let url = typeId ? `entityType/${typeId}/reindex` : "entities/reindex";
3428
+ url += "?" + urlParams.toString();
3429
+ req = Api.PrepReqParams(req);
3430
+ const res = yield api.POST(url, {}, req);
3431
+ return {
3432
+ pendingActionId: res.PendingActionID
3433
+ };
3568
3434
  });
3569
3435
  }
3570
- EntityHistoricData.GetStats = GetStats;
3436
+ EntityType.ReIndex = ReIndex;
3571
3437
  /**
3572
- * Creates or updates historic data records.
3573
- * Please note that the expected input/output does not include internal fields found inside the "Bruce" attribute.
3438
+ * Counts the total number of Entities in an Entity Type.
3574
3439
  * @param params
3575
3440
  * @returns
3576
3441
  */
3577
- function Update(params) {
3578
- var _a;
3442
+ function Count(params) {
3579
3443
  return __awaiter(this, void 0, void 0, function* () {
3580
- let { records, api, req } = params;
3581
- // Save time and just return a none response if no records are provided.
3582
- if (!(records === null || records === void 0 ? void 0 : records.length)) {
3583
- return {
3584
- records: []
3585
- };
3444
+ let { entityTypeId, api, req } = params;
3445
+ if (!entityTypeId) {
3446
+ throw ("Type ID is required.");
3586
3447
  }
3587
3448
  if (!api) {
3588
3449
  api = ENVIRONMENT.Api().GetBruceApi();
3589
3450
  }
3590
- const res = yield api.POST("v1/entity/historicData", {
3591
- records: records
3592
- }, Api.PrepReqParams(req));
3593
- // Kill cache for every unique attrKey.
3594
- let attrKeys = records.map(r => r.attrKey);
3595
- attrKeys = attrKeys.filter((v, i) => attrKeys.indexOf(v) === i);
3596
- for (const attrKey of attrKeys) {
3597
- api.Cache.RemoveByContains(Entity.GetHistoricContainsKey(attrKey));
3598
- }
3599
- // Kill any stats cache that includes any of the Entity IDs.
3600
- if ((_a = res.records) === null || _a === void 0 ? void 0 : _a.length) {
3601
- const entityIds = res.records.map(r => r.entityId).filter((v, i) => v && res.records.indexOf(v) === i);
3602
- ClearCacheByEntityIds(api, entityIds);
3603
- }
3604
- return res;
3451
+ const url = `entityType/${entityTypeId}/entitiesCount`;
3452
+ const { TotalEntities } = yield api.GET(url, Api.PrepReqParams(req));
3453
+ return TotalEntities;
3454
+ });
3455
+ }
3456
+ EntityType.Count = Count;
3457
+ /**
3458
+ * Returns cache identifier for an entity type.
3459
+ * Example: {
3460
+ * const api: BruceApi.Api = ...;
3461
+ * const key = GetCacheKey("abc");
3462
+ * api.Cache.Remove(key);
3463
+ * }
3464
+ * @param typeId
3465
+ * @param expandLODs
3466
+ * @returns
3467
+ */
3468
+ function GetCacheKey(typeId, expandLODs) {
3469
+ let key = `${Api.ECacheKey.EntityType}${Api.ECacheKey.Id}${typeId}`;
3470
+ if (expandLODs) {
3471
+ key += "_LOD_" + expandLODs;
3472
+ }
3473
+ return key;
3474
+ }
3475
+ EntityType.GetCacheKey = GetCacheKey;
3476
+ /**
3477
+ * Returns cache identifier for a list of entity types.
3478
+ * Example: {
3479
+ * const api: BruceApi.Api = ...;
3480
+ * const key = GetListCacheKey();
3481
+ * api.Cache.Remove(key);
3482
+ * }
3483
+ * @param typeIds
3484
+ * @returns
3485
+ */
3486
+ function GetListCacheKey(params) {
3487
+ if (!params) {
3488
+ params = {};
3489
+ }
3490
+ let { typeIds, expandSettings, parentTypeId, expandLODs, search } = params;
3491
+ let key = Api.ECacheKey.EntityType;
3492
+ if (!typeIds) {
3493
+ typeIds = [];
3494
+ }
3495
+ key += (typeIds.length ? Api.ECacheKey.Id : "") + typeIds.join(",");
3496
+ if (parentTypeId) {
3497
+ key += "_PARENT_" + parentTypeId;
3498
+ }
3499
+ if (!expandSettings) {
3500
+ expandSettings = false;
3501
+ }
3502
+ if (!expandLODs) {
3503
+ expandLODs = false;
3504
+ }
3505
+ key += "_SCHEMA_" + expandSettings;
3506
+ key += "_LOD_" + expandLODs;
3507
+ if (search) {
3508
+ key += "_SEARCH_" + search;
3509
+ }
3510
+ return key;
3511
+ }
3512
+ EntityType.GetListCacheKey = GetListCacheKey;
3513
+ })(EntityType || (EntityType = {}));
3514
+ /**
3515
+ * Adds expected internal structure items even if they aren't there.
3516
+ * Our API should be including them but this is a safety net.
3517
+ * @param type
3518
+ */
3519
+ function appendInternalAttrSchema(type) {
3520
+ // Schema not loaded. We'll ignore.
3521
+ if (type == null || type.DataSchema == null) {
3522
+ return;
3523
+ }
3524
+ // Append internal attributes.
3525
+ if (!type.DataSchema.Structure) {
3526
+ type.DataSchema.Structure = [];
3527
+ }
3528
+ let bruce = type.DataSchema.Structure.find(a => a.Key == "Bruce");
3529
+ if (!bruce) {
3530
+ bruce = {
3531
+ Key: "Bruce",
3532
+ Name: "Bruce",
3533
+ Description: "Nextspace internal attributes.",
3534
+ Type: EntityAttribute.EType.Structure,
3535
+ Structure: [],
3536
+ IsIndexed: true,
3537
+ IsImportant: false
3538
+ };
3539
+ type.DataSchema.Structure.push(bruce);
3540
+ }
3541
+ if (!bruce.Structure) {
3542
+ bruce.Structure = [];
3543
+ }
3544
+ // Append any missing internal attributes.
3545
+ if (!bruce.Structure.find(x => x.Key == "ID")) {
3546
+ bruce.Structure.push({
3547
+ Key: "ID",
3548
+ Name: "ID",
3549
+ Description: "Unique identifier for the Entity.",
3550
+ Type: EntityAttribute.EType.String,
3551
+ IsIndexed: true,
3552
+ IsImportant: true
3553
+ });
3554
+ }
3555
+ if (!bruce.Structure.find(x => x.Key == "Location")) {
3556
+ bruce.Structure.push({
3557
+ Key: "Location",
3558
+ Name: "Location",
3559
+ Description: "Location data.",
3560
+ Type: EntityAttribute.EType.Structure,
3561
+ Structure: [
3562
+ {
3563
+ Key: "latitude",
3564
+ Name: "Latitude",
3565
+ Type: EntityAttribute.EType.Double,
3566
+ IsIndexed: true,
3567
+ IsImportant: false
3568
+ },
3569
+ {
3570
+ Key: "longitude",
3571
+ Name: "Longitude",
3572
+ Type: EntityAttribute.EType.Double,
3573
+ IsIndexed: true,
3574
+ IsImportant: false
3575
+ },
3576
+ {
3577
+ Key: "altitude",
3578
+ Name: "Altitude",
3579
+ Type: EntityAttribute.EType.Double,
3580
+ IsIndexed: true,
3581
+ IsImportant: false
3582
+ }
3583
+ ]
3584
+ });
3585
+ }
3586
+ if (!bruce.Structure.find(x => x.Key == "Boundaries")) {
3587
+ bruce.Structure.push({
3588
+ Key: "Boundaries",
3589
+ Name: "Boundaries",
3590
+ Description: "Boundaries data.",
3591
+ Type: EntityAttribute.EType.Structure,
3592
+ Structure: [
3593
+ {
3594
+ Key: "minLongitude",
3595
+ Name: "Min Longitude",
3596
+ Type: EntityAttribute.EType.Double,
3597
+ IsIndexed: true,
3598
+ IsImportant: false
3599
+ },
3600
+ {
3601
+ Key: "maxLongitude",
3602
+ Name: "Max Longitude",
3603
+ Type: EntityAttribute.EType.Double,
3604
+ IsIndexed: true,
3605
+ IsImportant: false
3606
+ },
3607
+ {
3608
+ Key: "minLatitude",
3609
+ Name: "Min Latitude",
3610
+ Type: EntityAttribute.EType.Double,
3611
+ IsIndexed: true,
3612
+ IsImportant: false
3613
+ },
3614
+ {
3615
+ Key: "maxLatitude",
3616
+ Name: "Max Latitude",
3617
+ Type: EntityAttribute.EType.Double,
3618
+ IsIndexed: true,
3619
+ IsImportant: false
3620
+ },
3621
+ {
3622
+ Key: "minAltitude",
3623
+ Name: "Min Altitude",
3624
+ Type: EntityAttribute.EType.Double,
3625
+ IsIndexed: true,
3626
+ IsImportant: false
3627
+ },
3628
+ {
3629
+ Key: "maxAltitude",
3630
+ Name: "Max Altitude",
3631
+ Type: EntityAttribute.EType.Double,
3632
+ IsIndexed: true,
3633
+ IsImportant: false
3634
+ }
3635
+ ]
3605
3636
  });
3606
3637
  }
3607
- EntityHistoricData.Update = Update;
3608
- /**
3609
- * Deletes historic data records for an array of Entity IDs.
3610
- * This deletes all records within a provided key + range.
3611
- * @param params
3612
- * @returns
3613
- */
3614
- function Delete(params) {
3615
- return __awaiter(this, void 0, void 0, function* () {
3616
- let { entityIds, attrKey, dateTimeFrom, dateTimeTo, api, req } = params;
3617
- if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3618
- return;
3619
- }
3620
- if (!api) {
3621
- api = ENVIRONMENT.Api().GetBruceApi();
3622
- }
3623
- if (!attrKey || !dateTimeFrom || !dateTimeTo) {
3624
- throw new Error("Invalid parameters provided.");
3625
- }
3626
- if (typeof attrKey != "string") {
3627
- attrKey = PathUtils.Wrap(attrKey);
3628
- }
3629
- const urlParams = new URLSearchParams();
3630
- for (const entityId of entityIds) {
3631
- urlParams.append("entityId", entityId);
3632
- }
3633
- urlParams.append("attrKey", attrKey);
3634
- urlParams.append("dateTimeFrom", dateTimeFrom);
3635
- urlParams.append("dateTimeTo", dateTimeTo);
3636
- yield api.DELETE(`v1/entity/historicData?${urlParams.toString()}`, Api.PrepReqParams(req));
3637
- // Kill cache for all Entity cached Entity records related to the attrKey.
3638
- api.Cache.RemoveByContains(Entity.GetHistoricContainsKey(attrKey));
3639
- // Kill any stats cache that includes any of the Entity IDs.
3640
- ClearCacheByEntityIds(api, entityIds);
3638
+ if (!bruce.Structure.find(x => x.Key == "Transform")) {
3639
+ bruce.Structure.push({
3640
+ Key: "Transform",
3641
+ Name: "Transform",
3642
+ Description: "Transform data.",
3643
+ IsIndexed: true,
3644
+ IsImportant: false,
3645
+ Type: EntityAttribute.EType.Structure,
3646
+ Structure: [
3647
+ {
3648
+ Key: "heading",
3649
+ Name: "Heading",
3650
+ IsIndexed: true,
3651
+ IsImportant: false,
3652
+ Type: EntityAttribute.EType.Double
3653
+ },
3654
+ {
3655
+ Key: "pitch",
3656
+ Name: "Pitch",
3657
+ IsIndexed: true,
3658
+ IsImportant: false,
3659
+ Type: EntityAttribute.EType.Double
3660
+ },
3661
+ {
3662
+ Key: "roll",
3663
+ Name: "Roll",
3664
+ IsIndexed: true,
3665
+ IsImportant: false,
3666
+ Type: EntityAttribute.EType.Double
3667
+ },
3668
+ {
3669
+ Key: "scale",
3670
+ Name: "Scale",
3671
+ IsIndexed: true,
3672
+ IsImportant: false,
3673
+ Type: EntityAttribute.EType.Double
3674
+ }
3675
+ ]
3641
3676
  });
3642
3677
  }
3643
- EntityHistoricData.Delete = Delete;
3644
- function GetListCacheKey(entityIds, attrKey, dateTimeFrom, dateTimeTo) {
3645
- return Api.ECacheKey.EntityHistoricDataRec + Api.ECacheKey.Id + entityIds.join(",") + Api.ECacheKey.Id + attrKey + Api.ECacheKey.Id + dateTimeFrom + Api.ECacheKey.Id + dateTimeTo;
3646
- }
3647
- EntityHistoricData.GetListCacheKey = GetListCacheKey;
3648
- function GetStatsCacheKey(entityIds, typeId) {
3649
- if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3650
- entityIds = [];
3651
- }
3652
- if (!typeId) {
3653
- typeId = "";
3654
- }
3655
- return Api.ECacheKey.EntityHistoricDataStats + Api.ECacheKey.Id + typeId + Api.ECacheKey.Id + entityIds.join(",");
3656
- }
3657
- EntityHistoricData.GetStatsCacheKey = GetStatsCacheKey;
3658
- function ClearCacheByEntityIds(api, entityIds) {
3659
- if (!api || !(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
3660
- return;
3661
- }
3662
- const REC_KEY_PREFIX = Api.ECacheKey.EntityHistoricDataRec + Api.ECacheKey.Id;
3663
- const STATS_KEY_PREFIX = Api.ECacheKey.EntityHistoricDataStats + Api.ECacheKey.Id;
3664
- api.Cache.RemoveByCallback((key) => {
3665
- let keyStr = String(key);
3666
- if (!keyStr.startsWith(STATS_KEY_PREFIX) && !keyStr.startsWith(REC_KEY_PREFIX)) {
3667
- return false;
3668
- }
3669
- // Shorten to speed up the next step.
3670
- keyStr = keyStr.replace(STATS_KEY_PREFIX, "").replace(REC_KEY_PREFIX, "");
3671
- // Look for any matching Entity IDs.
3672
- for (let i = 0; i < entityIds.length; i++) {
3673
- const entityId = entityIds[i];
3674
- if (keyStr.includes(entityId)) {
3675
- return true;
3676
- }
3677
- }
3678
- return false;
3678
+ if (!bruce.Structure.find(x => x.Key == "VectorGeometry")) {
3679
+ bruce.Structure.push({
3680
+ Key: "VectorGeometry",
3681
+ Name: "Geometry",
3682
+ Description: "Geometry data.",
3683
+ Type: EntityAttribute.EType.Geometry,
3684
+ IsIndexed: true,
3685
+ IsImportant: false
3679
3686
  });
3680
3687
  }
3681
- EntityHistoricData.ClearCacheByEntityIds = ClearCacheByEntityIds;
3682
- })(EntityHistoricData || (EntityHistoricData = {}));
3688
+ // Filter out migrated/outdated ones.
3689
+ // Removed from root and the internal structure.
3690
+ const OUTDATED_INTERNAL = ["position", "geometry", "location", "boundaries", "transform"];
3691
+ bruce.Structure = bruce.Structure.filter(a => !OUTDATED_INTERNAL.includes(a.Key));
3692
+ type.DataSchema.Structure = type.DataSchema.Structure.filter(a => !OUTDATED_INTERNAL.includes(a.Key));
3693
+ }
3683
3694
 
3684
3695
  /**
3685
3696
  * Describes the "Entity" concept within Nextspace.
@@ -3769,38 +3780,48 @@ var Entity;
3769
3780
  }
3770
3781
  expand += expandStr;
3771
3782
  }
3772
- if (expand) {
3783
+ if (expand === null || expand === void 0 ? void 0 : expand.length) {
3773
3784
  urlParams.append("Expand", expand);
3774
3785
  }
3775
3786
  if (expandLODs) {
3776
3787
  urlParams.append("LODType", "*");
3777
3788
  }
3778
3789
  if (entityTypeId) {
3779
- urlParams.append("BruceEntityType", entityTypeId);
3790
+ urlParams.append("Type", entityTypeId);
3780
3791
  }
3781
3792
  if (historicKey) {
3782
- urlParams.set("historicKey", historicKey);
3793
+ urlParams.set("HistoricKey", historicKey);
3783
3794
  }
3784
3795
  if (historicFrom) {
3785
- urlParams.set("historicFrom", historicFrom);
3796
+ urlParams.set("HistoricFrom", historicFrom);
3786
3797
  }
3787
3798
  if (historicTo) {
3788
- urlParams.set("historicTo", historicTo);
3799
+ urlParams.set("HistoricTo", historicTo);
3789
3800
  }
3790
3801
  if (historicPoint) {
3791
- urlParams.set("historicPoint", historicPoint);
3802
+ urlParams.set("HistoricPoint", historicPoint);
3792
3803
  }
3793
3804
  if (schemaId) {
3794
- urlParams.set("schema", schemaId);
3805
+ urlParams.set("Schema", schemaId);
3795
3806
  }
3796
3807
  if (scenario && String(scenario) != "0") {
3797
3808
  urlParams.set("Scenario", String(scenario));
3798
3809
  }
3799
- urlParams.set("hasMigrated", String(Boolean(migrated)));
3800
- const data = yield api.GET(`entity/${entityId}?${urlParams.toString()}`, Api.PrepReqParams(reqParams));
3801
- res({
3802
- entity: data
3803
- });
3810
+ // v3 endpoint.
3811
+ if (migrated) {
3812
+ const data = yield api.GET(`v3/entity/${entityId}?${urlParams.toString()}`, Api.PrepReqParams(reqParams));
3813
+ res({
3814
+ entity: data
3815
+ });
3816
+ }
3817
+ // v1 endpoint.
3818
+ else {
3819
+ urlParams.set("hasMigrated", "false");
3820
+ const data = yield api.GET(`entity/${entityId}?${urlParams.toString()}`, Api.PrepReqParams(reqParams));
3821
+ res({
3822
+ entity: data
3823
+ });
3824
+ }
3804
3825
  }
3805
3826
  catch (e) {
3806
3827
  rej(e);
@@ -3915,6 +3936,14 @@ var Entity;
3915
3936
  reqData["Expand"] = "comment";
3916
3937
  }
3917
3938
  }
3939
+ if (expandSources) {
3940
+ if (reqData["Expand"]) {
3941
+ reqData["Expand"] += ",source";
3942
+ }
3943
+ else {
3944
+ reqData["Expand"] = "source";
3945
+ }
3946
+ }
3918
3947
  if (expandStr) {
3919
3948
  if (reqData["Expand"]) {
3920
3949
  reqData["Expand"] += `,${expandStr}`;
@@ -3926,33 +3955,38 @@ var Entity;
3926
3955
  if (expandLODs) {
3927
3956
  reqData["LODType"] = "*";
3928
3957
  }
3929
- if (expandSources) {
3930
- reqData["ExpandSources"] = true;
3931
- }
3932
3958
  if (historicKey) {
3933
- reqData["historicKey"] = historicKey;
3959
+ reqData["HistoricKey"] = historicKey;
3934
3960
  }
3935
3961
  if (historicFrom) {
3936
- reqData["historicFrom"] = historicFrom;
3962
+ reqData["HistoricFrom"] = historicFrom;
3937
3963
  }
3938
3964
  if (historicTo) {
3939
- reqData["historicTo"] = historicTo;
3965
+ reqData["HistoricTo"] = historicTo;
3940
3966
  }
3941
3967
  if (historicPoint) {
3942
- reqData["historicPoint"] = historicPoint;
3968
+ reqData["HistoricPoint"] = historicPoint;
3943
3969
  }
3944
3970
  if (scenario) {
3945
3971
  reqData["Scenario"] = scenario;
3946
3972
  }
3947
3973
  const urlParams = new URLSearchParams();
3948
3974
  if (schemaId) {
3949
- urlParams.set("schema", schemaId);
3975
+ urlParams.set("Schema", schemaId);
3950
3976
  }
3951
3977
  if (maxSearchTimeSec) {
3952
3978
  urlParams.set("MaxSearchTimeSec", String(Math.ceil(maxSearchTimeSec)));
3953
3979
  }
3954
- urlParams.set("hasMigrated", String(Boolean(migrated)));
3955
- const url = `entities?${urlParams.toString()}`;
3980
+ let url = null;
3981
+ // v3 endpoint.
3982
+ if (migrated) {
3983
+ url = `v3/getEntities?${urlParams.toString()}`;
3984
+ }
3985
+ // v1 endpoint.
3986
+ else {
3987
+ urlParams.set("hasMigrated", "false");
3988
+ url = `entities?${urlParams.toString()}`;
3989
+ }
3956
3990
  const reqs = [];
3957
3991
  if (reqIds.length > 0) {
3958
3992
  const req = api.POST(url, reqData, Api.PrepReqParams(reqParams));
@@ -4013,7 +4047,7 @@ var Entity;
4013
4047
  if (!api) {
4014
4048
  api = ENVIRONMENT.Api().GetBruceApi();
4015
4049
  }
4016
- yield api.DELETE(`entity/${entityId}`, Api.PrepReqParams(reqParams));
4050
+ yield api.DELETE(`v3/entity/${entityId}`, Api.PrepReqParams(reqParams));
4017
4051
  api.Cache.RemoveByContains(GetContainsKey(entityId));
4018
4052
  EntityHistoricData.ClearCacheByEntityIds(api, [entityId]);
4019
4053
  });
@@ -4032,7 +4066,7 @@ var Entity;
4032
4066
  if (!api) {
4033
4067
  api = ENVIRONMENT.Api().GetBruceApi();
4034
4068
  }
4035
- yield api.POST("deleteEntities", {
4069
+ yield api.POST("v3/deleteEntities", {
4036
4070
  Items: entityIds
4037
4071
  }, Api.PrepReqParams(reqParams));
4038
4072
  for (let i = 0; i < entityIds.length; i++) {
@@ -4049,18 +4083,20 @@ var Entity;
4049
4083
  * @returns
4050
4084
  */
4051
4085
  function Update(params) {
4052
- var _a, _b, _c, _d, _e;
4086
+ var _a, _b, _c, _d, _e, _f, _g;
4053
4087
  return __awaiter(this, void 0, void 0, function* () {
4054
4088
  let { api, entity: data, entities, override, req: reqParams, migrated } = params;
4055
4089
  if (migrated == null || migrated == undefined) {
4056
4090
  // Changed to default = true. 18th April 2025.
4057
4091
  migrated = true;
4058
4092
  }
4059
- // Bulk save.
4093
+ // Bulk save. Always using a v3 endpoint as v1 did not have a bulk save.
4060
4094
  if (entities === null || entities === void 0 ? void 0 : entities.length) {
4061
4095
  // If the Entities don't have IDs, then they must have a Type ID.
4062
4096
  for (let i = 0; i < entities.length; i++) {
4063
4097
  const entity = entities[i];
4098
+ // If ID is missing then we can assume we're making a new record.
4099
+ // This means a type ID must be supplied.
4064
4100
  if (!((_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID) && !((_b = entity.Bruce) === null || _b === void 0 ? void 0 : _b["EntityType.ID"])) {
4065
4101
  throw ("Entity Type ID is required for new Entity records.");
4066
4102
  }
@@ -4090,18 +4126,43 @@ var Entity;
4090
4126
  if (!data && (entities === null || entities === void 0 ? void 0 : entities.length)) {
4091
4127
  data = entities[0];
4092
4128
  }
4093
- if (!((_d = data === null || data === void 0 ? void 0 : data.Bruce) === null || _d === void 0 ? void 0 : _d["EntityType.ID"])) {
4094
- throw ("Entity Type ID is required.");
4129
+ // If ID is missing then we can assume we're making a new record.
4130
+ // This means a type ID must be supplied.
4131
+ 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)) {
4132
+ throw ("Entity Type ID is required for new records.");
4095
4133
  }
4096
4134
  if (!api) {
4097
4135
  api = ENVIRONMENT.Api().GetBruceApi();
4098
4136
  }
4099
- if (!((_e = data === null || data === void 0 ? void 0 : data.Bruce) === null || _e === void 0 ? void 0 : _e.ID)) {
4100
- data.Bruce = Object.assign(Object.assign({}, data.Bruce), { ID: ObjectUtils.UId() });
4137
+ /*
4138
+ Getting the API to always generate IDs when UI hasn't pre-generated them :)
4139
+ if (!data?.Bruce?.ID) {
4140
+ data.Bruce = {
4141
+ ...data.Bruce,
4142
+ ID: ObjectUtils.UId()
4143
+ };
4144
+ }
4145
+ */
4146
+ const entityId = (_f = data.Bruce) === null || _f === void 0 ? void 0 : _f.ID;
4147
+ const typeId = (_g = data.Bruce) === null || _g === void 0 ? void 0 : _g["EntityType.ID"];
4148
+ let reqUrl = null;
4149
+ // Create or update.
4150
+ // Though API also looks for ID in body...
4151
+ if (entityId) {
4152
+ reqUrl = migrated ? `v3/entity/${data.Bruce.ID}` : `entity/${data.Bruce.ID}`;
4101
4153
  }
4102
- let reqUrl = `entity/${data.Bruce.ID}/?dataoverride=${override}&BruceEntityType=${data.Bruce["EntityType.ID"]}`;
4103
- if (migrated) {
4104
- reqUrl += "&hasMigrated=true";
4154
+ else {
4155
+ reqUrl = migrated ? "v3/entity" : "entity";
4156
+ }
4157
+ // Override = Are we doing an update or replace?
4158
+ reqUrl += `?Override=${override}`;
4159
+ // Updating through a known type.
4160
+ if (typeId) {
4161
+ reqUrl += `&Type=${data.Bruce["EntityType.ID"]}`;
4162
+ }
4163
+ // Explicit in case API changes default logic for v1 endpoint.
4164
+ if (!migrated) {
4165
+ reqUrl += "&hasMigrated=false";
4105
4166
  }
4106
4167
  const res = yield api.POST(reqUrl, data, Api.PrepReqParams(reqParams));
4107
4168
  api.Cache.RemoveByContains(GetContainsKey(data.Bruce.ID));
@@ -4433,18 +4494,17 @@ var Entity;
4433
4494
  OrderBy: filter.orderBy,
4434
4495
  Filter: requestFilter,
4435
4496
  LODType: filter.lodCategoryId,
4436
- BruceEntityType: (!filter.entityTypeId ? null : filter.entityTypeId),
4497
+ Type: (!filter.entityTypeId ? null : filter.entityTypeId),
4437
4498
  PageIndex: filter.pageIndex,
4438
4499
  PageSize: filter.pageSize,
4439
- historicKey: historicKey,
4440
- historicFrom: historicFrom,
4441
- historicTo: historicTo,
4442
- historicPoint: historicPoint,
4443
- ExpandSources: expandSources,
4500
+ HistoricKey: historicKey,
4501
+ HistoricFrom: historicFrom,
4502
+ HistoricTo: historicTo,
4503
+ HistoricPoint: historicPoint,
4444
4504
  Scenario: scenario
4445
4505
  };
4446
- if (expandLocation || expandRelations || expandImports || expandEntityType || expandComments || expandStr || expandAttachments) {
4447
- let expand = "";
4506
+ let expand = "";
4507
+ {
4448
4508
  if (expandLocation) {
4449
4509
  expand += "location";
4450
4510
  }
@@ -4464,7 +4524,7 @@ var Entity;
4464
4524
  if (expand) {
4465
4525
  expand += ",";
4466
4526
  }
4467
- expand += "EntityType";
4527
+ expand += "entityType";
4468
4528
  }
4469
4529
  if (expandComments) {
4470
4530
  if (expand) {
@@ -4478,15 +4538,21 @@ var Entity;
4478
4538
  }
4479
4539
  expand += "attachment";
4480
4540
  }
4541
+ if (expandSources) {
4542
+ if (expand) {
4543
+ expand += ",";
4544
+ }
4545
+ expand += "source";
4546
+ }
4481
4547
  if (expandStr) {
4482
4548
  if (expand) {
4483
4549
  expand += ",";
4484
4550
  }
4485
4551
  expand += expandStr;
4486
4552
  }
4487
- if (expand) {
4488
- body["Expand"] = expand;
4489
- }
4553
+ }
4554
+ if (expand) {
4555
+ body["Expand"] = expand;
4490
4556
  }
4491
4557
  let totalCount;
4492
4558
  let entities = [];
@@ -4511,8 +4577,8 @@ var Entity;
4511
4577
  if (body.LODType) {
4512
4578
  urlParams.set("LODType", body.LODType);
4513
4579
  }
4514
- if (body.BruceEntityType) {
4515
- urlParams.set("BruceEntityType", typeof body.BruceEntityType == "string" ? body.BruceEntityType : body.BruceEntityType.join(","));
4580
+ if (body.Type) {
4581
+ urlParams.set("Type", typeof body.Type == "string" ? body.Type : body.Type.join(","));
4516
4582
  }
4517
4583
  if (body.PageIndex) {
4518
4584
  urlParams.set("PageIndex", String(body.PageIndex));
@@ -4520,72 +4586,23 @@ var Entity;
4520
4586
  if (body.PageSize) {
4521
4587
  urlParams.set("PageSize", String(body.PageSize));
4522
4588
  }
4523
- let expand = "";
4524
- if (expandRelations) {
4525
- if (expand.length) {
4526
- expand += ",";
4527
- }
4528
- expand += "Relation";
4529
- }
4530
- if (expandLocation) {
4531
- if (expand.length) {
4532
- expand += ",";
4533
- }
4534
- expand += "Location";
4535
- }
4536
- if (expandImports) {
4537
- if (expand.length) {
4538
- expand += ",";
4539
- }
4540
- expand += "Import";
4541
- }
4542
- if (expandSources) {
4543
- if (expand.length) {
4544
- expand += ",";
4545
- }
4546
- expand += "Source";
4547
- }
4548
- if (expandEntityType) {
4549
- if (expand.length) {
4550
- expand += ",";
4551
- }
4552
- expand += "EntityType";
4553
- }
4554
- if (expandComments) {
4555
- if (expand.length) {
4556
- expand += ",";
4557
- }
4558
- expand += "Comment";
4559
- }
4560
- if (expandAttachments) {
4561
- if (expand.length) {
4562
- expand += ",";
4563
- }
4564
- expand += "Attachment";
4565
- }
4566
- if (expandStr) {
4567
- if (expand.length) {
4568
- expand += ",";
4569
- }
4570
- expand += expandStr;
4571
- }
4572
- if (expand.length) {
4589
+ if (expand === null || expand === void 0 ? void 0 : expand.length) {
4573
4590
  urlParams.append("Expand", expand);
4574
4591
  }
4575
4592
  if (historicKey) {
4576
- urlParams.set("historicKey", historicKey);
4593
+ urlParams.set("HistoricKey", historicKey);
4577
4594
  }
4578
4595
  if (historicFrom) {
4579
- urlParams.set("historicFrom", historicFrom);
4596
+ urlParams.set("HistoricFrom", historicFrom);
4580
4597
  }
4581
4598
  if (historicTo) {
4582
- urlParams.set("historicTo", historicTo);
4599
+ urlParams.set("HistoricTo", historicTo);
4583
4600
  }
4584
4601
  if (historicPoint) {
4585
- urlParams.set("historicPoint", historicPoint);
4602
+ urlParams.set("HistoricPoint", historicPoint);
4586
4603
  }
4587
4604
  if (schemaId) {
4588
- urlParams.set("schema", schemaId);
4605
+ urlParams.set("Schema", schemaId);
4589
4606
  }
4590
4607
  if (scenario && String(scenario) != "0") {
4591
4608
  urlParams.set("Scenario", String(scenario));
@@ -4593,8 +4610,22 @@ var Entity;
4593
4610
  if (maxSearchTimeSec) {
4594
4611
  urlParams.set("MaxSearchTimeSec", String(Math.ceil(maxSearchTimeSec)));
4595
4612
  }
4596
- urlParams.set("hasMigrated", String(Boolean(migrated)));
4597
- let url = analysis ? "entities/summary" : "entities";
4613
+ let url = null;
4614
+ // v3 endpoint.
4615
+ if (migrated) {
4616
+ url = analysis ? "v3/entities" : "v3/entities";
4617
+ if (analysis) {
4618
+ urlParams.delete("PageIndex");
4619
+ urlParams.delete("PageSize");
4620
+ urlParams.append("PageIndex", "-1");
4621
+ urlParams.append("PageSize", "-1");
4622
+ }
4623
+ }
4624
+ // v1 endpoint.
4625
+ else {
4626
+ urlParams.set("hasMigrated", "false");
4627
+ url = analysis ? "entities/summary" : "entities";
4628
+ }
4598
4629
  url += "?" + urlParams.toString();
4599
4630
  const urlStr = api.ConstructUrl({
4600
4631
  cdn: !analysis && viaCdn,
@@ -4614,56 +4645,7 @@ var Entity;
4614
4645
  }
4615
4646
  else {
4616
4647
  const urlParams = new URLSearchParams();
4617
- let expand = "";
4618
- if (expandRelations) {
4619
- if (expand.length) {
4620
- expand += ",";
4621
- }
4622
- expand += "Relation";
4623
- }
4624
- if (expandLocation) {
4625
- if (expand.length) {
4626
- expand += ",";
4627
- }
4628
- expand += "Location";
4629
- }
4630
- if (expandImports) {
4631
- if (expand.length) {
4632
- expand += ",";
4633
- }
4634
- expand += "Import";
4635
- }
4636
- if (expandSources) {
4637
- if (expand.length) {
4638
- expand += ",";
4639
- }
4640
- expand += "Source";
4641
- }
4642
- if (expandEntityType) {
4643
- if (expand.length) {
4644
- expand += ",";
4645
- }
4646
- expand += "EntityType";
4647
- }
4648
- if (expandComments) {
4649
- if (expand.length) {
4650
- expand += ",";
4651
- }
4652
- expand += "Comment";
4653
- }
4654
- if (expandAttachments) {
4655
- if (expand.length) {
4656
- expand += ",";
4657
- }
4658
- expand += "Attachment";
4659
- }
4660
- if (expandStr) {
4661
- if (expand.length) {
4662
- expand += ",";
4663
- }
4664
- expand += expandStr;
4665
- }
4666
- if (expand.length) {
4648
+ if (expand === null || expand === void 0 ? void 0 : expand.length) {
4667
4649
  urlParams.append("Expand", expand);
4668
4650
  }
4669
4651
  if (schemaId) {
@@ -4672,8 +4654,20 @@ var Entity;
4672
4654
  if (maxSearchTimeSec) {
4673
4655
  urlParams.set("MaxSearchTimeSec", String(Math.ceil(maxSearchTimeSec)));
4674
4656
  }
4675
- urlParams.set("hasMigrated", String(Boolean(migrated)));
4676
- let url = analysis ? "entities/summary" : "entities";
4657
+ let url = null;
4658
+ // v3 endpoint.
4659
+ if (migrated) {
4660
+ url = "v3/getEntities";
4661
+ if (analysis) {
4662
+ body.PageIndex = -1;
4663
+ body.PageSize = -1;
4664
+ }
4665
+ }
4666
+ // v1 endpoint.
4667
+ else {
4668
+ url = analysis ? "entities/summary" : "entities";
4669
+ urlParams.set("hasMigrated", "false");
4670
+ }
4677
4671
  // Adding url params here because this will avoid making them encoded.
4678
4672
  // Our API isn't decoding them properly so $expand is not being recognized.
4679
4673
  url += "?" + urlParams.toString();
@@ -17036,7 +17030,7 @@ class NavigatorMcpWebSocketClient {
17036
17030
  }
17037
17031
 
17038
17032
  // This is updated with the package.json version on build.
17039
- const VERSION = "7.0.6";
17033
+ const VERSION = "7.0.8";
17040
17034
 
17041
17035
  export { VERSION, Assembly, AnnDocument, CustomForm, AbstractApi, Api, BruceApi, GlobalApi, GuardianApi, ApiGetters, Calculator, Bounds, BruceEvent, CacheControl, Camera, Cartes, Carto, Color, DelayQueue, Geometry, UTC, BruceVariable, LRUCache, GeoJson, EntityAttachmentType, EntityAttachment, EntityComment, EntityLink, EntityLod, EntityLodCategory, EntityRelationType, EntityRelation, EntitySource, EntityTag, EntityType, Entity, EntityCoords, EntityAttribute, EntityHistoricData, EntityTableView, Comment, ClientFile, ProgramKey, ZoomControl, MenuItem, ProjectViewBookmark, ProjectView, ProjectViewLegacyTile, ProjectViewTile, ProjectViewLegacy, ProjectViewLegacyBookmark, ProjectViewBookmarkGroup, PendingAction, MessageBroker, HostingLocation, Style, Tileset, Permission, Session, UserGroup, User, UserMfaMethod, Account, AccountInvite, AccountFeatures, AccountLimits, AccountTemplate, AccountType, EncryptUtils, MathUtils, ObjectUtils, PathUtils, UrlUtils, DataLab, DataLabGroup, ImportAssembly, ImportCad, ImportCsv, ImportJson, ImportGeoJson, ImportKml, ImportedFile, ExportBrz, ExportUsd, Markup, Uploader, Plugin, ENVIRONMENT, DataSource, Scenario, Tracking, NavigatorChatClient, NavigatorMcpWebSocketClient };
17042
17036
  //# sourceMappingURL=bruce-models.es5.js.map