Skip to content

Commit

Permalink
Merge pull request #1518 from Esri/portal-subtypes
Browse files Browse the repository at this point in the history
portal check for subtypes and add indexes logic
  • Loading branch information
jmhauck authored Jan 9, 2025
2 parents 99065d7 + 69f1a32 commit ce0cbb1
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 14 deletions.
43 changes: 37 additions & 6 deletions packages/common/src/featureServiceHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export function deleteViewProps(layer: any) {
* @param isView When true the current layer is a view and does not need to cache subtype details
* @returns An updated instance of the fieldInfos
*/
export function cacheFieldInfos(layer: any, fieldInfos: any, isView: boolean): any {
export function cacheFieldInfos(layer: any, fieldInfos: any, isView: boolean, isPortal: boolean): any {
// cache the source fields as they are in the original source
if (layer && layer.fields) {
fieldInfos[layer.id] = {
Expand All @@ -228,7 +228,7 @@ export function cacheFieldInfos(layer: any, fieldInfos: any, isView: boolean): a
id: layer.id,
};
/* istanbul ignore else */
if (!isView) {
if (!isView && isPortal) {
fieldInfos[layer.id].subtypes = layer.subtypes;
fieldInfos[layer.id].subtypeField = layer.subtypeField;
fieldInfos[layer.id].defaultSubtypeCode = layer.defaultSubtypeCode;
Expand All @@ -252,7 +252,7 @@ export function cacheFieldInfos(layer: any, fieldInfos: any, isView: boolean): a
};

/* istanbul ignore else */
if (!isView) {
if (!isView && isPortal) {
props["subtypes"] = true;
props["subtypeField"] = true;
props["defaultSubtypeCode"] = true;
Expand Down Expand Up @@ -281,6 +281,31 @@ export function cacheContingentValues(id: string, fieldInfos: any, itemTemplate:
return fieldInfos;
}

/**
* Cache the stored contingent values so we can add them in subsequent addToDef calls
*
* @param layer The current layer to check indexes on
* @param fieldInfos The object that stores the cached field infos
* @returns An updated instance of the fieldInfos
*/
export function cacheIndexes(layer: any, fieldInfos: any): any {
/* istanbul ignore else */
if (Array.isArray(layer.indexes)) {
const oidField = layer.objectIdField;
const guidField = layer.globalIdField;
fieldInfos[layer.id].indexes = layer.indexes.filter((i) => {
if ((i.isUnique && i.fields !== oidField && i.fields !== guidField) || i.indexType === "FullText") {
if (i.name) {
i.name = i.name.replaceAll(" ", "");
}
return i;
}
});
delete layer.indexes;
}
return fieldInfos;
}

/**
* Helper function to cache a single property into the fieldInfos object
* This property will be removed from the layer instance.
Expand Down Expand Up @@ -825,7 +850,7 @@ export function addFeatureServiceLayersAndTables(
updates
.reduce((prev, update) => {
return prev.then(() => {
return getRequest(update);
return getRequest(update, false, false, templateDictionary.isPortal);
});
}, Promise.resolve(null))
.then(
Expand Down Expand Up @@ -895,11 +920,17 @@ export function addFeatureServiceDefinition(
let item = toAdd.item;
const originalId = item.id;
const isView = itemTemplate.properties.service.isView;
fieldInfos = cacheFieldInfos(item, fieldInfos, isView);
const isPortal = templateDictionary.isPortal;
fieldInfos = cacheFieldInfos(item, fieldInfos, isView, isPortal);

// cache the values to be added in seperate addToDef calls
fieldInfos = cacheContingentValues(item.id, fieldInfos, itemTemplate);

// cache specific field indexes when deploying to ArcGIS Enterprise portal
if (isPortal) {
fieldInfos = cacheIndexes(item, fieldInfos);
}

/* istanbul ignore else */
if (item.isView) {
deleteViewProps(item);
Expand Down Expand Up @@ -929,7 +960,7 @@ export function addFeatureServiceDefinition(
}
}
/* istanbul ignore else */
if (templateDictionary.isPortal) {
if (isPortal) {
item = _updateForPortal(item, itemTemplate, templateDictionary);
}

Expand Down
39 changes: 36 additions & 3 deletions packages/common/src/restHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ export function getLayerUpdates(args: IPostProcessArgs, isPortal: boolean): IUpd
});

/* istanbul ignore else */
if (subtypeUpdates.length > 0) {
if (subtypeUpdates.length > 0 && isPortal) {
subtypeUpdates.forEach((subtypeUpdate) => {
updates.push(
_getUpdate(adminUrl + subtypeUpdate.id, null, { subtypeField: subtypeUpdate.subtypeField }, args, "update"),
Expand Down Expand Up @@ -1013,6 +1013,34 @@ export function getLayerUpdates(args: IPostProcessArgs, isPortal: boolean): IUpd
});
}
}

// issue: https://devtopia.esri.com/WebGIS/solution-deployment-apps/issues/273
// For portal only...add specific indexes with existing supplementary addToDefinition call if it exists
// or with a new addToDefinition call if one doesn't already exist
if (isPortal) {
Object.keys(args.objects).forEach((id) => {
const obj: any = Object.assign({}, args.objects[id]);
let update;
if (Array.isArray(obj.indexes) && obj.indexes.length > 0) {
const layerHasExistingAdd = updates.some((u) => {
if (u.url.indexOf(`${id}/addToDefinition`) > -1) {
update = u;
return true;
}
});
if (layerHasExistingAdd) {
// append to existing addToDef
update.params.addToDefinition = {
...update.params.addToDefinition,
indexes: obj.indexes,
};
} else {
// create new addToDef
updates.push(_getUpdate(checkUrlPathTermination(adminUrl) + id, null, { indexes: obj.indexes }, args, "add"));
}
}
});
}
return updates.length === 1 ? [] : updates;
}

Expand Down Expand Up @@ -1101,7 +1129,12 @@ export function _sortRelationships(layers: any[], tables: any[], relUpdates: any
* @private
*/
/* istanbul ignore else */
export function getRequest(update: IUpdate, skipRetry: boolean = false, useAsync: boolean = false): Promise<void> {
export function getRequest(
update: IUpdate,
skipRetry: boolean = false,
useAsync: boolean = false,
isPortal: boolean = false,
): Promise<void> {
return new Promise((resolve, reject) => {
const options: IRequestOptions = {
params: update.params,
Expand All @@ -1124,7 +1157,7 @@ export function getRequest(update: IUpdate, skipRetry: boolean = false, useAsync
},
(e: any) => {
if (!skipRetry) {
getRequest(update, true, true).then(
getRequest(update, true, true, isPortal).then(
() => resolve(),
(e) => reject(e),
);
Expand Down
53 changes: 49 additions & 4 deletions packages/common/test/featureServiceHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/

import {
cacheIndexes,
getFeatureServiceRelatedRecords,
templatize,
deleteViewProps,
Expand Down Expand Up @@ -556,15 +557,15 @@ describe("Module `featureServiceHelpers`: utility functions for feature-service
it("should not fail with undefined", () => {
let fieldInfos: any = {};
const layer: any = undefined;
fieldInfos = cacheFieldInfos(layer, fieldInfos, true);
fieldInfos = cacheFieldInfos(layer, fieldInfos, true, false);
expect(layer).toBeUndefined();
expect(fieldInfos).toEqual({});
});

it("should not fail without key properties on the layer", () => {
let fieldInfos: any = {};
const layer: any = {};
fieldInfos = cacheFieldInfos(layer, fieldInfos, false);
fieldInfos = cacheFieldInfos(layer, fieldInfos, false, false);
expect(layer).toEqual({});
expect(fieldInfos).toEqual({});
});
Expand Down Expand Up @@ -676,12 +677,56 @@ describe("Module `featureServiceHelpers`: utility functions for feature-service
},
};

fieldInfos = cacheFieldInfos(layer, fieldInfos, false);
fieldInfos = cacheFieldInfos(layer, fieldInfos, false, true);
expect(layer).toEqual(expectedLayer);
expect(fieldInfos).toEqual(expectedFieldInfos);
});
});

describe("cacheIndexes", () => {
it("should cache specific indexes and remove them from the layer", () => {
const layer = {
id: "0",
objectIdField: "objectid",
globalIdField: "globalid",
indexes: [
{
isUnique: true,
fields: "B",
indexType: "",
name: "B_Unique",
},
{
isUnique: true,
fields: "objectid",
indexType: "",
name: "C_objectid",
},
{
isUnique: false,
fields: "A",
indexType: "FullText",
name: "A _ FullText",
},
],
} as any;

const id = "0";
let fieldInfos: any = {};
fieldInfos[id] = {};
fieldInfos = cacheIndexes(layer, fieldInfos);

const expectedLayer = {
id: "0",
objectIdField: "objectid",
globalIdField: "globalid",
};
expect(layer).toEqual(expectedLayer);
expect(fieldInfos["0"].indexes.length).toEqual(2);
expect(fieldInfos["0"].indexes[1].name).toEqual("A_FullText");
});
});

describe("cacheContingentValues", () => {
it("should get contingent values from feature service properties", () => {
const id = "0";
Expand Down Expand Up @@ -3607,7 +3652,7 @@ describe("Module `featureServiceHelpers`: utility functions for feature-service
const layer1 = mockItems.getAGOLLayerOrTable(1, "ROW Permit Comment", "Table", [
mockItems.createAGOLRelationship(0, 1, "esriRelRoleDestination"),
]);
const fieldInfos = cacheFieldInfos(layer1, cacheFieldInfos(layer0, {}, false), false);
const fieldInfos = cacheFieldInfos(layer1, cacheFieldInfos(layer0, {}, false, false), false, false);

Object.keys(fieldInfos).forEach((k) => {
fieldInfos[k].sourceFields[1].visible = false;
Expand Down
19 changes: 18 additions & 1 deletion packages/common/test/restHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,13 @@ describe("Module `restHelpers`: common REST utility functions shared across pack
subtypeField: "SubtypeField",
defaultSubtypeCode: "0",
subtypes: [{ a: "A" }],
indexes: [{ name: "index" }],
},
1: {
b: "b",
type: "B",
id: 1,
indexes: [{ name: "index2" }],
},
};

Expand All @@ -1940,7 +1947,7 @@ describe("Module `restHelpers`: common REST utility functions shared across pack
authentication: MOCK_USER_SESSION,
};

const updates: any[] = restHelpers.getLayerUpdates(args, false);
const updates: any[] = restHelpers.getLayerUpdates(args, true);

const _object: any = Object.assign({}, objects[0]);
delete _object.type;
Expand Down Expand Up @@ -1995,6 +2002,7 @@ describe("Module `restHelpers`: common REST utility functions shared across pack
params: {
addToDefinition: {
subtypes: [{ a: "A" }],
indexes: [{ name: "index" }]
},
},
args,
Expand Down Expand Up @@ -2029,6 +2037,15 @@ describe("Module `restHelpers`: common REST utility functions shared across pack
},
args,
},
{
url: adminUrl + "1/addToDefinition",
params: {
addToDefinition: {
indexes: [{ name: "index2" }]
},
},
args,
},
];
expect(updates).toEqual(expected);
});
Expand Down

0 comments on commit ce0cbb1

Please sign in to comment.