{"version":3,"file":"mysql.mjs","names":[],"sources":["../src/adapters/mysql/adapter.ts","../src/adapters/mysql/dialect.ts"],"sourcesContent":["import {\n  KickDbError,\n  lockTableDdl,\n  migrationsTableDdl,\n  type Dialect,\n  type MigrationAdapter,\n  type MigrationRow,\n  type SchemaSnapshot,\n} from '../../index'\nimport { introspectMysql } from '../../migrate/introspect-mysql'\n\n/**\n * mysql2-shaped pool that `mysqlAdapter` consumes. Mirrors the\n * structural surface of `mysql2/promise`'s Pool. The adapter only\n * uses `query(...)` and `getConnection(...)` so any mysql2-compatible\n * driver works.\n *\n * Return type is `Promise<[R, unknown]>` (not `[R[], unknown]`) so\n * mysql2's `Pool.query()` is structurally assignable: SELECT\n * statements return `RowDataPacket[]` (so callers pass `R =\n * MyRow[]`), INSERT / UPDATE / DELETE return `ResultSetHeader` (so\n * callers pass `R = ResultSetHeader`). Each adapter call site picks\n * the row shape it expects via the type parameter.\n */\nexport interface MysqlConnectionLike {\n  query<R = unknown>(sql: string, params?: readonly unknown[]): Promise<[R, unknown]>\n  release(): void\n}\n\nexport interface MysqlPoolLike {\n  query<R = unknown>(sql: string, params?: readonly unknown[]): Promise<[R, unknown]>\n  getConnection(): Promise<MysqlConnectionLike>\n}\n\nexport interface MysqlAdapterOptions {\n  /**\n   * mysql2-compatible Pool. Caller-owned — `close()` on the adapter\n   * does NOT end the pool because adopters typically share a single\n   * pool across the migration adapter and the KickDbClient.\n   */\n  pool: MysqlPoolLike\n}\n\n/**\n * Minimum supported MySQL major + MariaDB version. `JSON_ARRAYAGG`\n * shipped in MySQL 8.0 and MariaDB 10.5 — earlier versions can't\n * run kickjs-db's relational query layer.\n *\n * Spec: docs/db/spec-relational-query-other-dialects.md §7 R-1.\n */\nconst MIN_MYSQL_MAJOR = 8\nconst MIN_MARIADB_MAJOR = 10\nconst MIN_MARIADB_MINOR = 5\n\n/**\n * Parsed shape returned by `parseMysqlVersion`. `flavor` lets\n * adopters distinguish MySQL from MariaDB without re-grepping the\n * raw string.\n */\nexport interface ParsedMysqlVersion {\n  flavor: 'mysql' | 'mariadb'\n  major: number\n  minor: number\n}\n\n/**\n * Parse a MySQL `SELECT VERSION()` string. Handles:\n *\n *   - MySQL: `8.0.34`, `8.4.0`, `5.7.42-log`\n *   - MariaDB plain: `10.6.11-MariaDB`, `10.5.21-MariaDB-log`,\n *                    `10.4.32-MariaDB`\n *   - MariaDB w/ compat prefix: `5.5.5-10.6.11-MariaDB-1:10.6.11+maria~ubu2004`\n *     (the leading `5.5.5-` is a wire-protocol thing for older MySQL\n *     clients; the real server version sits immediately before\n *     `-MariaDB`)\n *\n * Returns `null` on unparseable input.\n */\nexport function parseMysqlVersion(version: string): ParsedMysqlVersion | null {\n  const trimmed = version.trim()\n  const isMariaDb = /MariaDB/i.test(trimmed)\n\n  if (isMariaDb) {\n    // Pull the `major.minor` that sits immediately before\n    // `-MariaDB`. This skips the `5.5.5-` compat prefix when\n    // present and grabs the real server version regardless of\n    // whether one's there.\n    const m = /(\\d+)\\.(\\d+)(?:\\.\\d+)?-MariaDB/i.exec(trimmed)\n    if (m) {\n      const major = Number(m[1])\n      const minor = Number(m[2])\n      if (Number.isFinite(major) && Number.isFinite(minor)) {\n        return { flavor: 'mariadb', major, minor }\n      }\n    }\n    // Fallback for vendor strings we haven't seen — try the\n    // leading x.y. Better to surface the wrong floor than to\n    // refuse an otherwise valid MariaDB outright.\n    const fallback = /^(\\d+)\\.(\\d+)/.exec(trimmed)\n    if (!fallback) return null\n    const major = Number(fallback[1])\n    const minor = Number(fallback[2])\n    if (!Number.isFinite(major) || !Number.isFinite(minor)) return null\n    return { flavor: 'mariadb', major, minor }\n  }\n\n  // MySQL: leading x.y from the start of the string.\n  const m = /^(\\d+)\\.(\\d+)/.exec(trimmed)\n  if (!m) return null\n  const major = Number(m[1])\n  const minor = Number(m[2])\n  if (!Number.isFinite(major) || !Number.isFinite(minor)) return null\n  return { flavor: 'mysql', major, minor }\n}\n\n/**\n * Back-compat shim — pre-existing API surface that returned the\n * major version only. Kept exported so adopters depending on it\n * keep working; new code should use `parseMysqlVersion`.\n *\n * @deprecated Use `parseMysqlVersion` for full version + flavor info.\n */\nexport function parseMysqlMajorVersion(version: string): number | null {\n  const parsed = parseMysqlVersion(version)\n  return parsed?.major ?? null\n}\n\n/**\n * Returns the failure reason if the parsed version doesn't satisfy\n * kickjs-db's floor, or `null` if it does. Pure — no I/O.\n */\nfunction checkVersionSupport(parsed: ParsedMysqlVersion | null, raw: string): string | null {\n  if (parsed == null) {\n    return `unparseable version string: ${raw || '<empty>'}`\n  }\n  if (parsed.flavor === 'mariadb') {\n    if (parsed.major > MIN_MARIADB_MAJOR) return null\n    if (parsed.major < MIN_MARIADB_MAJOR) {\n      return `MariaDB ${MIN_MARIADB_MAJOR}.${MIN_MARIADB_MINOR}+ required (detected: ${raw})`\n    }\n    if (parsed.minor < MIN_MARIADB_MINOR) {\n      return `MariaDB ${MIN_MARIADB_MAJOR}.${MIN_MARIADB_MINOR}+ required (detected: ${raw})`\n    }\n    return null\n  }\n  // MySQL flavor.\n  if (parsed.major < MIN_MYSQL_MAJOR) {\n    return `MySQL ${MIN_MYSQL_MAJOR}.0+ required (detected: ${raw})`\n  }\n  return null\n}\n\n/**\n * Split a SQL blob into individual statements at the top-level `;`\n * boundary. Respects single-quote / double-quote / backtick string\n * literals AND `--` line comments + C-style block comments —\n * `;` inside any of those does not terminate a statement.\n *\n * mysql2's default `Pool.query()` rejects multi-statement SQL unless\n * the driver was created with `multipleStatements: true`. Splitting\n * lets the adapter run kickjs-emitted DDL (multi-statement, but\n * always semicolon-separated at the top level) without that flag.\n *\n * Two MySQL-specific quirks the splitter handles:\n *\n *   - **`--` comments require trailing whitespace/end-of-input.**\n *     Per MySQL docs, `--` is only a line-comment introducer when\n *     followed by whitespace (space/tab/newline) or end-of-input —\n *     otherwise it's two unary-minus operators (`5--3` evaluates\n *     to `8`). Bare `--xyz` is a parse error in MySQL but kickjs\n *     should pass it through unchanged so the driver surfaces the\n *     real error, not silently swallow the rest of the line.\n *   - **Doubled-quote string escapes.** MySQL accepts both\n *     backslash-escapes (`'it\\'s'`) and SQL-standard doubled-quote\n *     escapes (`'it''s'`). The state machine peeks for the doubled\n *     form and stays in-string. Same rule applies to `\"\"` inside\n *     double-quoted strings.\n *\n * Adopter-written migrations with pathological SQL — e.g. `;` in\n * an unterminated block comment — won't split correctly.\n * Documented in the README; turn on `multipleStatements: true` on\n * the pool if you hit it.\n */\nexport function splitMysqlStatements(sql: string): string[] {\n  const out: string[] = []\n  let buf = ''\n  let inSingle = false\n  let inDouble = false\n  let inBacktick = false\n  let inLineComment = false\n  let inBlockComment = false\n\n  const isCommentWhitespace = (c: string) =>\n    c === ' ' || c === '\\t' || c === '\\n' || c === '\\r' || c === '\\f' || c === '\\v'\n\n  for (let i = 0; i < sql.length; i++) {\n    const ch = sql[i]\n    const next = i + 1 < sql.length ? sql[i + 1] : ''\n    const after = i + 2 < sql.length ? sql[i + 2] : ''\n\n    if (inLineComment) {\n      buf += ch\n      if (ch === '\\n') inLineComment = false\n      continue\n    }\n    if (inBlockComment) {\n      buf += ch\n      if (ch === '*' && next === '/') {\n        buf += next\n        i++\n        inBlockComment = false\n      }\n      continue\n    }\n    if (inSingle) {\n      // Doubled `''` is an SQL-standard escape — stay in-string.\n      if (ch === \"'\" && next === \"'\") {\n        buf += ch\n        buf += next\n        i++\n        continue\n      }\n      buf += ch\n      if (ch === '\\\\' && next !== '') {\n        buf += next\n        i++\n        continue\n      }\n      if (ch === \"'\") inSingle = false\n      continue\n    }\n    if (inDouble) {\n      // Doubled `\"\"` is an SQL-standard escape — stay in-string.\n      if (ch === '\"' && next === '\"') {\n        buf += ch\n        buf += next\n        i++\n        continue\n      }\n      buf += ch\n      if (ch === '\\\\' && next !== '') {\n        buf += next\n        i++\n        continue\n      }\n      if (ch === '\"') inDouble = false\n      continue\n    }\n    if (inBacktick) {\n      buf += ch\n      if (ch === '`') inBacktick = false\n      continue\n    }\n\n    // `--` is a comment introducer only when followed by whitespace\n    // (or end-of-input). Anything else (`5--3`, `--xyz`) is left as\n    // operator-soup and the driver decides what to do with it.\n    if (ch === '-' && next === '-' && (after === '' || isCommentWhitespace(after))) {\n      buf += ch\n      inLineComment = true\n      continue\n    }\n    if (ch === '/' && next === '*') {\n      buf += ch\n      inBlockComment = true\n      continue\n    }\n    if (ch === \"'\") {\n      buf += ch\n      inSingle = true\n      continue\n    }\n    if (ch === '\"') {\n      buf += ch\n      inDouble = true\n      continue\n    }\n    if (ch === '`') {\n      buf += ch\n      inBacktick = true\n      continue\n    }\n    if (ch === ';') {\n      const trimmed = buf.trim()\n      if (trimmed.length > 0) out.push(trimmed)\n      buf = ''\n      continue\n    }\n    buf += ch\n  }\n\n  const tail = buf.trim()\n  if (tail.length > 0) out.push(tail)\n  return out\n}\n\n/**\n * MigrationAdapter implementation backed by mysql2.\n *\n * Asserts MySQL 8.0+ (or MariaDB 10.5+) on first connection (via\n * the first `ensureMigrationTables` call, lazily — no I/O at\n * construction time). Earlier versions throw `KickDbError` with\n * code `KICK_DB_RELATIONAL_NOT_SUPPORTED` carrying the detected\n * version so adopters get a clear error before any query reaches\n * the relational compiler.\n *\n * Multi-statement support: every `query()` call splits the SQL\n * blob at top-level semicolons and runs each statement\n * sequentially. Works against mysql2's default settings; adopters\n * who set `multipleStatements: true` on the pool pay no extra\n * cost (the split is cheap on small DDL blobs).\n *\n * Lock semantics: single-row UPDATE WHERE locked_at IS NULL on\n * `kick_migrations_lock`. Only the row created by\n * `ensureMigrationTables()` exists, so the UPDATE either flips\n * `locked_at` and returns `affectedRows=1` (we won) or matches\n * zero rows (someone else holds it).\n *\n * Introspection: not implemented in v1 — throws `KickDbError` with\n * code `KICK_DB_INTROSPECT_NOT_SUPPORTED`. Drift detection lands\n * in a follow-up that walks `information_schema`.\n */\nexport function mysqlAdapter(opts: MysqlAdapterOptions): MigrationAdapter {\n  const dialect: Dialect = 'mysql'\n  const { pool } = opts\n  let versionVerified = false\n\n  async function assertVersion() {\n    if (versionVerified) return\n    const [rows] = await pool.query<{ version: string }[]>(`SELECT VERSION() AS \\`version\\``)\n    const versionString = rows[0]?.version ?? ''\n    const parsed = parseMysqlVersion(versionString)\n    const failure = checkVersionSupport(parsed, versionString)\n    if (failure) {\n      throw new KickDbError(\n        'KICK_DB_RELATIONAL_NOT_SUPPORTED',\n        `${failure}. JSON_ARRAYAGG (required by the relational query layer) shipped in ` +\n          `MySQL 8.0 and MariaDB 10.5. Use layer-1/layer-2 queries (selectFrom / selectAll) ` +\n          `on older versions.`,\n      )\n    }\n    versionVerified = true\n  }\n\n  /**\n   * Run a (possibly multi-statement) SQL blob via the pool,\n   * splitting at top-level `;` so default mysql2 settings work.\n   */\n  async function runStatements(sql: string): Promise<void> {\n    for (const stmt of splitMysqlStatements(sql)) {\n      await pool.query(stmt)\n    }\n  }\n\n  /**\n   * Same as `runStatements` but on a held connection (used inside\n   * `applySqlInTx` so all statements share the BEGIN / COMMIT\n   * boundary).\n   */\n  async function runStatementsOnConn(conn: MysqlConnectionLike, sql: string): Promise<void> {\n    for (const stmt of splitMysqlStatements(sql)) {\n      await conn.query(stmt)\n    }\n  }\n\n  return {\n    dialect,\n\n    async ensureMigrationTables() {\n      await assertVersion()\n      await runStatements(migrationsTableDdl(dialect))\n      await runStatements(lockTableDdl(dialect))\n    },\n\n    async listApplied(): Promise<MigrationRow[]> {\n      const [rows] = await pool.query<\n        Array<{\n          id: string\n          name: string\n          hash: string\n          batch: number\n          applied_at: string | Date\n          direction: 'up' | 'down'\n        }>\n      >(\n        `SELECT id, name, hash, batch, applied_at, direction\n         FROM \\`kick_migrations\\`\n         ORDER BY applied_at ASC, id ASC`,\n      )\n      return rows.map((row) => ({\n        id: row.id,\n        name: row.name,\n        hash: row.hash,\n        batch: Number(row.batch),\n        appliedAt:\n          row.applied_at instanceof Date ? row.applied_at.toISOString() : String(row.applied_at),\n        direction: row.direction,\n      }))\n    },\n\n    async recordApplied(row) {\n      await pool.query(\n        `INSERT INTO \\`kick_migrations\\` (id, name, hash, batch, direction)\n         VALUES (?, ?, ?, ?, ?)`,\n        [row.id, row.name, row.hash, row.batch, row.direction],\n      )\n    },\n\n    async removeApplied(id: string) {\n      await pool.query(`DELETE FROM \\`kick_migrations\\` WHERE id = ?`, [id])\n    },\n\n    async acquireLock(owner: string): Promise<boolean> {\n      const [result] = await pool.query<{ affectedRows: number }>(\n        `UPDATE \\`kick_migrations_lock\\`\n         SET locked_at = CURRENT_TIMESTAMP, locked_by = ?\n         WHERE id = 1 AND locked_at IS NULL`,\n        [owner],\n      )\n      return result.affectedRows === 1\n    },\n\n    async releaseLock() {\n      await pool.query(\n        `UPDATE \\`kick_migrations_lock\\`\n         SET locked_at = NULL, locked_by = NULL\n         WHERE id = 1`,\n      )\n    },\n\n    async applySqlInTx(sql: string) {\n      const conn = await pool.getConnection()\n      try {\n        await conn.query('START TRANSACTION')\n        await runStatementsOnConn(conn, sql)\n        await conn.query('COMMIT')\n      } catch (err) {\n        await conn.query('ROLLBACK').catch(() => {\n          // Swallow rollback errors; we're already throwing the original.\n        })\n        throw err\n      } finally {\n        conn.release()\n      }\n    },\n\n    async applySqlNoTx(sql: string) {\n      await runStatements(sql)\n    },\n\n    async introspect(): Promise<SchemaSnapshot> {\n      // Reverse-engineer the live schema via information_schema. Types come\n      // back as the declared COLUMN_TYPE (a code-first `uuid()` reads as\n      // `char(36)`), so this powers `kick db introspect`; byte-exact drift\n      // against a code-first snapshot needs a dialect-normalised compare.\n      return introspectMysql(pool)\n    },\n\n    async close() {\n      // Caller owns the pool. The adapter doesn't end() it —\n      // adopters typically share the same pool with the\n      // KickDbClient.\n    },\n  }\n}\n","// mysqlDialect — thin factory over Kysely's MysqlDialect so adopters\n// never have to reach for `import { MysqlDialect } from 'kysely'`.\n// Mirrors the `@forinda/kickjs-db/pg` template; the kysely subpackage\n// is a pinned internal dep of the framework.\n\nimport { MysqlDialect, type Dialect as KyselyDialect } from 'kysely'\nimport { markDialect } from '../../dialect-marker'\n\nimport type { MysqlPoolLike } from './adapter'\n\nexport interface MysqlDialectOptions {\n  /**\n   * mysql2-compatible pool. Both `mysql.createPool(...)` from\n   * `mysql2/promise` and `mysql2.createPool(...)` (callback API\n   * wrapped in a promise) match structurally.\n   */\n  pool: MysqlPoolLike\n}\n\n/**\n * Construct the dialect that `createDbClient({ dialect })` consumes.\n *\n * **MySQL 8.0+ required.** Kickjs-db's relational query layer\n * compiles to `JSON_ARRAYAGG`, which shipped in 8.0. Adapter-side\n * version assertion lands at first connection from `mysqlAdapter()`;\n * see that factory's docs.\n *\n * @example\n * ```ts\n * import { createDbClient } from '@forinda/kickjs-db'\n * import { mysqlAdapter, mysqlDialect } from '@forinda/kickjs-db/mysql'\n * import { createPool } from 'mysql2/promise'\n *\n * const pool = createPool({\n *   host: '127.0.0.1', user: 'root', password: '...', database: 'app',\n * })\n *\n * export const db = createDbClient({\n *   schema,\n *   dialect: mysqlDialect({ pool }),\n * })\n *\n * export const migrationAdapter = mysqlAdapter({ pool })\n * ```\n */\nexport function mysqlDialect(opts: MysqlDialectOptions): KyselyDialect {\n  // MysqlDialect's `pool` parameter is typed as `mysql2.Pool` in\n  // newer Kysely versions; casting through `unknown` keeps adopters\n  // using compatible drivers (e.g. mysql-mariadb forks) working\n  // without pulling mysql2's typings into our public surface.\n  return markDialect(new MysqlDialect({ pool: opts.pool as unknown as never }), 'mysql')\n}\n"],"mappings":"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"}