import { ZERO_VERSION_COLUMN_NAME } from "../services/replicator/schema/constants.js";
import { liteTypeString, liteTypeToZqlValueType, upstreamDataType } from "../types/lite.js";
import { liteTableName } from "../types/names.js";
import { Enum } from "./postgres-type-class-enum.js";
import "./specs.js";
function isEnumColumn(spec) {
  return (spec.elemPgTypeClass ?? spec.pgTypeClass) === Enum;
}
function isArrayColumn(spec) {
  return spec.elemPgTypeClass !== null && spec.elemPgTypeClass !== void 0;
}
function zeroVersionColumnSpec(defaultVersion) {
  return {
    pos: Number.MAX_SAFE_INTEGER,
    // i.e. last
    characterMaximumLength: null,
    dataType: "text",
    notNull: false,
    dflt: !defaultVersion ? null : `'${defaultVersion}'`,
    elemPgTypeClass: null
  };
}
function warnIfDataTypeSupported(lc, liteTypeString2, table, column) {
  if (liteTypeToZqlValueType(liteTypeString2) === void 0) {
    lc.warn?.(
      `

WARNING: zero does not yet support the "${upstreamDataType(
        liteTypeString2
      )}" data type.
The "${table}"."${column}" column will not be synced to clients.

`
    );
  }
}
const SIMPLE_TOKEN_EXPRESSION_REGEX = /^[^'()]+$/;
const UNSUPPORTED_TOKENS = /\b(current_time|current_date|current_timestamp)\b/i;
const STRING_EXPRESSION_REGEX = /^('.*')::[^']+$/;
function mapPostgresToLiteDefault(table, column, dataType, defaultExpression) {
  if (!defaultExpression) {
    return null;
  }
  if (UNSUPPORTED_TOKENS.test(defaultExpression)) {
    throw new UnsupportedColumnDefaultError(
      `Cannot ADD a column with CURRENT_TIME, CURRENT_DATE, or CURRENT_TIMESTAMP`
    );
  }
  if (SIMPLE_TOKEN_EXPRESSION_REGEX.test(defaultExpression)) {
    if (liteTypeToZqlValueType(dataType) === "boolean") {
      return defaultExpression === "true" ? "1" : "0";
    }
    return defaultExpression;
  }
  const match = STRING_EXPRESSION_REGEX.exec(defaultExpression);
  if (!match) {
    throw new UnsupportedColumnDefaultError(
      `Unsupported default value for ${table}.${column}: ${defaultExpression}`
    );
  }
  return match[1];
}
function mapPostgresToLiteColumn(table, column, ignoreDefault) {
  const { pos, dataType, notNull, dflt, elemPgTypeClass = null } = column.spec;
  const liteType = liteTypeString(
    dataType,
    notNull,
    isEnumColumn(column.spec),
    isArrayColumn(column.spec)
  );
  return {
    pos,
    dataType: liteType,
    characterMaximumLength: null,
    // Note: NOT NULL constraints are always ignored for SQLite (replica) tables.
    // 1. They are enforced by the replication stream.
    // 2. We need nullability for columns with defaults to support
    // write permissions on the "proposed mutation" state. Proposed
    // mutations are written to SQLite in a `BEGIN CONCURRENT` transaction in mutagen.
    // Permission policies are run against that state (to get their ruling) then the
    // transaction is rolled back.
    notNull: false,
    // Note: DEFAULT constraints are ignored when creating new tables, but are
    //       necessary for adding columns to tables with existing rows.
    dflt: ignoreDefault === "ignore-default" ? null : mapPostgresToLiteDefault(table, column.name, dataType, dflt),
    elemPgTypeClass
  };
}
function mapPostgresToLite(t, defaultVersion) {
  const { schema: _, primaryKey: _dropped, ...liteSpec } = t;
  const name = liteTableName(t);
  return {
    ...liteSpec,
    name,
    columns: {
      ...Object.fromEntries(
        Object.entries(t.columns).map(([col, spec]) => [
          col,
          // `ignore-default` for create table statements because
          // there are no rows to set the default for.
          mapPostgresToLiteColumn(name, { name: col, spec }, "ignore-default")
        ])
      ),
      [ZERO_VERSION_COLUMN_NAME]: zeroVersionColumnSpec(defaultVersion)
    }
  };
}
function mapPostgresToLiteIndex(index) {
  const { schema, tableName, name, ...liteIndex } = index;
  return {
    tableName: liteTableName({ schema, name: tableName }),
    name: liteTableName({ schema, name }),
    ...liteIndex
  };
}
class UnsupportedColumnDefaultError extends Error {
  name = "UnsupportedColumnDefaultError";
}
export {
  UnsupportedColumnDefaultError,
  isArrayColumn,
  isEnumColumn,
  mapPostgresToLite,
  mapPostgresToLiteColumn,
  mapPostgresToLiteDefault,
  mapPostgresToLiteIndex,
  warnIfDataTypeSupported
};
//# sourceMappingURL=pg-to-lite.js.map
