"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__ΩIMySQLDatabaseAdapterConfig = exports.MySQLDatabaseAdapter = exports.__ΩMySQLDatabaseSession = void 0;
exports.createMySQLDatabase = createMySQLDatabase;
const __ΩConstructorParameters = ['T', 'args', 'new', 'ConstructorParameters', 'l>e"!R!RPde#!Ph"!@2""/#qk#\'QRb!Pde"!p)w$y'];
function __assignType(fn, args) {
    fn.__type = args;
    return fn;
}
/*@ts-ignore*/
var { __ΩClassType } = require('@deepkit/core');
const core_1 = require("@deepkit/core");
const logger_1 = require("@deepkit/logger");
const mysql_1 = require("@deepkit/mysql");
const orm_1 = require("@deepkit/orm");
const sql_1 = require("@deepkit/sql");
const type_1 = require("@deepkit/type");
const _1 = require(".");
const resolver_1 = require("../app/resolver");
const state_1 = require("../app/state");
const common_1 = require("./common");
const __ΩMySQLDatabaseSession = [() => MySQLDatabaseAdapter, () => orm_1.DatabaseSession, 'MySQLDatabaseSession', 'PP7!7"w#y'];
exports.__ΩMySQLDatabaseSession = __ΩMySQLDatabaseSession;
const originalRun = mysql_1.MySQLConnection.prototype.run;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
mysql_1.MySQLConnection.prototype.run = __assignType(async function (sql, params = []) {
    await originalRun.call(this, sql, params);
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    return this.lastExecResult?.[0];
}, ['sql', 'params', () => [], '', 'P&2!"F2">#"/$']);
class MySQLDatabaseAdapter extends mysql_1.MySQLDatabaseAdapter {
    registerTransformations() {
        // any
        this.platform.serializer.deserializeRegistry.register(type_1.ReflectionKind.any, __assignType((_type, state) => {
            state.addSetter(state.accessor);
        }, ['_type', 'state', '', 'P"2!"2""/#']));
        // date string
        this.platform.serializer.deserializeRegistry.addDecorator(__assignType(t => t.typeName === 'DateString', ['t', '', 'P"2!"/"']), __assignType((_type, state) => {
            state.addSetter(`${state.accessor} instanceof Date ? ${state.accessor}.toISOString().substring(0, 10) : ${state.accessor}`);
            state.ended = true;
        }, ['_type', 'state', '', 'P"2!"2""/#']));
        // register POINT as a coordinate
        // a specificity of 2 on the type guard allows the default object literal (at specificity 1) to match the {x,y} object
        // while allowing a fallback to match the POINT object coming from the mariadb driver
        const isCoordinateClass = __assignType((t) => t.kind === type_1.ReflectionKind.class && (0, core_1.getClassName)(t.classType) === 'Coordinate', ['Type', 't', '', 'P"w!2")/#']);
        const isCoordinateTypeName = __assignType((t) => {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            const typeName = t.typeName;
            return typeName === 'MySQLCoordinate' || typeName === 'NullableMySQLCoordinate' || typeName === 'Coordinate';
        }, ['Type', 't', '', 'P"w!2")/#']);
        const hasMySQLPointAnnotation = __assignType((t) => {
            const mysqlOptions = (type_1.databaseAnnotation.getDatabase.Ω = [['type', 'P&4!8M']], type_1.databaseAnnotation.getDatabase(t, 'mysql'));
            return mysqlOptions?.type === 'point';
        }, ['Type', 't', '', 'P"w!2")/#']);
        const containsCoordinate = __assignType((t) => {
            if (isCoordinateClass(t))
                return true;
            if (isCoordinateTypeName(t))
                return true;
            if (hasMySQLPointAnnotation(t))
                return true;
            if (t.kind === type_1.ReflectionKind.intersection)
                return t.types.some(containsCoordinate);
            if (t.kind === type_1.ReflectionKind.union)
                return t.types.filter(sql_1.isNonUndefined).some(containsCoordinate);
            return false;
        }, ['Type', 't', '', 'P"w!2")/#']);
        this.platform.addType(containsCoordinate, 'point');
        this.platform.serializer.typeGuards.registerClass(2, _1.Coordinate, __assignType((_type, state) => {
            state.addSetter(`typeof ${state.accessor} === 'object' && ${state.accessor}.type === 'Point'`);
        }, ['_type', 'state', '', 'P"2!"2""/#']));
        this.platform.serializer.serializeRegistry.registerClass(_1.Coordinate, __assignType((_type, state) => {
            state.addCodeForSetter(`
                const c = ${state.accessor};
                ${state.setter} = { type: 'Point', coordinates: [c.x, c.y] };
            `);
            state.ended = true;
        }, ['_type', 'state', '', 'P"2!"2""/#']));
        this.platform.serializer.deserializeRegistry.registerClass(_1.Coordinate, __assignType((_type, state) => {
            state.addCodeForSetter(`
                const c = ${state.accessor};
                ${state.setter} = { x: c.coordinates[0], y: c.coordinates[1] };
            `);
            state.ended = true;
        }, ['_type', 'state', '', 'P"2!"2""/#']));
        // when Jest mocks dates, the Date object checked by Deepkit is not the same as the one created by Jest
        if (process.env.APP_ENV === 'test') {
            const isDate = __assignType((t) => t.kind === type_1.ReflectionKind.class && t.classType.name === 'Date', ['Type', 't', '', 'P"w!2""/#']);
            this.platform.addType(isDate, 'datetime');
            this.platform.addType(__assignType(t => t.kind === type_1.ReflectionKind.union && t.types.filter(sql_1.isNonUndefined).every(isDate), ['t', '', 'P"2!"/"']), 'datetime');
        }
    }
}
exports.MySQLDatabaseAdapter = MySQLDatabaseAdapter;
MySQLDatabaseAdapter.__type = [() => mysql_1.MySQLDatabaseAdapter, 'registerTransformations', 'MySQLDatabaseAdapter', 'P7!P"0"5w#'];
const __ΩIMySQLDatabaseAdapterConfig = ['PoolConfig', 'enableLocksTable', 'IMySQLDatabaseAdapterConfig', 'P"w!)4"8Mw#y'];
exports.__ΩIMySQLDatabaseAdapterConfig = __ΩIMySQLDatabaseAdapterConfig;
function createMySQLDatabase(config, entities = []) {
    var _a;
    return _a = class extends common_1.BaseDatabase {
            constructor() {
                const appConfig = (0, resolver_1.getAppConfig)();
                const isProduction = appConfig.APP_ENV === 'production';
                const { enableLocksTable, ...otherConfig } = config;
                const adapter = new MySQLDatabaseAdapter({
                    host: appConfig.MYSQL_HOST,
                    port: appConfig.MYSQL_PORT,
                    user: appConfig.MYSQL_USER,
                    password: appConfig.MYSQL_PASSWORD_SECRET,
                    database: appConfig.MYSQL_DATABASE,
                    connectionLimit: appConfig.MYSQL_CONNECTION_LIMIT ?? (isProduction ? 10 : 5),
                    minimumIdle: appConfig.MYSQL_MIN_IDLE_CONNECTIONS ?? (isProduction ? undefined : 1),
                    idleTimeout: appConfig.MYSQL_IDLE_TIMEOUT_SECONDS ?? (isProduction ? 60 : 5),
                    allowPublicKeyRetrieval: true,
                    trace: true,
                    ...otherConfig
                });
                adapter.registerTransformations();
                if (state_1.globalState.additionalEntities) {
                    entities.push(...state_1.globalState.additionalEntities);
                }
                super(adapter, entities);
                if (enableLocksTable) {
                    this.rawExecute(`CREATE TABLE IF NOT EXISTS \`_locks\` (
                        \`key\` VARCHAR(255) NOT NULL PRIMARY KEY,
                        \`createdAt\` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                        \`lastTouched\` DATETIME
                    )`)
                        .then(() => this.rawExecute(`DELETE FROM _locks WHERE lastTouched < NOW() - INTERVAL 1 HOUR`))
                        .catch(__assignType(err => {
                        (0, resolver_1.r)(logger_1.Logger).error(`Could not create _locks table: %s`, err);
                    }, ['err', '', 'P"2!"/"']));
                }
            }
        },
        _a.__type = [() => MySQLDatabaseAdapter, () => common_1.BaseDatabase, 'constructor', () => MySQLDatabaseAdapter, 'PP7!7"P"0#5P7$6"'],
        _a;
}
createMySQLDatabase.__type = [() => __ΩIMySQLDatabaseAdapterConfig, 'config', () => __ΩConstructorParameters, () => orm_1.Database, 1, 'entities', () => [], () => __ΩClassType, () => MySQLDatabaseAdapter, () => common_1.BaseDatabase, 'createMySQLDatabase', 'Pn!2"i$o#".%f2&>\'PP7)7*o("/+'];
//# sourceMappingURL=mysql.js.map