Skip to content

Commit

Permalink
[RND-623] fix reference collection issue
Browse files Browse the repository at this point in the history
  • Loading branch information
bradbanister committed Oct 11, 2023
1 parent f679d95 commit 411c3c6
Show file tree
Hide file tree
Showing 2 changed files with 516 additions and 343 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,54 @@
// Licensed to the Ed-Fi Alliance under one or more agreements.
// The Ed-Fi Alliance licenses this file to you under the Apache License, Version 2.0.
// See the LICENSE and NOTICES files in the project root for more information.
import invariant from 'ts-invariant';
import { JSONPath as jsonPath } from 'jsonpath-plus';
import { DocumentIdentity } from '../model/DocumentIdentity';
import { DocumentReference } from '../model/DocumentReference';
import { DocumentObjectKey } from '../model/api-schema/DocumentObjectKey';
import { DocumentPaths } from '../model/api-schema/DocumentPaths';
import { JsonPath } from '../model/api-schema/JsonPath';
import { ResourceSchema } from '../model/api-schema/ResourceSchema';
import { DocumentIdentity } from '../model/DocumentIdentity';

/**
* In extracting DocumentReferences, there is an intermediate step where document values are resolved
* from a JsonPath. JsonPaths return arrays of values when the path goes into an array.
* This is the case for collections of document references.
*
* This means that each path resolves to one document value in *each* document reference in the collection.
* For each DocumentObjectKey of a reference, IntermediateDocumentReferences holds the array of resolved document values
* for a path.
*
* For example, given a document with a collection of ClassPeriod references:
*
* classPeriods: [
* {
* classPeriodReference: {
* schoolId: '24',
* classPeriodName: 'z1',
* },
* },
* {
* classPeriodReference: {
* schoolId: '25',
* classPeriodName: 'z2',
* },
* },
* ]
*
* With JsonPaths for ClassPeriod references:
* "* $.classPeriods[*].classPeriodReference.schoolId" for schoolId and
* "$.classPeriods[*].classPeriodReference.classPeriodName" for classPeriodName,
* the IntermediateDocumentReferences would be:
*
* {
* schoolId: ['24', '25'],
* classPeriodName: ['z1', 'z2']
* }
*
* IntermediateDocumentReferences here contains information for two DocumentReferences, but as "slices" in the wrong
* orientation.
*/
type IntermediateDocumentReferences = { [key: DocumentObjectKey]: any[] };

/**
* Takes a resource schema and an API document for that resource and
Expand All @@ -24,24 +65,55 @@ export function extractDocumentReferences(resourceSchema: ResourceSchema, docume
// Only applies to non-descriptor references
if (documentPaths.isDescriptor) return;

const documentIdentity: DocumentIdentity = [];
// Build up documentIdentity in order
documentPaths.pathOrder.forEach((documentKey: DocumentObjectKey) => {
const documentJsonPath: JsonPath = documentPaths.paths[documentKey];
const documentValue: any = jsonPath({
// Build up intermediateDocumentReferences
const intermediateDocumentReferences: IntermediateDocumentReferences = {};
Object.entries(documentPaths.paths).forEach(([documentKey, documentJsonPath]) => {
const documentValuesSlice: any[] = jsonPath({
path: documentJsonPath,
json: documentBody,
flatten: true,
});
documentIdentity.push({ documentKey, documentValue });
});

result.push({
documentIdentity,
isDescriptor: documentPaths.isDescriptor,
projectName: documentPaths.projectName,
resourceName: documentPaths.resourceName,
invariant(
Array.isArray(documentValuesSlice),
`JsonPath ${documentJsonPath} should have returned an array but instead was ${documentValuesSlice}`,
);

// Path can be empty if reference is optional
if (documentValuesSlice.length === 0) return;

intermediateDocumentReferences[documentKey] = documentValuesSlice;
});

const documentValuesSlices = Object.values(intermediateDocumentReferences);

// Empty if reference is optional and no values
if (documentValuesSlices.length === 0) return;

// Number of document values from resolved JsonPaths should all be the same, otherwise something is very wrong
invariant(
documentValuesSlices.every(
(documentValuesSlice) => documentValuesSlice.length === documentValuesSlices[0].length,
`Length of document value slices are not equal`,
),
);

// Reorient intermediateDocumentReferences into actual references
for (let index = 0; index < documentValuesSlices[0].length; index += 1) {
const documentIdentity: DocumentIdentity = [];

// Build the document identity in the correct path order
documentPaths.pathOrder.forEach((documentKey: DocumentObjectKey) => {
documentIdentity.push({ documentKey, documentValue: intermediateDocumentReferences[documentKey][index] });
});

result.push({
documentIdentity,
isDescriptor: documentPaths.isDescriptor,
projectName: documentPaths.projectName,
resourceName: documentPaths.resourceName,
});
}
});

return result;
Expand Down
Loading

0 comments on commit 411c3c6

Please sign in to comment.