var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
    if (value !== null && value !== void 0) {
        if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
        var dispose, inner;
        if (async) {
            if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
            dispose = value[Symbol.asyncDispose];
        }
        if (dispose === void 0) {
            if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
            dispose = value[Symbol.dispose];
            if (async) inner = dispose;
        }
        if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
        if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
        env.stack.push({ value: value, dispose: dispose, async: async });
    }
    else if (async) {
        env.stack.push({ async: true });
    }
    return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
    return function (env) {
        function fail(e) {
            env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
            env.hasError = true;
        }
        var r, s = 0;
        function next() {
            while (r = env.stack.pop()) {
                try {
                    if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
                    if (r.dispose) {
                        var result = r.dispose.call(r.value);
                        if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
                    }
                    else s |= 1;
                }
                catch (e) {
                    fail(e);
                }
            }
            if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
            if (env.hasError) throw env.error;
        }
        return next();
    };
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
    var e = new Error(message);
    return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
import { Schema, SchemaItemType, SchemaKey } from "@itwin/ecschema-metadata";
import { expect, use } from "chai";
import { TestContext } from "./TestContext";
import { IModelIncrementalSchemaLocater } from "../../IModelIncrementalSchemaLocater";
import * as deepEqualInAnyOrder from "deep-equal-in-any-order";
use(deepEqualInAnyOrder);
function findItem(name, rowData) {
    const item = rowData.find((i) => i.name === name);
    if (!item)
        throw new Error(`Could not find schema item '${name}'`);
    return item;
}
function findProperty(name, rowData) {
    return rowData.find((i) => i.name === name);
}
function isECClass(item) {
    return item.schemaItemType === SchemaItemType.EntityClass || item.schemaItemType === SchemaItemType.Mixin || item.schemaItemType === SchemaItemType.RelationshipClass ||
        item.schemaItemType === SchemaItemType.StructClass || item.schemaItemType === SchemaItemType.CustomAttributeClass;
}
function isRelationshipClass(item) {
    return "source" in item && "target" in item;
}
/**
 * A test locater that exposes the protected methods of IModelIncrementalSchemaLocater for granular testing.
 */
