/**
 * 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, list, primitive, deserialize, serialize, custom, optional, raw, SKIP, } from 'serializr';
import { usingConstantValueSchema, assertTrue, guaranteeIsNumber, guaranteeIsString, IllegalStateError, isNonNullable, shallowStringify, UnsupportedOperationError, usingModelSchema, optionalCustom, optionalCustomList, customList, TEMPORARY__disableModelSchemaExtensionMechanism, } from '@finos/legend-shared';
import { ATOMIC_TEST_TYPE, PRIMITIVE_TYPE, ELEMENT_PATH_DELIMITER, PackageableElementPointerType, } from '../../../../../../../graph/MetaModelConst.js';
import { V1_Mapping } from '../../../model/packageableElements/mapping/V1_Mapping.js';
import { V1_DEPRECATED__MappingTest, V1_DEPRECATED__ObjectInputData, V1_DEPRECATED__FlatDataInputData, V1_DEPRECATED__ExpectedOutputMappingTestAssert, V1_DEPRECATED__RelationalInputData, } from '../../../model/packageableElements/mapping/V1_DEPRECATED__MappingTest.js';
import { V1_multiplicityModelSchema, V1_packageableElementPointerModelSchema, V1_serializePackageableElementPointer, } from '../../../transformation/pureProtocol/serializationHelpers/V1_CoreSerializationHelper.js';
import { V1_propertyPointerModelSchema } from './V1_DomainSerializationHelper.js';
import { V1_RelationalAssociationMapping } from '../../../model/packageableElements/store/relational/mapping/V1_RelationalAssociationMapping.js';
import { V1_LocalMappingPropertyInfo } from '../../../model/packageableElements/mapping/V1_LocalMappingPropertyInfo.js';
import { V1_RelationalPropertyMapping } from '../../../model/packageableElements/store/relational/mapping/V1_RelationalPropertyMapping.js';
import { V1_serializeRelationalOperationElement, V1_deserializeRelationalOperationElement, V1_filterMappingModelSchema, V1_tablePtrModelSchema, } from './V1_DatabaseSerializationHelper.js';
import { V1_MappingIncludeMapping, } from '../../../model/packageableElements/mapping/V1_MappingInclude.js';
import { V1_MappingIncludeDataProduct } from '../../../model/packageableElements/dataProduct/V1_MappingIncludeDataProduct.js';
import { V1_EnumValueMappingEnumSourceValue, V1_EnumValueMappingIntegerSourceValue, V1_EnumValueMappingStringSourceValue, V1_EnumValueMapping, } from '../../../model/packageableElements/mapping/V1_EnumValueMapping.js';
import { V1_EnumerationMapping } from '../../../model/packageableElements/mapping/V1_EnumerationMapping.js';
import { V1_OperationClassMapping } from '../../../model/packageableElements/mapping/V1_OperationClassMapping.js';
import { V1_PureInstanceClassMapping } from '../../../model/packageableElements/store/modelToModel/mapping/V1_PureInstanceClassMapping.js';
import { V1_PurePropertyMapping } from '../../../model/packageableElements/store/modelToModel/mapping/V1_PurePropertyMapping.js';
import { V1_FlatDataPropertyMapping } from '../../../model/packageableElements/store/flatData/mapping/V1_FlatDataPropertyMapping.js';
import { V1_EmbeddedFlatDataPropertyMapping } from '../../../model/packageableElements/store/flatData/mapping/V1_EmbeddedFlatDataPropertyMapping.js';
import { V1_RootFlatDataClassMapping } from '../../../model/packageableElements/store/flatData/mapping/V1_RootFlatDataClassMapping.js';
import { V1_RootRelationalClassMapping } from '../../../model/packageableElements/store/relational/mapping/V1_RootRelationalClassMapping.js';
import { V1_RelationalClassMapping } from '../../../model/packageableElements/store/relational/mapping/V1_RelationalClassMapping.js';
import { V1_EmbeddedRelationalPropertyMapping } from '../../../model/packageableElements/store/relational/mapping/V1_EmbeddedRelationalPropertyMapping.js';
import { V1_OtherwiseEmbeddedRelationalPropertyMapping } from '../../../model/packageableElements/store/relational/mapping/V1_OtherwiseEmbeddedRelationalPropertyMapping.js';
import { V1_InlineEmbeddedPropertyMapping } from '../../../model/packageableElements/store/relational/mapping/V1_InlineEmbeddedPropertyMapping.js';
import { V1_rawLambdaModelSchema } from './V1_RawValueSpecificationSerializationHelper.js';
import { V1_AggregationAwareClassMapping } from '../../../model/packageableElements/store/relational/mapping/aggregationAware/V1_AggregationAwareClassMapping.js';
import { V1_AggregateSetImplementationContainer } from '../../../model/packageableElements/store/relational/mapping/aggregationAware/V1_AggregateSetImplementationContainer.js';
import { V1_AggregateSpecification } from '../../../model/packageableElements/store/relational/mapping/aggregationAware/V1_AggregateSpecification.js';
import { V1_AggregateFunction } from '../../../model/packageableElements/store/relational/mapping/aggregationAware/V1_AggregateFunction.js';
import { V1_GroupByFunction } from '../../../model/packageableElements/store/relational/mapping/aggregationAware/V1_GroupByFunction.js';
import { V1_AggregationAwarePropertyMapping } from '../../../model/packageableElements/store/relational/mapping/aggregationAware/V1_AggregationAwarePropertyMapping.js';
import { V1_XStorePropertyMapping } from '../../../model/packageableElements/mapping/xStore/V1_XStorePropertyMapping.js';
import { V1_XStoreAssociationMapping } from '../../../model/packageableElements/mapping/xStore/V1_XStoreAssociationMapping.js';
import { V1_BindingTransformer } from '../../../model/packageableElements/externalFormat/store/V1_DSL_ExternalFormat_BindingTransformer.js';
import { V1_MergeOperationClassMapping } from '../../../model/packageableElements/mapping/V1_MergeOperationClassMapping.js';
import { V1_FlatDataAssociationMapping } from '../../../model/packageableElements/store/flatData/mapping/V1_FlatDataAssociationMapping.js';
import { V1_FlatDataAssociationPropertyMapping } from '../../../model/packageableElements/store/flatData/mapping/V1_FlatDataAssociationPropertyMapping.js';
import { V1_MappingTestSuite } from '../../../model/packageableElements/mapping/V1_MappingTestSuite.js';
import { V1_deserializeAtomicTest, V1_deserializeTestAssertion, V1_deserializeTestSuite, V1_serializeAtomicTest, V1_serializeTestAssertion, V1_serializeTestSuite, V1_TestSuiteType, } from './V1_TestSerializationHelper.js';
import { V1_MappingStoreTestData } from '../../../model/packageableElements/mapping/V1_MappingStoreTestData.js';
import { V1_deserializeEmbeddedDataType, V1_serializeEmbeddedDataType, } from './V1_DataElementSerializationHelper.js';
import { V1_MAPPING_INCLUDE_DATAPRODUCT_TYPE, V1_mappingIncludeDataProductModelSchema, } from '../../../transformation/pureProtocol/serializationHelpers/V1_DataProductSerializationHelper.js';
import { V1_MappingTest } from '../../../model/packageableElements/mapping/V1_MappingTest.js';
import { V1_INTERNAL__UnknownClassMapping } from '../../../model/packageableElements/mapping/V1_INTERNAL__UnknownClassMapping.js';
import { V1_INTERNAL__UnknownMappingInclude } from '../../../model/packageableElements/mapping/V1_INTERNAL__UnknownMappingInclude.js';
import { V1_RelationFunctionClassMapping } from '../../../model/packageableElements/mapping/V1_RelationFunctionClassMapping.js';
import { V1_RelationFunctionPropertyMapping } from '../../../model/packageableElements/mapping/V1_RelationFunctionPropertyMapping.js';
var V1_ClassMappingType;
(function (V1_ClassMappingType) {
    V1_ClassMappingType["OPERATION"] = "operation";
    V1_ClassMappingType["MERGE_OPERATION"] = "mergeOperation";
    V1_ClassMappingType["PUREINSTANCE"] = "pureInstance";
    V1_ClassMappingType["ROOT_FLAT_DATA"] = "flatData";
    V1_ClassMappingType["ROOT_RELATIONAL"] = "relational";
    V1_ClassMappingType["RELATIONAL"] = "embedded";
    V1_ClassMappingType["AGGREGATION_AWARE"] = "aggregationAware";
    V1_ClassMappingType["RELATION_FUNCTION"] = "relation";
})(V1_ClassMappingType || (V1_ClassMappingType = {}));
var V1_PropertyMappingType;
(function (V1_PropertyMappingType) {
    V1_PropertyMappingType["PURE"] = "purePropertyMapping";
    V1_PropertyMappingType["FLAT_DATA"] = "flatDataPropertyMapping";
    V1_PropertyMappingType["ASSOCIATION_FLAT_DATA"] = "flatDataAssociationPropertyMapping";
    V1_PropertyMappingType["EMBEDDED_FLAT_DATA"] = "embeddedFlatDataPropertyMapping";
    V1_PropertyMappingType["RELATIONAL"] = "relationalPropertyMapping";
    V1_PropertyMappingType["EMBEDDED_RELATIONAL"] = "embeddedPropertyMapping";
    V1_PropertyMappingType["INLINE_EMBEDDED_RELATIONAL"] = "inlineEmbeddedPropertyMapping";
    V1_PropertyMappingType["OTHERWISE_EMBEDDED_RELATIONAL"] = "otherwiseEmbeddedPropertyMapping";
    V1_PropertyMappingType["AGGREGATION_AWARE"] = "AggregationAwarePropertyMapping";
    V1_PropertyMappingType["XSTORE"] = "xStorePropertyMapping";
    V1_PropertyMappingType["RELATION_FUNCTION"] = "relationFunctionPropertyMapping";
})(V1_PropertyMappingType || (V1_PropertyMappingType = {}));
// ------------------------------------- Shared -------------------------------------
const V1_localMappingPropertyInfoModelSchema = createModelSchema(V1_LocalMappingPropertyInfo, {
    multiplicity: usingModelSchema(V1_multiplicityModelSchema),
    type: primitive(),
});
// ------------------------------------- Operation Mapping -------------------------------------
const operationClassMappingModelSchema = createModelSchema(V1_OperationClassMapping, {
    _type: usingConstantValueSchema(V1_ClassMappingType.OPERATION),
    class: primitive(),
    extendsClassMappingId: optional(primitive()),
    id: optional(primitive()),
    operation: primitive(),
    parameters: list(primitive()),
    root: primitive(),
});
const mergeOperationClassMappingModelSchema = createModelSchema(V1_MergeOperationClassMapping, {
    _type: usingConstantValueSchema(V1_ClassMappingType.MERGE_OPERATION),
    class: primitive(),
    extendsClassMappingId: optional(primitive()),
    id: optional(primitive()),
    operation: primitive(),
    parameters: list(primitive()),
    root: primitive(),
    validationFunction: usingModelSchema(V1_rawLambdaModelSchema),
});
// ------------------------------------- Model-to-model Mapping -------------------------------------
const purePropertyMappingModelSchema = createModelSchema(V1_PurePropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.PURE),
    enumMappingId: optional(primitive()),
    explodeProperty: optional(primitive()),
    localMappingProperty: usingModelSchema(V1_localMappingPropertyInfoModelSchema),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    source: primitive(),
    target: optional(primitive()),
    transform: usingModelSchema(V1_rawLambdaModelSchema),
});
function V1_serializePurePropertyMapping(protocol) {
    if (protocol instanceof V1_PurePropertyMapping) {
        return serialize(purePropertyMappingModelSchema, protocol);
    }
    return SKIP;
}
function V1_deserializePurePropertyMapping(json) {
    switch (json._type) {
        case V1_PropertyMappingType.PURE:
            return deserialize(purePropertyMappingModelSchema, json);
        default:
            return SKIP;
    }
}
const pureInstanceClassMappingModelSchema = createModelSchema(V1_PureInstanceClassMapping, {
    _type: usingConstantValueSchema(V1_ClassMappingType.PUREINSTANCE),
    class: primitive(),
    extendsClassMappingId: optional(primitive()),
    filter: usingModelSchema(V1_rawLambdaModelSchema),
    id: optional(primitive()),
    propertyMappings: list(custom(V1_serializePurePropertyMapping, V1_deserializePurePropertyMapping)),
    root: primitive(),
    srcClass: optional(primitive()),
});
// ------------------------------------- Relational Mapping -------------------------------------
// NOTE: Order matters. V1_RootRelationalClassMapping model schema should be defined before V1_RelationalClassMapping
// since V1_RootRelationalClassMapping extends V1_RelationalClassMapping and thus the model schemas will get overridden and mix the order of the properties
const rootRelationalClassMappingModelSchema = createModelSchema(V1_RootRelationalClassMapping, {
    _type: usingConstantValueSchema(V1_ClassMappingType.ROOT_RELATIONAL),
    class: primitive(),
    distinct: primitive(),
    extendsClassMappingId: optional(primitive()),
    filter: usingModelSchema(V1_filterMappingModelSchema),
    groupBy: customList(V1_serializeRelationalOperationElement, V1_deserializeRelationalOperationElement, { INTERNAL__forceReturnEmptyInTest: true }),
    id: optional(primitive()),
    mainTable: usingModelSchema(V1_tablePtrModelSchema),
    primaryKey: list(custom(V1_serializeRelationalOperationElement, V1_deserializeRelationalOperationElement)),
    propertyMappings: list(custom(V1_serializeRelationalPropertyMapping, V1_deserializeRelationalPropertyMapping)),
    root: optional(primitive()),
});
const relationalClassMappingModelSchema = createModelSchema(V1_RelationalClassMapping, {
    _type: usingConstantValueSchema(V1_ClassMappingType.RELATIONAL),
    class: optional(primitive()),
    extendsClassMappingId: optional(primitive()),
    id: optional(primitive()),
    primaryKey: list(custom((val) => V1_serializeRelationalOperationElement(val), (val) => V1_deserializeRelationalOperationElement(val))),
    propertyMappings: list(custom((val) => V1_serializeRelationalPropertyMapping(val), (val) => V1_deserializeRelationalPropertyMapping(val))),
    root: optional(primitive()),
});
const bindingTransformerModelSchema = createModelSchema(V1_BindingTransformer, {
    binding: primitive(),
});
const relationalPropertyMappingModelSchema = createModelSchema(V1_RelationalPropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.RELATIONAL),
    bindingTransformer: optionalCustom((val) => serialize(bindingTransformerModelSchema, val), (val) => deserialize(bindingTransformerModelSchema, val)),
    enumMappingId: optional(primitive()),
    localMappingProperty: usingModelSchema(V1_localMappingPropertyInfoModelSchema),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    relationalOperation: raw(),
    source: optional(primitive()),
    target: optional(primitive()),
});
const flatDataAssociationPropertyMappingModelSchema = createModelSchema(V1_FlatDataAssociationPropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.ASSOCIATION_FLAT_DATA),
    flatData: primitive(),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    sectionName: primitive(),
    source: optional(primitive()),
    target: optional(primitive()),
});
const embeddedRelationalPropertyMappingModelSchema = createModelSchema(V1_EmbeddedRelationalPropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.EMBEDDED_RELATIONAL),
    classMapping: usingModelSchema(relationalClassMappingModelSchema),
    id: optional(primitive()),
    localMappingProperty: usingModelSchema(V1_localMappingPropertyInfoModelSchema),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    /**
     * Omit this information during protocol transformation as it can be
     * interpreted while building the graph; and will help grammar-roundtrip
     * tests (involving engine) to pass. Ideally, this requires grammar parser
     * and composer in engine to be more consistent.
     *
     * @discrepancy grammar-roundtrip
     */
    source: optional(primitive()),
    target: optional(primitive()),
});
const otherwiseEmbeddedRelationalPropertyMappingModelSchema = createModelSchema(V1_OtherwiseEmbeddedRelationalPropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.OTHERWISE_EMBEDDED_RELATIONAL),
    classMapping: usingModelSchema(relationalClassMappingModelSchema),
    localMappingProperty: usingModelSchema(V1_localMappingPropertyInfoModelSchema),
    otherwisePropertyMapping: custom(V1_serializeRelationalPropertyMapping, V1_deserializeRelationalPropertyMapping),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    /**
     * Omit this information during protocol transformation as it can be
     * interpreted while building the graph; and will help grammar-roundtrip
     * tests (involving engine) to pass. Ideally, this requires grammar parser
     * and composer in engine to be more consistent.
     *
     * @discrepancy grammar-roundtrip
     */
    source: optional(primitive()),
    target: optional(primitive()),
});
TEMPORARY__disableModelSchemaExtensionMechanism(otherwiseEmbeddedRelationalPropertyMappingModelSchema);
const inlineEmbeddedPropertyMappingModelSchema = createModelSchema(V1_InlineEmbeddedPropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.INLINE_EMBEDDED_RELATIONAL),
    id: optional(primitive()),
    localMappingProperty: usingModelSchema(V1_localMappingPropertyInfoModelSchema),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    /**
     * Omit this information during protocol transformation as it can be
     * interpreted while building the graph; and will help grammar-roundtrip
     * tests (involving engine) to pass. Ideally, this requires grammar parser
     * and composer in engine to be more consistent.
     *
     * @discrepancy grammar-roundtrip
     */
    source: optional(primitive()),
    setImplementationId: primitive(),
    target: optional(primitive()),
});
const xStorePropertyMappingModelSchema = createModelSchema(V1_XStorePropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.XSTORE),
    crossExpression: usingModelSchema(V1_rawLambdaModelSchema),
    localMappingProperty: usingModelSchema(V1_localMappingPropertyInfoModelSchema),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    source: primitive(),
    target: optional(primitive()),
});
function V1_serializeRelationalPropertyMapping(protocol) {
    if (protocol instanceof V1_RelationalPropertyMapping) {
        return serialize(relationalPropertyMappingModelSchema, protocol);
    }
    else if (protocol instanceof V1_OtherwiseEmbeddedRelationalPropertyMapping) {
        return serialize(otherwiseEmbeddedRelationalPropertyMappingModelSchema, protocol);
    }
    else if (protocol instanceof V1_EmbeddedRelationalPropertyMapping) {
        return serialize(embeddedRelationalPropertyMappingModelSchema, protocol);
    }
    else if (protocol instanceof V1_InlineEmbeddedPropertyMapping) {
        return serialize(inlineEmbeddedPropertyMappingModelSchema, protocol);
    }
    else if (protocol instanceof V1_XStorePropertyMapping) {
        return serialize(xStorePropertyMappingModelSchema, protocol);
    }
    return SKIP;
}
function V1_deserializeRelationalPropertyMapping(json) {
    switch (json._type) {
        case V1_PropertyMappingType.RELATIONAL:
            return deserialize(relationalPropertyMappingModelSchema, json);
        case V1_PropertyMappingType.EMBEDDED_RELATIONAL:
            return deserialize(embeddedRelationalPropertyMappingModelSchema, json);
        case V1_PropertyMappingType.OTHERWISE_EMBEDDED_RELATIONAL:
            return deserialize(otherwiseEmbeddedRelationalPropertyMappingModelSchema, json);
        case V1_PropertyMappingType.INLINE_EMBEDDED_RELATIONAL:
            return deserialize(inlineEmbeddedPropertyMappingModelSchema, json);
        case V1_PropertyMappingType.XSTORE:
            return deserialize(xStorePropertyMappingModelSchema, json);
        default:
            return SKIP;
    }
}
// ------------------------------------- Flat-data Mapping -------------------------------------
const flatDataPropertyMappingModelSchema = createModelSchema(V1_FlatDataPropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.FLAT_DATA),
    enumMappingId: optional(primitive()),
    localMappingProperty: usingModelSchema(V1_localMappingPropertyInfoModelSchema),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    source: primitive(),
    target: optional(primitive()),
    transform: usingModelSchema(V1_rawLambdaModelSchema),
});
const embeddedFlatDataPropertyMappingModelSchema = createModelSchema(V1_EmbeddedFlatDataPropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.EMBEDDED_FLAT_DATA),
    class: primitive(),
    id: optional(primitive()),
    localMappingProperty: usingModelSchema(V1_localMappingPropertyInfoModelSchema),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    propertyMappings: list(custom(V1_serializeFlatDataPropertyMapping, V1_deserializeFlatDataPropertyMapping)),
    root: primitive(),
    source: primitive(),
    target: optional(primitive()),
});
function V1_serializeFlatDataPropertyMapping(protocol) {
    if (protocol instanceof V1_FlatDataPropertyMapping) {
        return serialize(flatDataPropertyMappingModelSchema, protocol);
    }
    else if (protocol instanceof V1_EmbeddedFlatDataPropertyMapping) {
        return serialize(embeddedFlatDataPropertyMappingModelSchema, protocol);
    }
    return SKIP;
}
function V1_deserializeFlatDataPropertyMapping(json) {
    switch (json._type) {
        case V1_PropertyMappingType.FLAT_DATA:
            return deserialize(flatDataPropertyMappingModelSchema, json);
        case V1_PropertyMappingType.EMBEDDED_FLAT_DATA:
            return deserialize(embeddedFlatDataPropertyMappingModelSchema, json);
        default:
            return SKIP;
    }
}
const rootFlatDataCLassMappingModelSchema = createModelSchema(V1_RootFlatDataClassMapping, {
    _type: usingConstantValueSchema(V1_ClassMappingType.ROOT_FLAT_DATA),
    class: primitive(),
    extendsClassMappingId: optional(primitive()),
    filter: usingModelSchema(V1_rawLambdaModelSchema),
    flatData: primitive(),
    id: optional(primitive()),
    propertyMappings: list(custom(V1_serializeFlatDataPropertyMapping, V1_deserializeFlatDataPropertyMapping)),
    root: primitive(),
    sectionName: primitive(),
});
// ------------------------------------- Aggregation Aware Mapping -------------------------------------
const aggregationAwarePropertyMappingModelSchema = createModelSchema(V1_AggregationAwarePropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.AGGREGATION_AWARE),
    localMappingProperty: usingModelSchema(V1_localMappingPropertyInfoModelSchema),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    source: optional(primitive()),
    target: optional(primitive()),
});
const aggregateFunctionModelSchema = createModelSchema(V1_AggregateFunction, {
    aggregateFn: usingModelSchema(V1_rawLambdaModelSchema),
    mapFn: usingModelSchema(V1_rawLambdaModelSchema),
});
const groupByFunctionModelSchema = createModelSchema(V1_GroupByFunction, {
    groupByFn: usingModelSchema(V1_rawLambdaModelSchema),
});
const aggregateSpecificationModelSchema = createModelSchema(V1_AggregateSpecification, {
    aggregateValues: list(usingModelSchema(aggregateFunctionModelSchema)),
    canAggregate: primitive(),
    groupByFunctions: list(usingModelSchema(groupByFunctionModelSchema)),
});
const aggregateSetImplementationContainer = (plugins) => createModelSchema(V1_AggregateSetImplementationContainer, {
    aggregateSpecification: usingModelSchema(aggregateSpecificationModelSchema),
    index: primitive(),
    setImplementation: custom((val) => V1_serializeClassMapping(val, plugins), (val) => V1_deserializeClassMapping(val, plugins)),
});
function V1_serializeAggregationAwarePropertyMapping(protocol) {
    if (protocol instanceof V1_AggregationAwarePropertyMapping) {
        return serialize(aggregationAwarePropertyMappingModelSchema, protocol);
    }
    return SKIP;
}
function V1_deserializeAggregationAwarePropertyMapping(json) {
    switch (json._type) {
        case V1_PropertyMappingType.AGGREGATION_AWARE:
            return deserialize(aggregationAwarePropertyMappingModelSchema, json);
        default:
            return SKIP;
    }
}
const aggregationAwareClassMappingModelSchema = (plugins) => createModelSchema(V1_AggregationAwareClassMapping, {
    _type: usingConstantValueSchema(V1_ClassMappingType.AGGREGATION_AWARE),
    aggregateSetImplementations: list(usingModelSchema(aggregateSetImplementationContainer(plugins))),
    class: primitive(),
    extendsClassMappingId: optional(primitive()),
    id: optional(primitive()),
    mainSetImplementation: custom((val) => V1_serializeClassMapping(val, plugins), (val) => V1_deserializeClassMapping(val, plugins)),
    propertyMappings: list(custom(V1_serializeAggregationAwarePropertyMapping, V1_deserializeAggregationAwarePropertyMapping)),
    root: primitive(),
});
// ------------------------------------- Relation Function Mapping -------------------------------------
const relationFunctionPropertyMappingModelSchema = createModelSchema(V1_RelationFunctionPropertyMapping, {
    _type: usingConstantValueSchema(V1_PropertyMappingType.RELATION_FUNCTION),
    localMappingProperty: usingModelSchema(V1_localMappingPropertyInfoModelSchema),
    property: usingModelSchema(V1_propertyPointerModelSchema),
    source: optional(primitive()),
    target: optional(primitive()),
    column: primitive(),
    bindingTransformer: optionalCustom((val) => serialize(bindingTransformerModelSchema, val), (val) => deserialize(bindingTransformerModelSchema, val)),
});
function V1_serializeRelationFunctionPropertyMapping(protocol) {
    return serialize(relationFunctionPropertyMappingModelSchema, protocol);
}
function V1_deserializeRelationFunctionPropertyMapping(json) {
    switch (json._type) {
        case V1_PropertyMappingType.RELATION_FUNCTION:
            return deserialize(relationFunctionPropertyMappingModelSchema, json);
        default:
            return SKIP;
    }
}
const relationFunctionClassMappingModelSchema = createModelSchema(V1_RelationFunctionClassMapping, {
    _type: usingConstantValueSchema(V1_ClassMappingType.RELATION_FUNCTION),
    class: primitive(),
    extendsClassMappingId: optional(primitive()),
    id: optional(primitive()),
    propertyMappings: list(custom(V1_serializeRelationFunctionPropertyMapping, V1_deserializeRelationFunctionPropertyMapping)),
    root: primitive(),
    relationFunction: usingModelSchema(V1_packageableElementPointerModelSchema),
});
// ------------------------------------- Class Mapping -------------------------------------
function V1_serializeClassMapping(value, plugins) {
    if (value instanceof V1_INTERNAL__UnknownClassMapping) {
        return value.content;
    }
    else if (value instanceof V1_MergeOperationClassMapping) {
        return serialize(mergeOperationClassMappingModelSchema, value);
    }
    else if (value instanceof V1_OperationClassMapping) {
        return serialize(operationClassMappingModelSchema, value);
    }
    else if (value instanceof V1_PureInstanceClassMapping) {
        return serialize(pureInstanceClassMappingModelSchema, value);
    }
    else if (value instanceof V1_RootFlatDataClassMapping) {
        return serialize(rootFlatDataCLassMappingModelSchema, value);
    }
    else if (value instanceof V1_RootRelationalClassMapping) {
        return serialize(rootRelationalClassMappingModelSchema, value);
    }
    else if (value instanceof V1_RelationalClassMapping) {
        return serialize(relationalClassMappingModelSchema, value);
    }
    else if (value instanceof V1_AggregationAwareClassMapping) {
        return serialize(aggregationAwareClassMappingModelSchema(plugins), value);
    }
    else if (value instanceof V1_RelationFunctionClassMapping) {
        return serialize(relationFunctionClassMappingModelSchema, value);
    }
    const extraClassMappingSerializers = plugins.flatMap((plugin) => plugin.V1_getExtraClassMappingSerializers?.() ?? []);
    for (const serializer of extraClassMappingSerializers) {
        const json = serializer(value);
        if (json) {
            return json;
        }
    }
    throw new UnsupportedOperationError(`Can't serialize class mapping: no compatible serializer available from plugins`, value);
}
const V1_INTERNAL__UnknownClassMappingModelSchema = createModelSchema(V1_INTERNAL__UnknownClassMapping, {
    class: primitive(),
    id: optional(primitive()),
    root: primitive(),
});
function V1_deserializeClassMapping(json, plugins) {
    switch (json._type) {
        case V1_ClassMappingType.MERGE_OPERATION:
            return deserialize(mergeOperationClassMappingModelSchema, json);
        case V1_ClassMappingType.OPERATION:
            return deserialize(operationClassMappingModelSchema, json);
        case V1_ClassMappingType.PUREINSTANCE:
            return deserialize(pureInstanceClassMappingModelSchema, json);
        case V1_ClassMappingType.ROOT_FLAT_DATA:
            return deserialize(rootFlatDataCLassMappingModelSchema, json);
        case V1_ClassMappingType.ROOT_RELATIONAL:
            return deserialize(rootRelationalClassMappingModelSchema, json);
        case V1_ClassMappingType.RELATIONAL:
            return deserialize(relationalClassMappingModelSchema, json);
        case V1_ClassMappingType.AGGREGATION_AWARE:
            return deserialize(aggregationAwareClassMappingModelSchema(plugins), json);
        case V1_ClassMappingType.RELATION_FUNCTION:
            return deserialize(relationFunctionClassMappingModelSchema, json);
        default: {
            const extraClassMappingDeserializers = plugins.flatMap((plugin) => plugin.V1_getExtraClassMappingDeserializers?.() ?? []);
            for (const deserializer of extraClassMappingDeserializers) {
                const protocol = deserializer(json);
                if (protocol) {
                    return protocol;
                }
            }
            // Fall back to create unknown stub if not supported
            const protocol = deserialize(V1_INTERNAL__UnknownClassMappingModelSchema, json);
            protocol.content = json;
            return protocol;
        }
    }
}
// ------------------------------------- Mapping Test -------------------------------------
var V1_InputDataType;
(function (V1_InputDataType) {
    V1_InputDataType["OBJECT"] = "object";
    V1_InputDataType["FLAT_DATA"] = "flatData";
    V1_InputDataType["RELATIONAL"] = "relational";
})(V1_InputDataType || (V1_InputDataType = {}));
var V1_MappingTestAssertType;
(function (V1_MappingTestAssertType) {
    V1_MappingTestAssertType["EXPECTED_OUTPUT_MAPPING_TEST_ASSERT"] = "expectedOutputMappingTestAssert";
})(V1_MappingTestAssertType || (V1_MappingTestAssertType = {}));
const V1_objectInputData = createModelSchema(V1_DEPRECATED__ObjectInputData, {
    _type: usingConstantValueSchema(V1_InputDataType.OBJECT),
    data: primitive(),
    inputType: primitive(),
    sourceClass: primitive(),
});
const V1_flatDataInputData = createModelSchema(V1_DEPRECATED__FlatDataInputData, {
    _type: usingConstantValueSchema(V1_InputDataType.FLAT_DATA),
    data: primitive(),
    sourceFlatData: usingModelSchema(V1_packageableElementPointerModelSchema),
});
const V1_relationalInputData = createModelSchema(V1_DEPRECATED__RelationalInputData, {
    _type: usingConstantValueSchema(V1_InputDataType.RELATIONAL),
    data: primitive(),
    database: primitive(),
    inputType: primitive(),
});
const V1_expectedOutputMappingTestAssertModelSchema = createModelSchema(V1_DEPRECATED__ExpectedOutputMappingTestAssert, {
    _type: usingConstantValueSchema(V1_MappingTestAssertType.EXPECTED_OUTPUT_MAPPING_TEST_ASSERT),
    expectedOutput: primitive(),
});
const V1_serializeInputData = (protocol) => {
    if (protocol instanceof V1_DEPRECATED__ObjectInputData) {
        return serialize(V1_objectInputData, protocol);
    }
    else if (protocol instanceof V1_DEPRECATED__FlatDataInputData) {
        return serialize(V1_flatDataInputData, protocol);
    }
    else if (protocol instanceof V1_DEPRECATED__RelationalInputData) {
        return serialize(V1_relationalInputData, protocol);
    }
    throw new UnsupportedOperationError(`Can't serialize mapping test input data`, protocol);
};
const V1_deserializeInputData = (json) => {
    switch (json._type) {
        case V1_InputDataType.OBJECT:
            return deserialize(V1_objectInputData, json);
        case V1_InputDataType.FLAT_DATA:
            return deserialize(V1_flatDataInputData, json);
        case V1_InputDataType.RELATIONAL:
            return deserialize(V1_relationalInputData, json);
        default:
            throw new UnsupportedOperationError(`Can't deserialize mapping test input data of type '${json._type}'`);
    }
};
const V1_serializeTestAssert = (protocol) => {
    if (protocol instanceof V1_DEPRECATED__ExpectedOutputMappingTestAssert) {
        return serialize(V1_expectedOutputMappingTestAssertModelSchema, protocol);
    }
    throw new UnsupportedOperationError(`Can't serialize mapping test assert`, protocol);
};
const V1_deserializeTestAssert = (json) => {
    switch (json._type) {
        case V1_MappingTestAssertType.EXPECTED_OUTPUT_MAPPING_TEST_ASSERT:
            return deserialize(V1_expectedOutputMappingTestAssertModelSchema, json);
        default:
            throw new UnsupportedOperationError(`Can't deserialize mapping test assert of type '${json._type}'`);
    }
};
const V1_mappingTestModelLegacySchema = createModelSchema(V1_DEPRECATED__MappingTest, {
    assert: custom(V1_serializeTestAssert, V1_deserializeTestAssert),
    inputData: list(custom(V1_serializeInputData, V1_deserializeInputData)),
    name: primitive(),
    query: usingModelSchema(V1_rawLambdaModelSchema),
});
export const V1_mappingStoreTestDataModelSchema = (plugins) => createModelSchema(V1_MappingStoreTestData, {
    data: custom((val) => V1_serializeEmbeddedDataType(val, plugins), (val) => V1_deserializeEmbeddedDataType(val, plugins)),
    store: custom((val) => serialize(V1_packageableElementPointerModelSchema, val), (val) => V1_serializePackageableElementPointer(val, PackageableElementPointerType.STORE)),
});
export const V1_mappingTestModelSchema = (plugins) => createModelSchema(V1_MappingTest, {
    _type: usingConstantValueSchema(ATOMIC_TEST_TYPE.Mapping_Test),
    assertions: list(custom(V1_serializeTestAssertion, V1_deserializeTestAssertion)),
    doc: optional(primitive()),
    id: primitive(),
    storeTestData: usingModelSchema(V1_mappingStoreTestDataModelSchema(plugins)),
});
export const V1_mappingTestSuiteModelSchema = (plugins) => createModelSchema(V1_MappingTestSuite, {
    _type: usingConstantValueSchema(V1_TestSuiteType.MAPPING_TEST_SUITE),
    doc: optional(primitive()),
    id: primitive(),
    func: usingModelSchema(V1_rawLambdaModelSchema),
    tests: list(custom((val) => V1_serializeAtomicTest(val, plugins), (val) => V1_deserializeAtomicTest(val, plugins))),
});
// ------------------------------------- Association Mapping -------------------------------------
var V1_AssociationMappingType;
(function (V1_AssociationMappingType) {
    V1_AssociationMappingType["RELATIONAL"] = "relational";
    V1_AssociationMappingType["XSTORE"] = "xStore";
    V1_AssociationMappingType["FLAT_DATA"] = "flatData";
})(V1_AssociationMappingType || (V1_AssociationMappingType = {}));
const V1_serializeAssociationPropertyMapping = (protocol) => {
    if (protocol instanceof V1_RelationalPropertyMapping) {
        return serialize(relationalPropertyMappingModelSchema, protocol);
    }
    else if (protocol instanceof V1_XStorePropertyMapping) {
        return serialize(xStorePropertyMappingModelSchema, protocol);
    }
    else if (protocol instanceof V1_FlatDataAssociationPropertyMapping) {
        return serialize(flatDataAssociationPropertyMappingModelSchema, protocol);
    }
    return SKIP;
};
const V1_deserializeAssociationPropertyMapping = (json) => {
    switch (json._type) {
        case V1_PropertyMappingType.RELATIONAL:
            return deserialize(relationalPropertyMappingModelSchema, json);
        case V1_PropertyMappingType.XSTORE:
            return deserialize(xStorePropertyMappingModelSchema, json);
        case V1_PropertyMappingType.ASSOCIATION_FLAT_DATA:
            return deserialize(flatDataAssociationPropertyMappingModelSchema, json);
        default:
            return SKIP;
    }
};
const relationalAssociationMappingModelschema = createModelSchema(V1_RelationalAssociationMapping, {
    _type: usingConstantValueSchema(V1_AssociationMappingType.RELATIONAL),
    association: custom((val) => serialize(V1_packageableElementPointerModelSchema, val), (val) => V1_serializePackageableElementPointer(val, PackageableElementPointerType.ASSOCIATION)),
    id: optional(primitive()),
    propertyMappings: list(custom(V1_serializeAssociationPropertyMapping, V1_deserializeAssociationPropertyMapping)),
    stores: list(primitive()),
});
const flatDataAssociationMappingModelschema = createModelSchema(V1_FlatDataAssociationMapping, {
    _type: usingConstantValueSchema(V1_AssociationMappingType.FLAT_DATA),
    association: custom((val) => serialize(V1_packageableElementPointerModelSchema, val), (val) => V1_serializePackageableElementPointer(val, PackageableElementPointerType.ASSOCIATION)),
    id: optional(primitive()),
    propertyMappings: list(custom(V1_serializeAssociationPropertyMapping, V1_deserializeAssociationPropertyMapping)),
    stores: list(primitive()),
});
const xStoreAssociationMappingModelschema = createModelSchema(V1_XStoreAssociationMapping, {
    _type: usingConstantValueSchema(V1_AssociationMappingType.XSTORE),
    association: custom((val) => serialize(V1_packageableElementPointerModelSchema, val), (val) => V1_serializePackageableElementPointer(val, PackageableElementPointerType.ASSOCIATION)),
    id: optional(primitive()),
    propertyMappings: list(custom(V1_serializeAssociationPropertyMapping, V1_deserializeAssociationPropertyMapping)),
    stores: list(primitive()),
});
const V1_serializeAssociationMapping = (protocol) => {
    if (protocol instanceof V1_RelationalAssociationMapping) {
        return serialize(relationalAssociationMappingModelschema, protocol);
    }
    else if (protocol instanceof V1_XStoreAssociationMapping) {
        return serialize(xStoreAssociationMappingModelschema, protocol);
    }
    else if (protocol instanceof V1_FlatDataAssociationMapping) {
        return serialize(flatDataAssociationMappingModelschema, protocol);
    }
    throw new UnsupportedOperationError(`Can't serialize association mapping`, protocol);
};
const V1_deserializeAssociationMapping = (json) => {
    switch (json._type) {
        case V1_AssociationMappingType.RELATIONAL:
            return deserialize(relationalAssociationMappingModelschema, json);
        case V1_AssociationMappingType.XSTORE:
            return deserialize(xStoreAssociationMappingModelschema, json);
        case V1_AssociationMappingType.FLAT_DATA:
            return deserialize(flatDataAssociationMappingModelschema, json);
        default:
            throw new UnsupportedOperationError(`Can't deserialize association mapping of type '${json._type}'`);
    }
};
// ------------------------------------- Enumeration Mapping -------------------------------------
var V1_EnumValueMappingSourceValueType;
(function (V1_EnumValueMappingSourceValueType) {
    V1_EnumValueMappingSourceValueType["STRING"] = "stringSourceValue";
    V1_EnumValueMappingSourceValueType["INTEGER"] = "integerSourceValue";
    V1_EnumValueMappingSourceValueType["ENUM"] = "enumSourceValue";
})(V1_EnumValueMappingSourceValueType || (V1_EnumValueMappingSourceValueType = {}));
const enumValueMappingStringSourceValueModelSchema = createModelSchema(V1_EnumValueMappingStringSourceValue, {
    _type: usingConstantValueSchema(V1_EnumValueMappingSourceValueType.STRING),
    value: primitive(),
});
const enumValueMappingIntegerSourceValueModelSchema = createModelSchema(V1_EnumValueMappingIntegerSourceValue, {
    _type: usingConstantValueSchema(V1_EnumValueMappingSourceValueType.INTEGER),
    value: primitive(),
});
const enumValueMappingEnumSourceValueeModelSchema = createModelSchema(V1_EnumValueMappingEnumSourceValue, {
    _type: usingConstantValueSchema(V1_EnumValueMappingSourceValueType.ENUM),
    enumeration: primitive(),
    value: primitive(),
});
const serializeEnumValueMappingSourceValue = (protocol) => {
    if (protocol instanceof V1_EnumValueMappingStringSourceValue) {
        return serialize(enumValueMappingStringSourceValueModelSchema, protocol);
    }
    else if (protocol instanceof V1_EnumValueMappingIntegerSourceValue) {
        return serialize(enumValueMappingIntegerSourceValueModelSchema, protocol);
    }
    else if (protocol instanceof V1_EnumValueMappingEnumSourceValue) {
        return serialize(enumValueMappingEnumSourceValueeModelSchema, protocol);
    }
    throw new UnsupportedOperationError(`Can't serialize enum value mapping source value`, protocol);
};
const V1_deserializeEnumValueMappingSourceValue = (json, context) => {
    if (context.args) {
        // NOTE: we cannot use `instanceof` here since it will cause circular dependency
        const parentEnumerationMapping = context.args;
        if (parentEnumerationMapping.sourceType) {
            switch (parentEnumerationMapping.sourceType) {
                case PRIMITIVE_TYPE.STRING: {
                    const sourceValue = new V1_EnumValueMappingStringSourceValue();
                    sourceValue.value = guaranteeIsString(json, 'Enum value mapping string source value must be a string');
                    return sourceValue;
                }
                case PRIMITIVE_TYPE.INTEGER: {
                    const sourceValue = new V1_EnumValueMappingIntegerSourceValue();
                    sourceValue.value = guaranteeIsNumber(json, 'Enum value mapping integer source value must be a number');
                    return sourceValue;
                }
                default: {
                    const sourceValue = new V1_EnumValueMappingEnumSourceValue();
                    assertTrue(isNonNullable(parentEnumerationMapping.sourceType) &&
                        typeof parentEnumerationMapping.sourceType === 'string', 'Enum value mapping enumeration source value enumeration must be a string');
                    sourceValue.enumeration = parentEnumerationMapping.sourceType;
                    sourceValue.value = guaranteeIsString(json, 'Enum value mapping enumeration source value must be a string');
                    return sourceValue;
                }
            }
        }
        switch (json._type) {
            case V1_EnumValueMappingSourceValueType.STRING:
                return deserialize(enumValueMappingStringSourceValueModelSchema, json);
            case V1_EnumValueMappingSourceValueType.INTEGER:
                return deserialize(enumValueMappingIntegerSourceValueModelSchema, json);
            case V1_EnumValueMappingSourceValueType.ENUM:
                return deserialize(enumValueMappingEnumSourceValueeModelSchema, json);
            // NOTE: we might need to work on this since this is not backward compatible
            default:
                throw new UnsupportedOperationError(`Can't deserialize enum value mapping source value of type '${json._type}'`);
        }
    }
    throw new IllegalStateError(`Deserialization parent context is not defined. Got: ${shallowStringify(context)}`);
};
const enumValueMappingModelSchema = createModelSchema(V1_EnumValueMapping, {
    enumValue: primitive(),
    sourceValues: list(custom(serializeEnumValueMappingSourceValue, (value, context) => V1_deserializeEnumValueMappingSourceValue(value, context))), //TODO look into why args is private in context
});
const V1_enumerationMappingModelSchema = createModelSchema(V1_EnumerationMapping, {
    enumValueMappings: list(custom((value) => serialize(enumValueMappingModelSchema, value), (value, context) => deserialize(enumValueMappingModelSchema, value, undefined, context.target))),
    enumeration: custom((val) => serialize(V1_packageableElementPointerModelSchema, val), (val) => V1_serializePackageableElementPointer(val, PackageableElementPointerType.ENUMERATION)),
    id: optional(primitive()),
});
// ------------------------------------- Mapping -------------------------------------
export const V1_MAPPING_ELEMENT_PROTOCOL_TYPE = 'mapping';
const V1_MAPPING_INCLUDE_MAPPING_TYPE = 'mappingIncludeMapping';
const V1_mappingIncludeMappingModelSchema = createModelSchema(V1_MappingIncludeMapping, {
    _type: usingConstantValueSchema(V1_MAPPING_INCLUDE_MAPPING_TYPE),
    includedMapping: primitive(),
    sourceDatabasePath: optional(primitive()),
    targetDatabasePath: optional(primitive()),
});
const V1_serializeMappingInclude = (protocol, plugins) => {
    if (protocol instanceof V1_INTERNAL__UnknownMappingInclude) {
        return protocol.content;
    }
    else if (protocol instanceof V1_MappingIncludeDataProduct) {
        return serialize(V1_mappingIncludeDataProductModelSchema, protocol);
    }
    else if (protocol instanceof V1_MappingIncludeMapping) {
        return serialize(V1_mappingIncludeMappingModelSchema, protocol);
    }
    const extraMappingIncludeSerializers = plugins.flatMap((plugin) => plugin.V1_getExtraMappingIncludeProtocolSerializers?.() ?? []);
    for (const serializer of extraMappingIncludeSerializers) {
        const json = serializer(protocol);
        if (json) {
            return json;
        }
    }
    throw new UnsupportedOperationError(`Can't serialize mapping include: no compatible serializer available from plugins`, protocol);
};
const V1_deserializeMappingInclude = (json, plugins) => {
    if (json._type === V1_MAPPING_INCLUDE_DATAPRODUCT_TYPE) {
        return deserialize(V1_mappingIncludeDataProductModelSchema, json);
    }
    if (!json._type || json._type === V1_MAPPING_INCLUDE_MAPPING_TYPE) {
        return deserialize(V1_mappingIncludeMappingModelSchema, {
            ...json,
            /** @backwardCompatibility */
            includedMapping: json.includedMapping ??
                `${json.includedMappingPackage}${ELEMENT_PATH_DELIMITER}${json.includedMappingName}`,
        });
    }
    const extraMappingIncludeDeserializers = plugins.flatMap((plugin) => plugin.V1_getExtraMappingIncludeProtocolDeserializers?.() ?? []);
    for (const deserializer of extraMappingIncludeDeserializers) {
        const protocol = deserializer(json);
        if (protocol) {
            return protocol;
        }
    }
    // Fall back to create unknown stub if not supported
    const protocol = new V1_INTERNAL__UnknownMappingInclude();
    protocol.content = json;
    return protocol;
};
export const V1_mappingModelSchema = (plugins) => createModelSchema(V1_Mapping, {
    _type: usingConstantValueSchema(V1_MAPPING_ELEMENT_PROTOCOL_TYPE),
    associationMappings: customList(V1_serializeAssociationMapping, V1_deserializeAssociationMapping, {
        INTERNAL__forceReturnEmptyInTest: true,
    }),
    classMappings: list(custom((val) => V1_serializeClassMapping(val, plugins), (val) => V1_deserializeClassMapping(val, plugins))),
    enumerationMappings: list(usingModelSchema(V1_enumerationMappingModelSchema)),
    includedMappings: list(custom((val) => V1_serializeMappingInclude(val, plugins), (val) => V1_deserializeMappingInclude(val, plugins))),
    name: primitive(),
    package: primitive(),
    testSuites: optionalCustomList((value) => V1_serializeTestSuite(value, plugins), (value) => V1_deserializeTestSuite(value, plugins)),
    tests: list(usingModelSchema(V1_mappingTestModelLegacySchema)),
});
//# sourceMappingURL=V1_MappingSerializationHelper.js.map