import { CannotAttachTreeChildrenEntityError } from "../../error/CannotAttachTreeChildrenEntityError";
/**
 * Executes subject operations for closure entities.
 */
export class ClosureSubjectExecutor {
    // -------------------------------------------------------------------------
    // Constructor
    // -------------------------------------------------------------------------
    constructor(queryRunner) {
        this.queryRunner = queryRunner;
    }
    // -------------------------------------------------------------------------
    // Public Methods
    // -------------------------------------------------------------------------
    /**
     * Removes all children of the given subject's entity.

    async deleteChildrenOf(subject: Subject) {
        // const relationValue = subject.metadata.treeParentRelation.getEntityValue(subject.databaseEntity);
        // console.log("relationValue: ", relationValue);
        // this.queryRunner.manager
        //     .createQueryBuilder()
        //     .from(subject.metadata.closureJunctionTable.target, "tree")
        //     .where("tree.");
    }*/
    /**
     * Executes operations when subject is being inserted.
     */
    async insert(subject) {
        // create values to be inserted into the closure junction
        const closureJunctionInsertMap = {};
        subject.metadata.closureJunctionTable.ancestorColumns.forEach(column => {
            closureJunctionInsertMap[column.databaseName] = subject.identifier;
        });
        subject.metadata.closureJunctionTable.descendantColumns.forEach(column => {
            closureJunctionInsertMap[column.databaseName] = subject.identifier;
        });
        // insert values into the closure junction table
        await this.queryRunner
            .manager
            .createQueryBuilder()
            .insert()
            .into(subject.metadata.closureJunctionTable.tablePath)
            .values(closureJunctionInsertMap)
            .updateEntity(false)
            .callListeners(false)
            .execute();
        let parent = subject.metadata.treeParentRelation.getEntityValue(subject.entity); // if entity was attached via parent
        if (!parent && subject.parentSubject && subject.parentSubject.entity) // if entity was attached via children
            parent = subject.parentSubject.insertedValueSet ? subject.parentSubject.insertedValueSet : subject.parentSubject.entity;
        if (parent) {
            const escape = (alias) => this.queryRunner.connection.driver.escape(alias);
            const tableName = this.getTableName(subject.metadata.closureJunctionTable.tablePath);
            const ancestorColumnNames = subject.metadata.closureJunctionTable.ancestorColumns.map(column => {
                return escape(column.databaseName);
            });
            const descendantColumnNames = subject.metadata.closureJunctionTable.descendantColumns.map(column => {
                return escape(column.databaseName);
            });
            const firstQueryParameters = [];
            const childEntityIdValues = subject.metadata.primaryColumns.map(column => column.getEntityValue(subject.insertedValueSet));
            const childEntityIds1 = subject.metadata.primaryColumns.map((column, index) => {
                firstQueryParameters.push(childEntityIdValues[index]);
                return this.queryRunner.connection.driver.createParameter("child_entity_" + column.databaseName, firstQueryParameters.length - 1);
            });
            const whereCondition = subject.metadata.primaryColumns.map(column => {
                const columnName = escape(column.databaseName + "_descendant");
                const parentId = column.getEntityValue(parent);
                if (!parentId)
                    throw new CannotAttachTreeChildrenEntityError(subject.metadata.name);
                firstQueryParameters.push(parentId);
                const parameterName = this.queryRunner.connection.driver.createParameter("parent_entity_" + column.databaseName, firstQueryParameters.length - 1);
                return columnName + " = " + parameterName;
            }).join(", ");
            await this.queryRunner.query(`INSERT INTO ${tableName} (${[...ancestorColumnNames, ...descendantColumnNames].join(", ")}) ` +
                `SELECT ${ancestorColumnNames.join(", ")}, ${childEntityIds1.join(", ")} FROM ${tableName} WHERE ${whereCondition}`, firstQueryParameters);
        }
    }
    /**
     * Gets escaped table name with schema name if SqlServer or Postgres driver used with custom
     * schema name, otherwise returns escaped table name.
     */
    getTableName(tablePath) {
        return tablePath.split(".")
            .map(i => {
            // this condition need because in SQL Server driver when custom database name was specified and schema name was not, we got `dbName..tableName` string, and doesn't need to escape middle empty string
            if (i === "")
                return i;
            return this.queryRunner.connection.driver.escape(i);
        }).join(".");
    }
}

//# sourceMappingURL=ClosureSubjectExecutor.js.map