class TestSchemaLocater extends IModelIncrementalSchemaLocater {
}
describe("ECSql query tests", function () {
    function validateItem(name, itemPropObjects, schema) {
        const actualJson = findItem(name, itemPropObjects);
        const expectedItem = schema.getItemSync(name);
        const expectedJson = expectedItem.toJSON();
        // The following code exists because some data coming from the database will not match the
        // data from the context due to default values. This is OK as long as the conditions are
        // correct. For instance, schemaItem name will not exist in serialized JSON, but does exist
        // coming from the DB. RelationshipConstraint's AbstractConstraint is set when only one
        // constraint class exists coming from the database, but a serialized Relationship will not
        // contain the abstract constraint. The one constraint is 'assumed' to be the abstract constraint.
        expect(actualJson.name).to.equal(expectedItem?.name);
        delete actualJson.name;
        if (isECClass(actualJson)) {
            if (expectedJson.schemaItemType === "Mixin") {
                expect(actualJson.modifier).to.be.oneOf([undefined, 'Abstract']);
                delete actualJson.modifier;
            }
            else if (expectedJson.modifier === undefined) {
                expect(actualJson.modifier).to.be.oneOf([undefined, 'None']);
                delete actualJson.modifier;
            }
        }
        if (isRelationshipClass(actualJson)) {
            // abstract can be set via database, but not via context for 1 constraint class
            // so verify constraint and conditions are correct and delete property
            const expectedRelationship = expectedJson;
            if (actualJson.source.abstractConstraint !== expectedRelationship.source.abstractConstraint) {
                expect(actualJson.source.abstractConstraint).to.equal(expectedRelationship.source.constraintClasses[0]);
                expect(actualJson.source.constraintClasses.length).to.equal(1);
                delete actualJson.source.abstractConstraint;
            }
            if (actualJson.target.abstractConstraint !== expectedRelationship.target.abstractConstraint) {
                expect(actualJson.target.abstractConstraint).to.equal(expectedRelationship.target.constraintClasses[0]);
                expect(actualJson.target.constraintClasses.length).to.equal(1);
                delete actualJson.target.abstractConstraint;
            }
        }
        if (actualJson.schemaItemType === SchemaItemType.Format) {
            if (undefined !== actualJson.includeZero && undefined === expectedJson.includeZero) {
                expect(actualJson.includeZero).to.equal(true);
                delete actualJson.includeZero;
            }
            if (actualJson.composite && undefined !== actualJson.composite.includeZero && undefined === expectedJson.composite.includeZero) {
                expect(actualJson.composite.includeZero).to.equal(true);
                delete actualJson.composite.includeZero;
            }
            if (actualJson.composite && undefined !== actualJson.composite.spacer && undefined === expectedJson.composite.spacer) {
                expect(actualJson.composite.spacer).to.equal(" ");
                delete actualJson.composite.spacer;
            }
            if (undefined !== actualJson.decimalSeparator && undefined === expectedJson.decimalSeparator) {
                expect(actualJson.decimalSeparator).to.equal(".");
                delete actualJson.decimalSeparator;
            }
            if (undefined !== actualJson.roundFactor && undefined === expectedJson.roundFactor) {
                expect(actualJson.roundFactor).to.equal(0);
                delete actualJson.roundFactor;
            }
            if (undefined !== actualJson.showSignOption && undefined === expectedJson.showSignOption) {
                expect(actualJson.showSignOption).to.equal("OnlyNegative");
                delete actualJson.showSignOption;
            }
            if (undefined !== actualJson.thousandSeparator && undefined === expectedJson.thousandSeparator) {
                expect(actualJson.thousandSeparator).to.equal(",");
                delete actualJson.thousandSeparator;
            }
            if (undefined !== actualJson.uomSeparator && undefined === expectedJson.uomSeparator) {
                expect(actualJson.uomSeparator).to.equal(" ");
                delete actualJson.uomSeparator;
            }
            if (undefined !== actualJson.spacer && undefined === expectedJson.spacer) {
                expect(actualJson.spacer).to.equal(" ");
                delete actualJson.spacer;
            }
            if (undefined !== actualJson.formatTraits) {
                actualJson.formatTraits = actualJson.formatTraits.map((trait) => {
                    return trait.charAt(0).toUpperCase() + trait.slice(1);
                });
            }
        }
        expect(actualJson).to.deep.equalInAnyOrder(expectedJson);
    }
    async function createTestContext() {
        const testEnv = await TestContext.create();
        return testEnv;
    }
    it("Schema query, props parsed successfully", async function () {
        const env_1 = { stack: [], error: void 0, hasError: false };
        try {
            const testSchemaKey = new SchemaKey("SchemaTest", 1, 0, 0);
            const env = __addDisposableResource(env_1, await createTestContext(), true);
            const expectedSchema = await env.importAssetSchema(testSchemaKey);
            const actualSchemaProps = await env.schemaLocater.getSchemaJson(testSchemaKey, env.schemaContext);
            expect(actualSchemaProps).to.not.be.undefined;
            const actualSchema = await Schema.fromJson(actualSchemaProps, env.schemaContext);
            expect(actualSchema.toJSON()).to.deep.equal(expectedSchema?.toJSON());
        }
        catch (e_1) {
            env_1.error = e_1;
            env_1.hasError = true;
        }
        finally {
            const result_1 = __disposeResources(env_1);
            if (result_1)
                await result_1;
        }
    });
    it("Property query, props parsed successfully", async function () {
        const env_2 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("PropertyTest", 1, 0, 0);
            const env = __addDisposableResource(env_2, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const classPropsObjects = await env.schemaLocater.getEntities(testKey.name, env.schemaContext);
            const entityOneProps = findItem("EntityOne", classPropsObjects);
            const entityTwoProps = findItem("EntityTwo", classPropsObjects);
            const expectedEntityOne = await schema.getEntityClass("EntityOne");
            const expectedEntityTwo = await schema.getEntityClass("EntityTwo");
            const validateProperty = (propertyName, actualItem = entityOneProps, expectedItem = expectedEntityOne) => {
                const actualProperty = findProperty(propertyName, actualItem.properties);
                const expectedProperty = expectedItem?.getPropertySync(propertyName);
                // if maxOccurs is the maximum int value in the context Schema,
                // the property from the DB will not have a value
                if (expectedProperty.maxOccurs === 2147483647) {
                    expect(actualProperty.maxOccurs).to.be.undefined;
                    // set so comparison will pass
                    actualProperty.maxOccurs = 2147483647;
                }
                expect(actualProperty).to.deep.equal(expectedProperty?.toJSON());
            };
            // All but one testable property is in EntityOne
            for (const property of await expectedEntityOne.getProperties(true)) {
                validateProperty(property.name);
            }
            // Backward direction Navigation property is in EntityTwo
            validateProperty("EntityTwoParent", entityTwoProps, expectedEntityTwo);
        }
        catch (e_2) {
            env_2.error = e_2;
            env_2.hasError = true;
        }
        finally {
            const result_2 = __disposeResources(env_2);
            if (result_2)
                await result_2;
        }
    });
    it("Entity query, props parsed successfully", async function () {
        const env_3 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("EntityTest", 1, 0, 0);
            const env = __addDisposableResource(env_3, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const classPropsObjects = await env.schemaLocater.getEntities(testKey.name, env.schemaContext);
            expect(classPropsObjects.length).to.be.greaterThan(0);
            validateItem("EntityModifierNone", classPropsObjects, schema);
            validateItem("EntityModifierAbstract", classPropsObjects, schema);
            validateItem("EntityModifierSealed", classPropsObjects, schema);
        }
        catch (e_3) {
            env_3.error = e_3;
            env_3.hasError = true;
        }
        finally {
            const result_3 = __disposeResources(env_3);
            if (result_3)
                await result_3;
        }
    });
    it("Struct query, props parsed successfully", async function () {
        const env_4 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("StructTest", 1, 0, 0);
            const env = __addDisposableResource(env_4, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const classPropsObjects = await env.schemaLocater.getStructs(testKey.name, env.schemaContext);
            expect(classPropsObjects.length).to.be.greaterThan(0);
            validateItem("StructModifierNone", classPropsObjects, schema);
            validateItem("StructModifierAbstract", classPropsObjects, schema);
            validateItem("StructModifierSealed", classPropsObjects, schema);
        }
        catch (e_4) {
            env_4.error = e_4;
            env_4.hasError = true;
        }
        finally {
            const result_4 = __disposeResources(env_4);
            if (result_4)
                await result_4;
        }
    });
    it("Mixin query, props parsed successfully", async function () {
        const env_5 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("MixinTest", 1, 0, 0);
            const env = __addDisposableResource(env_5, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const classPropsObjects = await env.schemaLocater.getMixins(testKey.name, env.schemaContext);
            expect(classPropsObjects.length).to.be.greaterThan(0);
            validateItem("IBaseMixin", classPropsObjects, schema);
            validateItem("ITestMixin", classPropsObjects, schema);
        }
        catch (e_5) {
            env_5.error = e_5;
            env_5.hasError = true;
        }
        finally {
            const result_5 = __disposeResources(env_5);
            if (result_5)
                await result_5;
        }
    });
    it("Relationship query, props parsed successfully", async function () {
        const env_6 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("RelationshipTest", 1, 0, 0);
            const env = __addDisposableResource(env_6, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const classPropsObjects = await env.schemaLocater.getRelationships(testKey.name, env.schemaContext);
            expect(classPropsObjects.length).to.be.greaterThan(0);
            validateItem("OwnerOwnsVehicles", classPropsObjects, schema);
            validateItem("OwnerOwnsCars", classPropsObjects, schema);
            validateItem("OwnerOwnsAmericanCars", classPropsObjects, schema);
            validateItem("PhysicalModelBreaksDownCarElement", classPropsObjects, schema);
        }
        catch (e_6) {
            env_6.error = e_6;
            env_6.hasError = true;
        }
        finally {
            const result_6 = __disposeResources(env_6);
            if (result_6)
                await result_6;
        }
    });
    it("CustomAttributeClass query, props parsed successfully", async function () {
        const env_7 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("CustomAttributeClassTest", 1, 0, 0);
            const env = __addDisposableResource(env_7, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const classPropsObjects = await env.schemaLocater.getCustomAttributeClasses(testKey.name, env.schemaContext);
            expect(classPropsObjects.length).to.be.greaterThan(0);
            validateItem("CustomAttributeModifierNone", classPropsObjects, schema);
            validateItem("CustomAttributeModifierSealed", classPropsObjects, schema);
            validateItem("CustomAttributeModifierAbstract", classPropsObjects, schema);
        }
        catch (e_7) {
            env_7.error = e_7;
            env_7.hasError = true;
        }
        finally {
            const result_7 = __disposeResources(env_7);
            if (result_7)
                await result_7;
        }
    });
    it("KindOfQuantity query, props parsed successfully", async function () {
        const env_8 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("KindOfQuantityTest", 1, 0, 0);
            const env = __addDisposableResource(env_8, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getKindOfQuantities(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            validateItem("ACCELERATION", itemPropsObjects, schema);
            validateItem("ANGLE", itemPropsObjects, schema);
        }
        catch (e_8) {
            env_8.error = e_8;
            env_8.hasError = true;
        }
        finally {
            const result_8 = __disposeResources(env_8);
            if (result_8)
                await result_8;
        }
    });
    it("PropertyCategory query, props parsed successfully", async function () {
        const env_9 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("PropertyCategoryTest", 1, 0, 0);
            const env = __addDisposableResource(env_9, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getPropertyCategories(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            validateItem("PropertyCategory1", itemPropsObjects, schema);
            validateItem("PropertyCategory2", itemPropsObjects, schema);
        }
        catch (e_9) {
            env_9.error = e_9;
            env_9.hasError = true;
        }
        finally {
            const result_9 = __disposeResources(env_9);
            if (result_9)
                await result_9;
        }
    });
    it("Enumeration query, props parsed successfully", async function () {
        const env_10 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("EnumerationTest", 1, 0, 0);
            const env = __addDisposableResource(env_10, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getEnumerations(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            validateItem("IntEnumeration", itemPropsObjects, schema);
            validateItem("StringEnumeration", itemPropsObjects, schema);
        }
        catch (e_10) {
            env_10.error = e_10;
            env_10.hasError = true;
        }
        finally {
            const result_10 = __disposeResources(env_10);
            if (result_10)
                await result_10;
        }
    });
    it("Unit query, props parsed successfully", async function () {
        const env_11 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("UnitTest", 1, 0, 0);
            const env = __addDisposableResource(env_11, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getUnits(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            validateItem("LITRE", itemPropsObjects, schema);
            validateItem("GALLON", itemPropsObjects, schema);
            validateItem("ACRE", itemPropsObjects, schema);
            validateItem("FAHRENHEIT", itemPropsObjects, schema);
        }
        catch (e_11) {
            env_11.error = e_11;
            env_11.hasError = true;
        }
        finally {
            const result_11 = __disposeResources(env_11);
            if (result_11)
                await result_11;
        }
    });
    it("InvertedUnit query, props parsed successfully", async function () {
        const env_12 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("InvertedUnitTest", 1, 0, 0);
            const env = __addDisposableResource(env_12, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getInvertedUnits(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            validateItem("FT_HORIZONTAL_PER_FT_VERTICAL", itemPropsObjects, schema);
        }
        catch (e_12) {
            env_12.error = e_12;
            env_12.hasError = true;
        }
        finally {
            const result_12 = __disposeResources(env_12);
            if (result_12)
                await result_12;
        }
    });
    it("UnitSystem query, props parsed successfully", async function () {
        const env_13 = { stack: [], error: void 0, hasError: false };
        try {
            // There's a UnitSystem in there.
            const testKey = new SchemaKey("InvertedUnitTest", 1, 0, 0);
            const env = __addDisposableResource(env_13, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getUnitSystems(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            validateItem("USCUSTOM", itemPropsObjects, schema);
        }
        catch (e_13) {
            env_13.error = e_13;
            env_13.hasError = true;
        }
        finally {
            const result_13 = __disposeResources(env_13);
            if (result_13)
                await result_13;
        }
    });
    it("Constant query, props parsed successfully", async function () {
        const env_14 = { stack: [], error: void 0, hasError: false };
        try {
            // There's a UnitSystem in there.
            const testKey = new SchemaKey("ConstantTest", 1, 0, 0);
            const env = __addDisposableResource(env_14, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getConstants(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            validateItem("KILO", itemPropsObjects, schema);
            validateItem("HALF_PI", itemPropsObjects, schema);
        }
        catch (e_14) {
            env_14.error = e_14;
            env_14.hasError = true;
        }
        finally {
            const result_14 = __disposeResources(env_14);
            if (result_14)
                await result_14;
        }
    });
    it("Phenomenon query, props parsed successfully", async function () {
        const env_15 = { stack: [], error: void 0, hasError: false };
        try {
            // There's a Phenomenon in there.
            const testKey = new SchemaKey("ConstantTest", 1, 0, 0);
            const env = __addDisposableResource(env_15, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getPhenomenon(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            validateItem("NUMBER", itemPropsObjects, schema);
            validateItem("LENGTH_RATIO", itemPropsObjects, schema);
        }
        catch (e_15) {
            env_15.error = e_15;
            env_15.hasError = true;
        }
        finally {
            const result_15 = __disposeResources(env_15);
            if (result_15)
                await result_15;
        }
    });
    it("Format Schema parses successfully", async function () {
        const env_16 = { stack: [], error: void 0, hasError: false };
        try {
            // Using installed Formats schema
            const testKey = new SchemaKey("Formats", 1, 0, 0);
            const env = __addDisposableResource(env_16, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getFormats(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            for (const props of itemPropsObjects) {
                validateItem(props.name, itemPropsObjects, schema);
            }
        }
        catch (e_16) {
            env_16.error = e_16;
            env_16.hasError = true;
        }
        finally {
            const result_16 = __disposeResources(env_16);
            if (result_16)
                await result_16;
        }
    });
    it("Comprehensive Format parses successfully", async function () {
        const env_17 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("FormatTest", 1, 0, 0);
            const env = __addDisposableResource(env_17, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getFormats(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            for (const props of itemPropsObjects) {
                validateItem(props.name, itemPropsObjects, schema);
            }
        }
        catch (e_17) {
            env_17.error = e_17;
            env_17.hasError = true;
        }
        finally {
            const result_17 = __disposeResources(env_17);
            if (result_17)
                await result_17;
        }
    });
    it("CustomAttribute instances parse successfully", async function () {
        const env_18 = { stack: [], error: void 0, hasError: false };
        try {
            const testKey = new SchemaKey("CustomAttributeInstanceTest", 1, 0, 0);
            const env = __addDisposableResource(env_18, await createTestContext(), true);
            const schema = await env.importAssetSchema(testKey);
            const itemPropsObjects = await env.schemaLocater.getStructs(testKey.name, env.schemaContext);
            expect(itemPropsObjects.length).to.be.greaterThan(0);
            for (const props of itemPropsObjects) {
                validateItem(props.name, itemPropsObjects, schema);
            }
        }
        catch (e_18) {
            env_18.error = e_18;
            env_18.hasError = true;
        }
        finally {
            const result_18 = __disposeResources(env_18);
            if (result_18)
                await result_18;
        }
    });
});
//# sourceMappingURL=ECSqlQueries.test.js.map