"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__tsfTypeAliases = exports.sql = void 0;
exports.createSqlQuery = createSqlQuery;
exports.renderSql = renderSql;
exports.normalizeSqlBindingValue = normalizeSqlBindingValue;
exports.quoteIdentifier = quoteIdentifier;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-server-foundation/type-metadata-runtime"));
function isSqlQuery(value) {
    return !!value && typeof value === 'object' && value.kind === 'sql';
}
function isIdentifier(value) {
    return !!value && typeof value === 'object' && value.kind === 'identifier';
}
function isTrustedRaw(value) {
    return !!value && typeof value === 'object' && value.kind === 'rawTrusted';
}
function makeQuery(chunks, values) {
    return Object.freeze({
        kind: 'sql',
        chunks: Object.freeze(chunks),
        values: Object.freeze(values)
    });
}
function sqlTag(strings, ...values) {
    const chunks = [strings[0] ?? ''];
    const bindings = [];
    for (let i = 0; i < values.length; i++) {
        const value = values[i];
        const nextChunk = strings[i + 1] ?? '';
        if (isSqlQuery(value)) {
            chunks[chunks.length - 1] += value.chunks[0] ?? '';
            for (let j = 0; j < value.values.length; j++) {
                bindings.push(value.values[j]);
                chunks.push(value.chunks[j + 1] ?? '');
            }
            chunks[chunks.length - 1] += nextChunk;
        }
        else if (isIdentifier(value) || isTrustedRaw(value)) {
            bindings.push(value);
            chunks.push(nextChunk);
        }
        else {
            bindings.push(value);
            chunks.push(nextChunk);
        }
    }
    return makeQuery(chunks, bindings);
}
function join(values, separator = sqlTag `, `) {
    if (!values.length)
        return makeQuery([''], []);
    let result = sqlTag `${values[0]}`;
    for (const value of values.slice(1)) {
        result = sqlTag `${result}${separator}${value}`;
    }
    return result;
}
function identifier(...names) {
    if (!names.length)
        throw new Error('sql.identifier() requires at least one name');
    for (const name of names) {
        if (!name || name.includes('\0')) {
            throw new Error(`Invalid SQL identifier segment: ${JSON.stringify(name)}`);
        }
    }
    return Object.freeze({ kind: 'identifier', names: Object.freeze([...names]) });
}
function rawTrusted(text) {
    return Object.freeze({ kind: 'rawTrusted', text });
}
exports.sql = Object.assign(sqlTag, {
    join,
    identifier,
    rawTrusted
});
function createSqlQuery(sqlIn, bindings = []) {
    const parts = sqlIn.split('?');
    if (parts.length - 1 !== bindings.length) {
        throw new Error(`Expected ${parts.length - 1} SQL bindings, received ${bindings.length}`);
    }
    return makeQuery(parts, [...bindings]);
}
function renderSql(input, dialect) {
    if (typeof input === 'string')
        return { sql: input, bindings: [] };
    const bindings = [];
    let text = input.chunks[0] ?? '';
    for (let i = 0; i < input.values.length; i++) {
        const value = input.values[i];
        if (isIdentifier(value)) {
            text += renderIdentifier(value, dialect);
        }
        else if (isTrustedRaw(value)) {
            text += value.text;
        }
        else {
            bindings.push(normalizeSqlBindingValue(value));
            text += dialect === 'postgres' ? `$${bindings.length}` : '?';
        }
        text += input.chunks[i + 1] ?? '';
    }
    return { sql: text, bindings };
}
function normalizeSqlBindingValue(value) {
    if (typeof value === 'bigint')
        return value.toString();
    if (!isDateLike(value))
        return value;
    const time = value.getTime();
    if (!Number.isFinite(time))
        return value;
    return formatSqlDateTimeUtc(value);
}
function isDateLike(value) {
    if (!value || typeof value !== 'object')
        return false;
    const candidate = value;
    return (Object.prototype.toString.call(value) === '[object Date]' &&
        typeof candidate.getTime === 'function' &&
        typeof candidate.getUTCFullYear === 'function' &&
        typeof candidate.getUTCMonth === 'function' &&
        typeof candidate.getUTCDate === 'function' &&
        typeof candidate.getUTCHours === 'function' &&
        typeof candidate.getUTCMinutes === 'function' &&
        typeof candidate.getUTCSeconds === 'function' &&
        typeof candidate.getUTCMilliseconds === 'function');
}
function formatSqlDateTimeUtc(value) {
    return `${pad(value.getUTCFullYear(), 4)}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())} ${pad(value.getUTCHours())}:${pad(value.getUTCMinutes())}:${pad(value.getUTCSeconds())}.${pad(value.getUTCMilliseconds(), 3)}`;
}
function pad(value, size = 2) {
    return String(value).padStart(size, '0');
}
function renderIdentifier(identifier, dialect) {
    return identifier.names.map(name => quoteIdentifier(name, dialect)).join('.');
}
function quoteIdentifier(name, dialect) {
    if (dialect === 'postgres')
        return `"${name.replace(/"/g, '""')}"`;
    return `\`${name.replace(/`/g, '``')}\``;
}
exports.__tsfTypeAliases = _a.decodeCompactMetadataV1("[1,{\"Dialect\":{\"kind\":12,\"types\":[{\"kind\":10,\"literal\":\"mysql\"},{\"kind\":10,\"literal\":\"postgres\"}],\"typeName\":\"Dialect\"},\"RenderedSql\":{\"kind\":18,\"typeName\":\"RenderedSql\",\"types\":[{\"kind\":20,\"name\":\"sql\",\"type\":{\"kind\":6},\"optional\":false},{\"kind\":20,\"name\":\"bindings\",\"type\":{\"kind\":14,\"type\":{\"kind\":2}},\"optional\":false}]},\"SqlFragment\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"SqlQuery\",\"types\":[{\"kind\":20,\"name\":\"kind\",\"type\":{\"kind\":10,\"literal\":\"sql\"},\"optional\":false},{\"kind\":20,\"name\":\"chunks\",\"type\":{\"kind\":14,\"type\":{\"kind\":6}},\"optional\":false},{\"kind\":20,\"name\":\"values\",\"type\":{\"kind\":14,\"type\":{\"kind\":2,\"typeName\":\"SqlValue\"}},\"optional\":false}]},{\"kind\":18,\"typeName\":\"SqlIdentifier\",\"types\":[{\"kind\":20,\"name\":\"kind\",\"type\":{\"kind\":10,\"literal\":\"identifier\"},\"optional\":false},{\"kind\":20,\"name\":\"names\",\"type\":{\"kind\":14,\"type\":{\"kind\":6}},\"optional\":false}]},{\"kind\":18,\"typeName\":\"SqlTrustedRaw\",\"types\":[{\"kind\":20,\"name\":\"kind\",\"type\":{\"kind\":10,\"literal\":\"rawTrusted\"},\"optional\":false},{\"kind\":20,\"name\":\"text\",\"type\":{\"kind\":6},\"optional\":false}]}],\"typeName\":\"SqlFragment\"},\"SqlIdentifier\":{\"kind\":18,\"typeName\":\"SqlIdentifier\",\"types\":[{\"kind\":20,\"name\":\"kind\",\"type\":{\"kind\":10,\"literal\":\"identifier\"},\"optional\":false},{\"kind\":20,\"name\":\"names\",\"type\":{\"kind\":14,\"type\":{\"kind\":6}},\"optional\":false}]},\"SqlInput\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"SqlQuery\",\"types\":[{\"kind\":20,\"name\":\"kind\",\"type\":{\"kind\":10,\"literal\":\"sql\"},\"optional\":false},{\"kind\":20,\"name\":\"chunks\",\"type\":{\"kind\":14,\"type\":{\"kind\":6}},\"optional\":false},{\"kind\":20,\"name\":\"values\",\"type\":{\"kind\":14,\"type\":{\"kind\":2,\"typeName\":\"SqlValue\"}},\"optional\":false}]},{\"kind\":6}],\"typeName\":\"SqlInput\"},\"SqlQuery\":{\"kind\":18,\"typeName\":\"SqlQuery\",\"types\":[{\"kind\":20,\"name\":\"kind\",\"type\":{\"kind\":10,\"literal\":\"sql\"},\"optional\":false},{\"kind\":20,\"name\":\"chunks\",\"type\":{\"kind\":14,\"type\":{\"kind\":6}},\"optional\":false},{\"kind\":20,\"name\":\"values\",\"type\":{\"kind\":14,\"type\":{\"kind\":2,\"typeName\":\"SqlValue\"}},\"optional\":false}]},\"SqlTrustedRaw\":{\"kind\":18,\"typeName\":\"SqlTrustedRaw\",\"types\":[{\"kind\":20,\"name\":\"kind\",\"type\":{\"kind\":10,\"literal\":\"rawTrusted\"},\"optional\":false},{\"kind\":20,\"name\":\"text\",\"type\":{\"kind\":6},\"optional\":false}]},\"SqlValue\":{\"kind\":2,\"typeName\":\"SqlValue\"}}]", []);
//# sourceMappingURL=sql.js.map