bruce-models 7.0.7 → 7.0.8

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