@finos/legend-graph
Version:
Legend graph and graph manager
1,196 lines (1,097 loc) • 44.2 kB
text/typescript
/**
* Copyright (c) 2020-present, Goldman Sachs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
createModelSchema,
primitive,
serialize,
SKIP,
list,
custom,
deserialize,
optional,
type ModelSchema,
} from 'serializr';
import {
type PlainObject,
usingConstantValueSchema,
UnsupportedOperationError,
usingModelSchema,
guaranteeIsString,
isString,
isPlainObject,
optionalCustom,
} from '@finos/legend-shared';
import { V1_Variable } from '../../../model/valueSpecification/V1_Variable.js';
import { V1_RootGraphFetchTree } from '../../../model/valueSpecification/raw/classInstance/graph/V1_RootGraphFetchTree.js';
import { V1_Lambda } from '../../../model/valueSpecification/raw/V1_Lambda.js';
import { V1_EnumValue } from '../../../model/valueSpecification/raw/V1_EnumValue.js';
import { V1_Path } from '../../../model/valueSpecification/raw/classInstance/path/V1_Path.js';
import { V1_AppliedFunction } from '../../../model/valueSpecification/application/V1_AppliedFunction.js';
import { V1_Collection } from '../../../model/valueSpecification/raw/V1_Collection.js';
import { V1_CDecimal } from '../../../model/valueSpecification/raw/V1_CDecimal.js';
import { V1_CInteger } from '../../../model/valueSpecification/raw/V1_CInteger.js';
import { V1_CString } from '../../../model/valueSpecification/raw/V1_CString.js';
import { V1_CFloat } from '../../../model/valueSpecification/raw/V1_CFloat.js';
import { V1_CDateTime } from '../../../model/valueSpecification/raw/V1_CDateTime.js';
import { V1_CStrictDate } from '../../../model/valueSpecification/raw/V1_CStrictDate.js';
import { V1_CStrictTime } from '../../../model/valueSpecification/raw/V1_CStrictTime.js';
import { V1_CLatestDate } from '../../../model/valueSpecification/raw/V1_CLatestDate.js';
import { V1_CBoolean } from '../../../model/valueSpecification/raw/V1_CBoolean.js';
import { V1_AggregateValue } from '../../../model/valueSpecification/raw/classInstance/V1_AggregateValue.js';
import { V1_Pair } from '../../../model/valueSpecification/raw/classInstance/V1_Pair.js';
import { V1_RuntimeInstance } from '../../../model/valueSpecification/raw/classInstance/V1_RuntimeInstance.js';
import { V1_ExecutionContextInstance } from '../../../model/valueSpecification/raw/classInstance/V1_ExecutionContextInstance.js';
import { V1_PropertyGraphFetchTree } from '../../../model/valueSpecification/raw/classInstance/graph/V1_PropertyGraphFetchTree.js';
import { V1_SubTypeGraphFetchTree } from '../../../model/valueSpecification/raw/classInstance/graph/V1_SubTypeGraphFetchTree.js';
import { V1_SerializationConfig } from '../../../model/valueSpecification/raw/classInstance/V1_SerializationConfig.js';
import { V1_KeyExpression } from '../../../model/valueSpecification/raw/V1_KeyExpression.js';
import { V1_PureList } from '../../../model/valueSpecification/raw/classInstance/V1_PureList.js';
import { V1_TDSAggregateValue } from '../../../model/valueSpecification/raw/classInstance/V1_TDSAggregateValue.js';
import { V1_TDSColumnInformation } from '../../../model/valueSpecification/raw/classInstance/V1_TDSColumnInformation.js';
import { V1_TDSSortInformation } from '../../../model/valueSpecification/raw/classInstance/V1_TDSSortInformation.js';
import { V1_TDSOlapRank } from '../../../model/valueSpecification/raw/classInstance/V1_TDSOlapRank.js';
import { V1_TDSOlapAggregation } from '../../../model/valueSpecification/raw/classInstance/V1_TDSOlapAggregation.js';
import { V1_ColSpecArray } from '../../../model/valueSpecification/raw/classInstance/relation/V1_ColSpecArray.js';
import { V1_ColSpec } from '../../../model/valueSpecification/raw/classInstance/relation/V1_ColSpec.js';
import { V1_RelationStoreAccessor } from '../../../model/valueSpecification/raw/classInstance/relation/V1_RelationStoreAccessor.js';
import { V1_multiplicityModelSchema } from './V1_CoreSerializationHelper.js';
import type {
V1_ValueSpecification,
V1_ValueSpecificationVisitor,
} from '../../../model/valueSpecification/V1_ValueSpecification.js';
import { V1_PropertyPathElement } from '../../../model/valueSpecification/raw/classInstance/path/V1_PropertyPathElement.js';
import type { V1_PathElement } from '../../../model/valueSpecification/raw/classInstance/path/V1_PathElement.js';
import { V1_AppliedProperty } from '../../../model/valueSpecification/application/V1_AppliedProperty.js';
import { V1_serializeRuntime } from './V1_RuntimeSerializationHelper.js';
import type { V1_ExecutionContext } from '../../../model/valueSpecification/raw/executionContext/V1_ExecutionContext.js';
import { V1_AnalyticsExecutionContext } from '../../../model/valueSpecification/raw/executionContext/V1_AnalyticsExecutionContext.js';
import { V1_BaseExecutionContext } from '../../../model/valueSpecification/raw/executionContext/V1_BaseExecutionContext.js';
import type { V1_GraphFetchTree } from '../../../model/valueSpecification/raw/classInstance/graph/V1_GraphFetchTree.js';
import { V1_PackageableElementPtr } from '../../../model/valueSpecification/raw/V1_PackageableElementPtr.js';
import type { V1_INTERNAL__UnknownValueSpecification } from '../../../model/valueSpecification/V1_INTERNAL__UnknownValueSpecfication.js';
import { V1_EngineRuntime } from '../../../model/packageableElements/runtime/V1_Runtime.js';
import { V1_GenericTypeInstance } from '../../../model/valueSpecification/raw/V1_GenericTypeInstance.js';
import type { V1_PrimitiveValueSpecification } from '../../../model/valueSpecification/raw/V1_PrimitiveValueSpecification.js';
import { V1_Multiplicity } from '../../../model/packageableElements/domain/V1_Multiplicity.js';
import type { PureProtocolProcessorPlugin } from '../../../../PureProtocolProcessorPlugin.js';
import { V1_ClassInstance } from '../../../model/valueSpecification/raw/V1_ClassInstance.js';
import { V1_CByteArray } from '../../../model/valueSpecification/raw/V1_CByteArray.js';
import {
V1_deserializeGenericType,
V1_genericTypeModelSchema,
} from './V1_TypeSerializationHelper.js';
import { V1_createGenericTypeWithElementPath } from '../../../helpers/V1_DomainHelper.js';
enum V1_ExecutionContextType {
BASE_EXECUTION_CONTEXT = 'BaseExecutionContext',
ANALYTICS_EXECUTION_CONTEXT = 'AnalyticsExecutionContext',
}
enum V1_PathElementType {
PROPERTY_PATH_ELEMENT = 'propertyPath',
}
export enum V1_GraphFetchTreeType {
PROPERTY_GRAPH_FETCH_TREE = 'propertyGraphFetchTree',
}
export enum V1_ClassInstanceType {
ROOT_GRAPH_FETCH_TREE = 'rootGraphFetchTree',
SUBTYPE_GRAPH_FETCH_TREE = 'subTypeGraphFetchTree',
PATH = 'path',
AGGREGATE_VALUE = 'aggregateValue',
EXECUTION_CONTEXT_INSTANCE = 'executionContextInstance',
PAIR = 'pair',
PURE_LIST = 'listInstance',
RUNTIME_INSTANCE = 'runtimeInstance',
SERIALIZATION_CONFIG = 'alloySerializationConfig',
COL_SPEC = 'colSpec',
COL_SPEC_ARRAY = 'colSpecArray',
RELATION_STORE_ACCESSOR = '>',
TDS_AGGREGATE_VALUE = 'tdsAggregateValue',
TDS_COLUMN_INFORMATION = 'tdsColumnInformation',
TDS_SORT_INFORMATION = 'tdsSortInformation',
TDS_OLAP_RANK = 'tdsOlapRank',
TDS_OLAP_AGGREGATION = 'tdsOlapAggregation',
}
enum V1_ValueSpecificationType {
VARIABLE = 'var',
LAMBDA = 'lambda',
KEY_EXPRESSION = 'keyExpression',
APPLIED_FUNCTION = 'func',
APPLIED_PROPERTY = 'property',
PACKAGEABLE_ELEMENT_PTR = 'packageableElementPtr',
GENERIC_TYPE_INSTANCE = 'genericTypeInstance',
ENUM_VALUE = 'enumValue',
COLLECTION = 'collection',
CINTEGER = 'integer',
CDECIMAL = 'decimal',
CSTRING = 'string',
CBOOLEAN = 'boolean',
CBYTEARRAY = 'byteArray',
CFLOAT = 'float',
CDATETIME = 'dateTime',
CSTRICTDATE = 'strictDate',
CSTRICTTIME = 'strictTime',
CLATESTDATE = 'latestDate',
CLASS_INSTANCE = 'classInstance',
// ------------------------------ DEPRECATED ----------------------------------
HACKED_CLASS = 'hackedClass',
HACKED_UNIT = 'hackedUnit',
UNIT_TYPE = 'unitType',
PRIMITIVE_TYPE = 'primitiveType',
CLASS = 'class',
ENUM = 'enum',
MAPPING_INSTANCE = 'mappingInstance',
}
// ---------------------------------------- Value Specification --------------------------------------
export const V1_variableModelSchema = createModelSchema(V1_Variable, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.VARIABLE),
genericType: optionalCustom(
(val) => serialize(V1_genericTypeModelSchema, val),
(val) => V1_deserializeGenericType(val),
{
beforeDeserialize: function (callback, jsonValue, jsonParentValue) {
/** @backwardCompatibility */
if (
jsonParentValue.class !== undefined &&
jsonParentValue.genericType === undefined
) {
callback(null, jsonParentValue.class);
} else {
callback(null, jsonParentValue.genericType);
}
},
},
),
multiplicity: usingModelSchema(V1_multiplicityModelSchema),
name: primitive(),
});
export const V1_lambdaModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_Lambda> =>
createModelSchema(V1_Lambda, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.LAMBDA),
body: list(
custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
),
parameters: list(usingModelSchema(V1_variableModelSchema)),
});
const keyExpressionModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_KeyExpression> =>
createModelSchema(V1_KeyExpression, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.KEY_EXPRESSION),
add: optional(primitive()),
expression: custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
key: custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
});
const appliedFunctionModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_AppliedFunction> =>
createModelSchema(V1_AppliedFunction, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.APPLIED_FUNCTION),
function: primitive(),
parameters: list(
custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
),
});
const appliedPropertyModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_AppliedProperty> =>
createModelSchema(V1_AppliedProperty, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.APPLIED_PROPERTY),
class: optional(primitive()),
parameters: list(
custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
),
property: primitive(),
});
export const V1_packageableElementPtrSchema = (isType?: boolean) =>
createModelSchema(V1_PackageableElementPtr, {
_type: usingConstantValueSchema(
V1_ValueSpecificationType.PACKAGEABLE_ELEMENT_PTR,
),
fullPath: primitive(),
});
const genericTypeInstanceSchema = (plugins: PureProtocolProcessorPlugin[]) =>
createModelSchema(V1_GenericTypeInstance, {
_type: usingConstantValueSchema(
V1_ValueSpecificationType.GENERIC_TYPE_INSTANCE,
),
genericType: custom(
(val) => serialize(V1_genericTypeModelSchema, val),
(val) => V1_deserializeGenericType(val),
{
beforeDeserialize: function (callback, jsonValue, jsonParentValue) {
/** @backwardCompatibility */
if (
jsonParentValue.fullPath !== undefined &&
jsonParentValue.genericType === undefined
) {
callback(null, jsonParentValue.fullPath);
} else {
callback(null, jsonParentValue.genericType);
}
},
},
),
});
/** @backwardCompatibility */
const deserializeHackedUnit = (json: PlainObject): V1_GenericTypeInstance => {
const protocol = new V1_GenericTypeInstance();
if (isString(json.unitType)) {
protocol.genericType = V1_createGenericTypeWithElementPath(json.unitType);
} else {
protocol.genericType = V1_createGenericTypeWithElementPath(
guaranteeIsString(
json.fullPath,
`Can't deserialize hacked unit: either field 'fullPath' or 'unitType' must be a non-empty string`,
),
);
}
return protocol;
};
/** @backwardCompatibility */
const deserializeHackedClass = (json: PlainObject): V1_GenericTypeInstance => {
const protocol = new V1_GenericTypeInstance();
protocol.genericType = V1_createGenericTypeWithElementPath(
guaranteeIsString(
json.fullPath,
`Can't deserialize hacked class: field 'fullPath' must be a non-empty string`,
),
);
return protocol;
};
const collectionModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_Collection> =>
createModelSchema(V1_Collection, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.COLLECTION),
multiplicity: usingModelSchema(V1_multiplicityModelSchema),
values: list(
custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
),
});
const enumValueModelSchema = createModelSchema(V1_EnumValue, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.ENUM_VALUE),
fullPath: primitive(),
value: primitive(),
});
const CDecimalModelSchema = createModelSchema(V1_CDecimal, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CDECIMAL),
value: primitive(),
});
const CIntegerModelSchema = createModelSchema(V1_CInteger, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CINTEGER),
value: primitive(),
});
const CStringModelSchema = createModelSchema(V1_CString, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CSTRING),
value: primitive(),
});
const CFloatModelSchema = createModelSchema(V1_CFloat, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CFLOAT),
value: primitive(),
});
const CDateTimeModelSchema = createModelSchema(V1_CDateTime, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CDATETIME),
value: primitive(),
});
const CStrictTimeModelSchema = createModelSchema(V1_CStrictTime, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CSTRICTTIME),
value: primitive(),
});
const CStrictDateModelSchema = createModelSchema(V1_CStrictDate, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CSTRICTDATE),
value: primitive(),
});
const CLatestDateModelSchema = createModelSchema(V1_CLatestDate, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CLATESTDATE),
});
const CBooleanModelSchema = createModelSchema(V1_CBoolean, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CBOOLEAN),
value: primitive(),
});
const CByteArrayModelSchema = createModelSchema(V1_CByteArray, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CBYTEARRAY),
value: primitive(),
});
/** @backwardCompatibility */
const deserializePrimitiveValueSpecification = <
T extends V1_PrimitiveValueSpecification,
>(
json: PlainObject,
plugins: PureProtocolProcessorPlugin[],
deserializer: (json: PlainObject<T>) => T,
): V1_ValueSpecification => {
if (Array.isArray(json.values)) {
if (json.values.length === 0) {
const collection = new V1_Collection();
collection.multiplicity = V1_Multiplicity.ZERO;
return collection;
} else if (json.values.length === 1) {
return deserializer({
...json,
value: json.values[0],
});
} else {
return V1_deserializeValueSpecification(
{
...json,
_type: V1_ValueSpecificationType.COLLECTION,
},
plugins,
);
}
}
return deserializer(json);
};
// ---------------------------------------- Class Instance --------------------------------------
const classInstanceModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_ClassInstance> =>
createModelSchema(V1_ClassInstance, {
_type: usingConstantValueSchema(V1_ValueSpecificationType.CLASS_INSTANCE),
multiplicity: usingModelSchema(V1_multiplicityModelSchema),
type: primitive(),
value: custom(
(val) => V1_serializeClassInstanceValue(val, plugins),
(val, context) =>
V1_deserializeClassInstanceValue(val, context.json.type, plugins),
),
});
// path
const propertyPathElementModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_PropertyPathElement> =>
createModelSchema(V1_PropertyPathElement, {
_type: usingConstantValueSchema(V1_PathElementType.PROPERTY_PATH_ELEMENT),
property: primitive(),
parameters: list(
custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
),
});
function V1_serializePathElement(
protocol: V1_PathElement,
plugins: PureProtocolProcessorPlugin[],
): V1_PathElement | PlainObject<V1_PathElement> | typeof SKIP {
if (protocol instanceof V1_PropertyPathElement) {
return serialize(propertyPathElementModelSchema(plugins), protocol);
}
return SKIP;
}
function V1_deserializePathElement(
json: PlainObject<V1_PathElement>,
plugins: PureProtocolProcessorPlugin[],
): V1_PathElement | typeof SKIP {
switch (json._type) {
case V1_PathElementType.PROPERTY_PATH_ELEMENT:
return deserialize(propertyPathElementModelSchema(plugins), json);
default:
return SKIP;
}
}
const pathModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_Path> =>
createModelSchema(V1_Path, {
_type: usingConstantValueSchema(V1_ClassInstanceType.PATH),
name: primitive(),
startType: primitive(),
path: list(
custom(
(val) => V1_serializePathElement(val, plugins),
(val) => V1_deserializePathElement(val, plugins),
),
),
});
// graph fetch tree
const rootGraphFetchTreeModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_RootGraphFetchTree> =>
createModelSchema(V1_RootGraphFetchTree, {
_type: usingConstantValueSchema(V1_ClassInstanceType.ROOT_GRAPH_FETCH_TREE),
class: primitive(),
subTrees: list(
custom(
(val) => V1_serializeGraphFetchTree(val, plugins),
(val) => V1_deserializeGraphFetchTree(val, plugins),
),
),
subTypeTrees: list(
custom(
(val) => V1_serializeGraphFetchTree(val, plugins),
(val) => V1_deserializeGraphFetchTree(val, plugins),
),
),
});
const propertyGraphFetchTreeModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_PropertyGraphFetchTree> =>
createModelSchema(V1_PropertyGraphFetchTree, {
_type: usingConstantValueSchema(
V1_GraphFetchTreeType.PROPERTY_GRAPH_FETCH_TREE,
),
alias: optional(primitive()),
parameters: list(
custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
),
property: primitive(),
subTrees: list(
custom(
(val) => V1_serializeGraphFetchTree(val, plugins),
(val) => V1_deserializeGraphFetchTree(val, plugins),
),
),
subTypeTrees: list(
custom(
(val) => V1_serializeGraphFetchTree(val, plugins),
(val) => V1_deserializeGraphFetchTree(val, plugins),
),
),
subType: optional(primitive()),
});
const subTypeGraphFetchTreeModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_SubTypeGraphFetchTree> =>
createModelSchema(V1_SubTypeGraphFetchTree, {
_type: usingConstantValueSchema(
V1_ClassInstanceType.SUBTYPE_GRAPH_FETCH_TREE,
),
subTrees: list(
custom(
(val) => V1_serializeGraphFetchTree(val, plugins),
(val) => V1_deserializeGraphFetchTree(val, plugins),
),
),
subTypeClass: primitive(),
});
export function V1_serializeGraphFetchTree(
protocol: V1_GraphFetchTree,
plugins: PureProtocolProcessorPlugin[],
): PlainObject<V1_GraphFetchTree> {
// we have further subtypes of Property and RootGraph Tree so we should look at the extensions first
const serializers = plugins.flatMap(
(plugin) => plugin.V1_getExtraGraphFetchProtocolSerializers?.() ?? [],
);
for (const serializer of serializers) {
const json = serializer(protocol, plugins);
if (json) {
return json;
}
}
if (protocol instanceof V1_PropertyGraphFetchTree) {
return serialize(propertyGraphFetchTreeModelSchema(plugins), protocol);
} else if (protocol instanceof V1_RootGraphFetchTree) {
return serialize(rootGraphFetchTreeModelSchema(plugins), protocol);
} else if (protocol instanceof V1_SubTypeGraphFetchTree) {
return serialize(subTypeGraphFetchTreeModelSchema(plugins), protocol);
}
throw new UnsupportedOperationError(
`Can't serialize graph fetch tree: no compatible serializer available from plugins`,
protocol,
);
}
export function V1_deserializeGraphFetchTree(
json: PlainObject<V1_GraphFetchTree>,
plugins: PureProtocolProcessorPlugin[],
): V1_GraphFetchTree {
switch (json._type) {
case V1_GraphFetchTreeType.PROPERTY_GRAPH_FETCH_TREE:
return deserialize(propertyGraphFetchTreeModelSchema(plugins), json);
case V1_ClassInstanceType.ROOT_GRAPH_FETCH_TREE:
return deserialize(rootGraphFetchTreeModelSchema(plugins), json);
case V1_ClassInstanceType.SUBTYPE_GRAPH_FETCH_TREE:
return deserialize(subTypeGraphFetchTreeModelSchema(plugins), json);
default: {
const deserializers = plugins.flatMap(
(plugin) => plugin.V1_getExtraGraphFetchProtocolDeserializers?.() ?? [],
);
for (const deserializer of deserializers) {
const protocol = deserializer(json, plugins);
if (protocol) {
return protocol;
}
}
throw new UnsupportedOperationError(
`Can't deserialize graph fetch tree node of type '${json._type}': no compatible deserializer available from plugins`,
);
}
}
}
// execution context
const analyticsExecutionContextModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_AnalyticsExecutionContext> =>
createModelSchema(V1_AnalyticsExecutionContext, {
_type: usingConstantValueSchema(
V1_ExecutionContextType.ANALYTICS_EXECUTION_CONTEXT,
),
enableConstraints: optional(primitive()),
queryTimeOutInSeconds: optional(primitive()),
toFlowSetFunction: usingModelSchema(V1_lambdaModelSchema(plugins)),
useAnalytics: primitive(),
});
const baseExecutionContextModelSchema = createModelSchema(
V1_BaseExecutionContext,
{
_type: usingConstantValueSchema(
V1_ExecutionContextType.BASE_EXECUTION_CONTEXT,
),
enableConstraints: optional(primitive()),
queryTimeOutInSeconds: optional(primitive()),
},
);
function V1_serializeExecutionContext(
protocol: V1_ExecutionContext,
plugins: PureProtocolProcessorPlugin[],
): PlainObject<V1_ExecutionContext> | typeof SKIP {
if (protocol instanceof V1_AnalyticsExecutionContext) {
return serialize(analyticsExecutionContextModelSchema(plugins), protocol);
} else if (protocol instanceof V1_BaseExecutionContext) {
return serialize(baseExecutionContextModelSchema, protocol);
}
return SKIP;
}
function V1_deserializeExecutionContext(
json: PlainObject<V1_ExecutionContext>,
plugins: PureProtocolProcessorPlugin[],
): V1_ExecutionContext | typeof SKIP {
switch (json._type) {
case V1_ExecutionContextType.ANALYTICS_EXECUTION_CONTEXT:
return deserialize(analyticsExecutionContextModelSchema(plugins), json);
case V1_ExecutionContextType.BASE_EXECUTION_CONTEXT:
return deserialize(baseExecutionContextModelSchema, json);
default:
return SKIP;
}
}
const executionContextInstanceModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_ExecutionContextInstance> =>
createModelSchema(V1_ExecutionContextInstance, {
_type: usingConstantValueSchema(
V1_ClassInstanceType.EXECUTION_CONTEXT_INSTANCE,
),
executionContext: custom(
(val) => V1_serializeExecutionContext(val, plugins),
(val) => V1_deserializeExecutionContext(val, plugins),
),
});
// others
const aggregationValueModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_AggregateValue> =>
createModelSchema(V1_AggregateValue, {
_type: usingConstantValueSchema(V1_ClassInstanceType.AGGREGATE_VALUE),
mapFn: usingModelSchema(V1_lambdaModelSchema(plugins)),
aggregateFn: usingModelSchema(V1_lambdaModelSchema(plugins)),
});
const pairModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_Pair> =>
createModelSchema(V1_Pair, {
_type: usingConstantValueSchema(V1_ClassInstanceType.PAIR),
first: custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
second: custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
});
const runtimeInstanceModelSchema = createModelSchema(V1_RuntimeInstance, {
_type: usingConstantValueSchema(V1_ClassInstanceType.RUNTIME_INSTANCE),
runtime: custom(
(val) => V1_serializeRuntime(val),
(val) => deserialize(V1_EngineRuntime, val),
),
});
const pureListModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_PureList> =>
createModelSchema(V1_PureList, {
_type: usingConstantValueSchema(V1_ClassInstanceType.PURE_LIST),
values: list(
custom(
(val) => V1_serializeValueSpecification(val, plugins),
(val) => V1_deserializeValueSpecification(val, plugins),
),
),
});
const serializationConfigModelSchema = createModelSchema(
V1_SerializationConfig,
{
_type: usingConstantValueSchema(V1_ClassInstanceType.SERIALIZATION_CONFIG),
includeType: optional(primitive()),
typeKeyName: primitive(),
includeEnumTypee: optional(primitive()),
removePropertiesWithNullValuese: optional(primitive()),
removePropertiesWithEmptySetse: optional(primitive()),
fullyQualifiedTypePathe: optional(primitive()),
includeObjectReferencee: optional(primitive()),
},
);
// TDS
const tdsAggregrateValueModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_TDSAggregateValue> =>
createModelSchema(V1_TDSAggregateValue, {
_type: usingConstantValueSchema(V1_ClassInstanceType.TDS_AGGREGATE_VALUE),
name: primitive(),
pmapFn: usingModelSchema(V1_lambdaModelSchema(plugins)),
aggregateFn: usingModelSchema(V1_lambdaModelSchema(plugins)),
});
const tdsColumnInformationModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_TDSColumnInformation> =>
createModelSchema(V1_TDSColumnInformation, {
_type: usingConstantValueSchema(
V1_ClassInstanceType.TDS_COLUMN_INFORMATION,
),
name: primitive(),
columnFn: usingModelSchema(V1_lambdaModelSchema(plugins)),
});
const tdsSortInformationModelSchema = createModelSchema(V1_TDSSortInformation, {
_type: usingConstantValueSchema(V1_ClassInstanceType.TDS_SORT_INFORMATION),
column: primitive(),
direction: primitive(),
});
const relationStoreAccessorModelSchema = createModelSchema(
V1_RelationStoreAccessor,
{
path: list(primitive()),
},
);
const colSpecModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_ColSpec> =>
createModelSchema(V1_ColSpec, {
function1: optional(usingModelSchema(V1_lambdaModelSchema(plugins))),
function2: optional(usingModelSchema(V1_lambdaModelSchema(plugins))),
name: primitive(),
type: optional(primitive()),
});
const colSpecArrayModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_ColSpecArray> =>
createModelSchema(V1_ColSpecArray, {
colSpecs: list(usingModelSchema(colSpecModelSchema(plugins))),
});
const tdsOlapRankModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_TDSOlapRank> =>
createModelSchema(V1_TDSOlapRank, {
_type: usingConstantValueSchema(V1_ClassInstanceType.TDS_OLAP_RANK),
function: usingModelSchema(V1_lambdaModelSchema(plugins)),
});
const tdsOlapAggregationModelSchema = (
plugins: PureProtocolProcessorPlugin[],
): ModelSchema<V1_TDSOlapAggregation> =>
createModelSchema(V1_TDSOlapAggregation, {
_type: usingConstantValueSchema(V1_ClassInstanceType.TDS_OLAP_AGGREGATION),
function: usingModelSchema(V1_lambdaModelSchema(plugins)),
columnName: primitive(),
});
export function V1_deserializeClassInstanceValue(
json: PlainObject,
type: string,
plugins: PureProtocolProcessorPlugin[],
): unknown {
switch (type) {
case V1_ClassInstanceType.PATH:
return deserialize(pathModelSchema(plugins), json);
case V1_ClassInstanceType.ROOT_GRAPH_FETCH_TREE:
return deserialize(rootGraphFetchTreeModelSchema(plugins), json);
case V1_ClassInstanceType.AGGREGATE_VALUE:
return deserialize(aggregationValueModelSchema(plugins), json);
case V1_ClassInstanceType.EXECUTION_CONTEXT_INSTANCE:
return deserialize(executionContextInstanceModelSchema(plugins), json);
case V1_ClassInstanceType.PAIR:
return deserialize(pairModelSchema(plugins), json);
case V1_ClassInstanceType.PURE_LIST:
return deserialize(pureListModelSchema(plugins), json);
case V1_ClassInstanceType.RUNTIME_INSTANCE:
return deserialize(runtimeInstanceModelSchema, json);
case V1_ClassInstanceType.SERIALIZATION_CONFIG:
return deserialize(serializationConfigModelSchema, json);
case V1_ClassInstanceType.TDS_AGGREGATE_VALUE:
return deserialize(tdsAggregrateValueModelSchema(plugins), json);
case V1_ClassInstanceType.TDS_COLUMN_INFORMATION:
return deserialize(tdsColumnInformationModelSchema(plugins), json);
case V1_ClassInstanceType.TDS_OLAP_AGGREGATION:
return deserialize(tdsOlapAggregationModelSchema(plugins), json);
case V1_ClassInstanceType.TDS_OLAP_RANK:
return deserialize(tdsOlapRankModelSchema(plugins), json);
case V1_ClassInstanceType.TDS_SORT_INFORMATION:
return deserialize(tdsSortInformationModelSchema, json);
case V1_ClassInstanceType.COL_SPEC:
return deserialize(colSpecModelSchema(plugins), json);
case V1_ClassInstanceType.COL_SPEC_ARRAY:
return deserialize(colSpecArrayModelSchema(plugins), json);
case V1_ClassInstanceType.RELATION_STORE_ACCESSOR:
return deserialize(relationStoreAccessorModelSchema, json);
default: {
const deserializers = plugins.flatMap(
(plugin) =>
plugin.V1_getExtraClassInstanceValueProtocolDeserializers?.() ?? [],
);
for (const deserializer of deserializers) {
const protocol = deserializer(json, type, plugins);
if (protocol) {
return protocol;
}
}
throw new UnsupportedOperationError(
`Can't deserialize value specification of type '${json._type}': no compatible deserializer available from plugins`,
);
}
}
}
export function V1_serializeClassInstanceValue(
protocol: unknown,
plugins: PureProtocolProcessorPlugin[],
): PlainObject {
if (protocol instanceof V1_Path) {
return serialize(pathModelSchema(plugins), protocol);
} else if (protocol instanceof V1_RootGraphFetchTree) {
return serialize(rootGraphFetchTreeModelSchema(plugins), protocol);
} else if (protocol instanceof V1_ExecutionContextInstance) {
return serialize(executionContextInstanceModelSchema(plugins), protocol);
} else if (protocol instanceof V1_AggregateValue) {
return serialize(aggregationValueModelSchema(plugins), protocol);
} else if (protocol instanceof V1_Pair) {
return serialize(pairModelSchema(plugins), protocol);
} else if (protocol instanceof V1_PureList) {
return serialize(pureListModelSchema(plugins), protocol);
} else if (protocol instanceof V1_RuntimeInstance) {
return serialize(runtimeInstanceModelSchema, protocol);
} else if (protocol instanceof V1_SerializationConfig) {
return serialize(serializationConfigModelSchema, protocol);
} else if (protocol instanceof V1_TDSAggregateValue) {
return serialize(tdsAggregrateValueModelSchema(plugins), protocol);
} else if (protocol instanceof V1_TDSColumnInformation) {
return serialize(tdsColumnInformationModelSchema(plugins), protocol);
} else if (protocol instanceof V1_TDSOlapAggregation) {
return serialize(tdsOlapAggregationModelSchema(plugins), protocol);
} else if (protocol instanceof V1_TDSOlapRank) {
return serialize(tdsOlapRankModelSchema(plugins), protocol);
} else if (protocol instanceof V1_TDSSortInformation) {
return serialize(tdsSortInformationModelSchema, protocol);
} else if (protocol instanceof V1_ColSpec) {
return serialize(colSpecModelSchema(plugins), protocol);
} else if (protocol instanceof V1_ColSpecArray) {
return serialize(colSpecArrayModelSchema(plugins), protocol);
} else if (protocol instanceof V1_RelationStoreAccessor) {
return serialize(relationStoreAccessorModelSchema, protocol);
}
const serializers = plugins.flatMap(
(plugin) =>
plugin.V1_getExtraClassInstanceValueProtocolSerializers?.() ?? [],
);
for (const serializer of serializers) {
const json = serializer(protocol, plugins);
if (json) {
return json;
}
}
throw new UnsupportedOperationError(
`Can't serialize class instance value: no compatible serializer available from plugins`,
protocol,
);
}
// ---------------------------------------- Serialization Methods --------------------------------------
class V1_ValueSpecificationSerializer
implements V1_ValueSpecificationVisitor<PlainObject<V1_ValueSpecification>>
{
readonly plugins: PureProtocolProcessorPlugin[] = [];
constructor(plugins: PureProtocolProcessorPlugin[]) {
this.plugins = plugins;
}
visit_INTERNAL__UnknownValueSpecfication(
valueSpecification: V1_INTERNAL__UnknownValueSpecification,
): PlainObject<V1_ValueSpecification> {
return valueSpecification.content;
}
visit_Variable(
valueSpecification: V1_Variable,
): PlainObject<V1_ValueSpecification> {
return serialize(V1_variableModelSchema, valueSpecification);
}
visit_Lambda(
valueSpecification: V1_Lambda,
): PlainObject<V1_ValueSpecification> {
return serialize(V1_lambdaModelSchema(this.plugins), valueSpecification);
}
visit_KeyExpression(
valueSpecification: V1_KeyExpression,
): PlainObject<V1_ValueSpecification> {
return serialize(
keyExpressionModelSchema(this.plugins),
valueSpecification,
);
}
visit_PackageableElementPtr(
valueSpecification: V1_PackageableElementPtr,
): PlainObject<V1_ValueSpecification> {
return serialize(V1_packageableElementPtrSchema(), valueSpecification);
}
visit_GenericTypeInstance(
valueSpecification: V1_GenericTypeInstance,
): PlainObject<V1_ValueSpecification> {
return serialize(
genericTypeInstanceSchema(this.plugins),
valueSpecification,
);
}
visit_AppliedFunction(
valueSpecification: V1_AppliedFunction,
): PlainObject<V1_ValueSpecification> {
return serialize(
appliedFunctionModelSchema(this.plugins),
valueSpecification,
);
}
visit_AppliedProperty(
valueSpecification: V1_AppliedProperty,
): PlainObject<V1_ValueSpecification> {
return serialize(
appliedPropertyModelSchema(this.plugins),
valueSpecification,
);
}
visit_Collection(
valueSpecification: V1_Collection,
): PlainObject<V1_ValueSpecification> {
return serialize(collectionModelSchema(this.plugins), valueSpecification);
}
visit_EnumValue(
valueSpecification: V1_EnumValue,
): PlainObject<V1_ValueSpecification> {
return serialize(enumValueModelSchema, valueSpecification);
}
visit_CInteger(
valueSpecification: V1_CInteger,
): PlainObject<V1_ValueSpecification> {
return serialize(CIntegerModelSchema, valueSpecification);
}
visit_CDecimal(
valueSpecification: V1_CDecimal,
): PlainObject<V1_ValueSpecification> {
return serialize(CDecimalModelSchema, valueSpecification);
}
visit_CString(
valueSpecification: V1_CString,
): PlainObject<V1_ValueSpecification> {
return serialize(CStringModelSchema, valueSpecification);
}
visit_CBoolean(
valueSpecification: V1_CBoolean,
): PlainObject<V1_ValueSpecification> {
return serialize(CBooleanModelSchema, valueSpecification);
}
visit_CByteArray(
valueSpecification: V1_CByteArray,
): PlainObject<V1_ValueSpecification> {
return serialize(CByteArrayModelSchema, valueSpecification);
}
visit_CFloat(
valueSpecification: V1_CFloat,
): PlainObject<V1_ValueSpecification> {
return serialize(CFloatModelSchema, valueSpecification);
}
visit_CDateTime(
valueSpecification: V1_CDateTime,
): PlainObject<V1_ValueSpecification> {
return serialize(CDateTimeModelSchema, valueSpecification);
}
visit_CStrictDate(
valueSpecification: V1_CStrictDate,
): PlainObject<V1_ValueSpecification> {
return serialize(CStrictDateModelSchema, valueSpecification);
}
visit_CStrictTime(
valueSpecification: V1_CStrictTime,
): PlainObject<V1_ValueSpecification> {
return serialize(CStrictTimeModelSchema, valueSpecification);
}
visit_CLatestDate(
valueSpecification: V1_CLatestDate,
): PlainObject<V1_ValueSpecification> {
return serialize(CLatestDateModelSchema, valueSpecification);
}
visit_ClassInstance(
valueSpecification: V1_ClassInstance,
): PlainObject<V1_ValueSpecification> {
return serialize(
classInstanceModelSchema(this.plugins),
valueSpecification,
);
}
}
export function V1_deserializeValueSpecification(
json: PlainObject<V1_ValueSpecification>,
plugins: PureProtocolProcessorPlugin[],
): V1_ValueSpecification {
switch (json._type) {
case V1_ValueSpecificationType.APPLIED_FUNCTION:
return deserialize(appliedFunctionModelSchema(plugins), json);
case V1_ValueSpecificationType.APPLIED_PROPERTY:
return deserialize(appliedPropertyModelSchema(plugins), json);
case V1_ValueSpecificationType.VARIABLE:
return deserialize(V1_variableModelSchema, json);
case V1_ValueSpecificationType.LAMBDA:
return deserialize(V1_lambdaModelSchema(plugins), json);
case V1_ValueSpecificationType.KEY_EXPRESSION:
return deserialize(keyExpressionModelSchema(plugins), json);
case V1_ValueSpecificationType.COLLECTION:
return deserialize(collectionModelSchema(plugins), json);
case V1_ValueSpecificationType.ENUM_VALUE:
return deserialize(enumValueModelSchema, json);
// primitive values
case V1_ValueSpecificationType.CBOOLEAN:
return deserializePrimitiveValueSpecification(json, plugins, (val) =>
deserialize(CBooleanModelSchema, val),
);
case V1_ValueSpecificationType.CBYTEARRAY: {
return deserializePrimitiveValueSpecification(json, plugins, (val) =>
deserialize(CByteArrayModelSchema, val),
);
}
case V1_ValueSpecificationType.CDATETIME:
return deserializePrimitiveValueSpecification(json, plugins, (val) =>
deserialize(CDateTimeModelSchema, val),
);
case V1_ValueSpecificationType.CSTRICTTIME:
return deserializePrimitiveValueSpecification(json, plugins, (val) =>
deserialize(CStrictTimeModelSchema, val),
);
case V1_ValueSpecificationType.CDECIMAL:
return deserializePrimitiveValueSpecification(json, plugins, (val) =>
deserialize(CDecimalModelSchema, val),
);
case V1_ValueSpecificationType.CFLOAT:
return deserializePrimitiveValueSpecification(json, plugins, (val) =>
deserialize(CFloatModelSchema, val),
);
case V1_ValueSpecificationType.CINTEGER:
return deserializePrimitiveValueSpecification(json, plugins, (val) =>
deserialize(CIntegerModelSchema, val),
);
case V1_ValueSpecificationType.CLATESTDATE:
return deserializePrimitiveValueSpecification(json, plugins, (val) =>
deserialize(CLatestDateModelSchema, val),
);
case V1_ValueSpecificationType.CSTRICTDATE:
return deserializePrimitiveValueSpecification(json, plugins, (val) =>
deserialize(CStrictDateModelSchema, val),
);
case V1_ValueSpecificationType.CSTRING: {
// This workaround is intended to handle an edge case where CString is sent with empty values
// we will convert it to an empty string instead
// See https://github.com/finos/legend-engine/pull/1076
if (
Array.isArray(json.values) &&
!json.values.length &&
isPlainObject(json.multiplicity) &&
json.multiplicity.upperBound === 1
) {
const result = new V1_CString();
result.value = '';
return result;
}
return deserializePrimitiveValueSpecification(json, plugins, (val) =>
deserialize(CStringModelSchema, val),
);
}
// class instance
case V1_ValueSpecificationType.CLASS_INSTANCE:
return deserialize(classInstanceModelSchema(plugins), json);
/**
* NOTE: the following types are here for backward compatibility
* as some of these are used to be value specifications, but now
* transformed into class instances
*
* @backwardCompatibility
*/
case V1_ClassInstanceType.PAIR:
case V1_ClassInstanceType.AGGREGATE_VALUE:
case V1_ClassInstanceType.EXECUTION_CONTEXT_INSTANCE:
case V1_ClassInstanceType.PATH:
case V1_ClassInstanceType.ROOT_GRAPH_FETCH_TREE:
case V1_ClassInstanceType.PURE_LIST:
case V1_ClassInstanceType.RUNTIME_INSTANCE:
case V1_ClassInstanceType.SERIALIZATION_CONFIG:
case V1_ClassInstanceType.TDS_AGGREGATE_VALUE:
case V1_ClassInstanceType.TDS_COLUMN_INFORMATION:
case V1_ClassInstanceType.TDS_OLAP_AGGREGATION:
case V1_ClassInstanceType.TDS_OLAP_RANK:
case V1_ClassInstanceType.TDS_SORT_INFORMATION:
return deserialize(classInstanceModelSchema(plugins), {
_type: V1_ValueSpecificationType.CLASS_INSTANCE,
type: json._type,
value: json,
});
// packageable element pointer
case V1_ValueSpecificationType.HACKED_CLASS: // deprecated
return deserializeHackedClass(json);
case V1_ValueSpecificationType.UNIT_TYPE: // deprecated
case V1_ValueSpecificationType.HACKED_UNIT: // deprecated
return deserializeHackedUnit(json);
case V1_ValueSpecificationType.PRIMITIVE_TYPE: // deprecated
case V1_ValueSpecificationType.ENUM: // deprecated
case V1_ValueSpecificationType.CLASS: // deprecated
case V1_ValueSpecificationType.MAPPING_INSTANCE: // deprecated
case V1_ValueSpecificationType.PACKAGEABLE_ELEMENT_PTR:
return deserialize(V1_packageableElementPtrSchema(), json);
case V1_ValueSpecificationType.GENERIC_TYPE_INSTANCE:
return deserialize(genericTypeInstanceSchema(plugins), json);
default:
throw new UnsupportedOperationError(
`Can't deserialize value specification of type '${json._type}'`,
);
}
}
export function V1_serializeValueSpecification(
protocol: V1_ValueSpecification,
plugins: PureProtocolProcessorPlugin[],
): PlainObject<V1_ValueSpecification> {
return protocol.accept_ValueSpecificationVisitor(
new V1_ValueSpecificationSerializer(plugins),
);
}