import { assert } from "../../../shared/src/asserts.js";
import { stringify } from "../../../shared/src/bigint-json.js";
import { dataTypeToZqlValueType as upstreamDataTypeToZqlValueType, } from "./pg.js";
function columnType(col, table) {
    const spec = table.columns[col];
    assert(spec, `Unknown column ${col} in table ${table.name}`);
    return spec.dataType;
}
export const JSON_STRINGIFIED = 's';
export const JSON_PARSED = 'p';
/**
 * Creates a LiteRow from the supplied RowValue. A copy of the `row`
 * is made only if a value conversion is performed.
 */
export function liteRow(row, table, jsonFormat) {
    let copyNeeded = false;
    let numCols = 0;
    for (const key in row) {
        numCols++;
        const val = row[key];
        const liteVal = liteValue(val, columnType(key, table), jsonFormat);
        if (val !== liteVal) {
            copyNeeded = true;
            break;
        }
    }
    if (!copyNeeded) {
        return { row: row, numCols };
    }
    // Slow path for when a conversion is needed.
    numCols = 0;
    const converted = {};
    for (const key in row) {
        numCols++;
        converted[key] = liteValue(row[key], columnType(key, table), jsonFormat);
    }
    return { row: converted, numCols };
}
/**
 * Postgres values types that are supported by SQLite are stored as-is.
 * This includes Uint8Arrays for the `bytea` / `BLOB` type.
 * * `boolean` values are converted to `0` or `1` integers.
 * * `PreciseDate` values are converted to epoch microseconds.
 * * JSON and Array values are stored as `JSON.stringify()` strings.
 *
 * Note that this currently does not handle the `bytea[]` type, but that's
 * already a pretty questionable type.
 */
export function liteValue(val, pgType, jsonFormat) {
    if (val instanceof Uint8Array || val === null) {
        return val;
    }
    const valueType = dataTypeToZqlValueType(pgType);
    if (valueType === 'json') {
        if (jsonFormat === JSON_STRINGIFIED && typeof val === 'string') {
            // JSON and JSONB values are already strings if the JSON was not parsed.
            return val;
        }
        // Non-JSON/JSONB values will always appear as objects / arrays.
        return stringify(val);
    }
    const obj = toLiteValue(val);
    return obj && typeof obj === 'object' ? stringify(obj) : obj;
}
function toLiteValue(val) {
    switch (typeof val) {
        case 'string':
        case 'number':
        case 'bigint':
            return val;
        case 'boolean':
            return val ? 1 : 0;
    }
    if (val === null) {
        return val;
    }
    if (Array.isArray(val)) {
        return val.map(v => toLiteValue(v));
    }
    assert(val.constructor?.name === 'Object', `Unhandled object type ${val.constructor?.name}`);
    return val; // JSON
}
export function mapLiteDataTypeToZqlSchemaValue(liteDataType) {
    return { type: mapLiteDataTypeToZqlValueType(liteDataType) };
}
function mapLiteDataTypeToZqlValueType(dataType) {
    const type = dataTypeToZqlValueType(dataType);
    if (type === undefined) {
        throw new Error(`Unsupported data type ${dataType}`);
    }
    return type;
}
// Note: Includes the "TEXT" substring for SQLite type affinity
const TEXT_ENUM_ATTRIBUTE = '|TEXT_ENUM';
const NOT_NULL_ATTRIBUTE = '|NOT_NULL';
export const TEXT_ARRAY_ATTRIBUTE = '|TEXT_ARRAY';
/**
 * Formats a {@link LiteTypeString}.
 */
export function liteTypeString(upstreamDataType, notNull, textEnum) {
    let typeString = upstreamDataType;
    if (notNull) {
        typeString += NOT_NULL_ATTRIBUTE;
    }
    if (textEnum) {
        typeString += TEXT_ENUM_ATTRIBUTE;
    }
    return typeString;
}
export function upstreamDataType(liteTypeString) {
    const delim = liteTypeString.indexOf('|');
    return delim > 0 ? liteTypeString.substring(0, delim) : liteTypeString;
}
export function nullableUpstream(liteTypeString) {
    return !liteTypeString.includes(NOT_NULL_ATTRIBUTE);
}
/**
 * Returns the value type for the `pgDataType` if it is supported by ZQL.
 * (Note that `pgDataType` values are stored as-is in the SQLite column defs).
 *
 * For types not supported by ZQL, returns `undefined`.
 */
export function dataTypeToZqlValueType(liteTypeString) {
    return upstreamDataTypeToZqlValueType(upstreamDataType(liteTypeString).toLowerCase(), liteTypeString.includes(TEXT_ENUM_ATTRIBUTE), isArray(liteTypeString));
}
export function isEnum(liteTypeString) {
    return liteTypeString.includes(TEXT_ENUM_ATTRIBUTE);
}
export function isArray(liteTypeString) {
    return (liteTypeString.includes(TEXT_ARRAY_ATTRIBUTE) ||
        liteTypeString.includes('[]'));
}
//# sourceMappingURL=lite.js.map