UNPKG

flint-orm

Version:

Type-safe SQLite ORM for JavaScript

444 lines (442 loc) 12.4 kB
// @bun var __create = Object.create; var __getProtoOf = Object.getPrototypeOf; var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; function __accessProp(key) { return this[key]; } var __toESMCache_node; var __toESMCache_esm; var __toESM = (mod, isNodeMode, target) => { var canCache = mod != null && typeof mod === "object"; if (canCache) { var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap; var cached = cache.get(mod); if (cached) return cached; } target = mod != null ? __create(__getProtoOf(mod)) : {}; const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target; for (let key of __getOwnPropNames(mod)) if (!__hasOwnProp.call(to, key)) __defProp(to, key, { get: __accessProp.bind(mod, key), enumerable: true }); if (canCache) cache.set(mod, to); return to; }; var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports); var __returnValue = (v) => v; function __exportSetter(name, newValue) { this[name] = __returnValue.bind(null, newValue); } var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true, configurable: true, set: __exportSetter.bind(all, name) }); }; var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res); var __require = import.meta.require; // src/schema/columns.ts function nullCast() { return null; } function makeColumn(config) { const base = { name: config.name, __internal: { _type: undefined, sqlType: config.sqlType, isPrimaryKey: false, isNotNull: false, isUnique: false, hasDefault: false, defaultValue: undefined, defaultFn: undefined, isAutoIncrement: false, hasDefaultNow: false, hasOnUpdate: false, referencesTable: null, referencesColumn: null, onDelete: null, onUpdate: null, encode: config.encode, decode: config.decode, tableName: null } }; const col = { ...base, primaryKey() { return { ...this, __internal: { ...this.__internal, isPrimaryKey: true } }; }, notNull() { return { ...this, __internal: { ...this.__internal, isNotNull: true } }; }, unique() { return { ...this, __internal: { ...this.__internal, isUnique: true } }; }, default(value) { return { ...this, __internal: { ...this.__internal, hasDefault: true, defaultValue: value } }; }, defaultFn(fn) { return { ...this, __internal: { ...this.__internal, hasDefault: true, defaultFn: fn } }; }, references(target) { return { ...this, __internal: { ...this.__internal, referencesTable: target.__internal.tableName, referencesColumn: target.name } }; }, onDelete(action) { return { ...this, __internal: { ...this.__internal, onDelete: action } }; }, onUpdate(action) { return { ...this, __internal: { ...this.__internal, onUpdate: action } }; } }; return col; } function text(name) { return makeColumn({ name: name ?? "", sqlType: "text", encode: (v) => v, decode: (v) => v == null ? nullCast() : v }); } function integer(name) { const base = makeColumn({ name: name ?? "", sqlType: "integer", encode: (v) => v, decode: (v) => v == null ? nullCast() : Number(v) }); const intCol = { ...base, primaryKey() { return { ...this, __internal: { ...this.__internal, isPrimaryKey: true } }; }, notNull() { return { ...this, __internal: { ...this.__internal, isNotNull: true } }; }, unique() { return { ...this, __internal: { ...this.__internal, isUnique: true } }; }, default(value) { return { ...this, __internal: { ...this.__internal, hasDefault: true, defaultValue: value } }; }, defaultFn(fn) { return { ...this, __internal: { ...this.__internal, hasDefault: true, defaultFn: fn } }; }, autoIncrement() { return { ...this, __internal: { ...this.__internal, isAutoIncrement: true } }; } }; return intCol; } function boolean(name) { return makeColumn({ name: name ?? "", sqlType: "integer", encode: (v) => v ? 1 : 0, decode: (v) => v == null ? nullCast() : Boolean(v) }); } function json(name) { return makeColumn({ name: name ?? "", sqlType: "text", encode: (v) => v == null ? null : JSON.stringify(v), decode: (v) => v == null ? nullCast() : JSON.parse(v) }); } function date(name) { const base = makeColumn({ name: name ?? "", sqlType: "integer", encode: (v) => v == null ? null : v.getTime(), decode: (v) => v == null ? nullCast() : new Date(v) }); const dateCol = { ...base, primaryKey() { return { ...this, __internal: { ...this.__internal, isPrimaryKey: true } }; }, notNull() { return { ...this, __internal: { ...this.__internal, isNotNull: true } }; }, unique() { return { ...this, __internal: { ...this.__internal, isUnique: true } }; }, default(value) { return { ...this, __internal: { ...this.__internal, hasDefault: true, defaultValue: value } }; }, defaultFn(fn) { return { ...this, __internal: { ...this.__internal, hasDefault: true, defaultFn: fn } }; }, defaultNow() { return { ...this, __internal: { ...this.__internal, hasDefaultNow: true } }; }, onUpdateTimestamp() { return { ...this, __internal: { ...this.__internal, hasOnUpdate: true } }; } }; return dateCol; } function real(name) { return makeColumn({ name: name ?? "", sqlType: "real", encode: (v) => v, decode: (v) => v == null ? nullCast() : Number(v) }); } // src/schema/table.ts function table(name, columns, indexFn) { const stamped = Object.create(null); for (const [key, col] of Object.entries(columns)) { const columnName = col.name || key; const stampedInternal = { ...col.__internal, name: columnName, tableName: name }; const stampedCol = { name: columnName, __internal: stampedInternal, primaryKey() { return { ...this, __internal: { ...stampedInternal, isPrimaryKey: true } }; }, notNull() { return { ...this, __internal: { ...stampedInternal, isNotNull: true } }; }, unique() { return { ...this, __internal: { ...stampedInternal, isUnique: true } }; }, default(value) { return { ...this, __internal: { ...stampedInternal, hasDefault: true, defaultValue: value } }; }, defaultFn(fn) { return { ...this, __internal: { ...stampedInternal, hasDefault: true, defaultFn: fn } }; }, references(target) { return { ...this, __internal: { ...stampedInternal, referencesTable: target.__internal.tableName, referencesColumn: target.name } }; }, onDelete(action) { return { ...this, __internal: { ...stampedInternal, onDelete: action } }; }, onUpdate(action) { return { ...this, __internal: { ...stampedInternal, onUpdate: action } }; } }; if ("autoIncrement" in col) { stampedCol.autoIncrement = function() { return { ...this, __internal: { ...stampedInternal, isAutoIncrement: true } }; }; } if ("defaultNow" in col) { stampedCol.defaultNow = function() { return { ...this, __internal: { ...stampedInternal, hasDefaultNow: true } }; }; } if ("onUpdateTimestamp" in col) { stampedCol.onUpdateTimestamp = function() { return { ...this, __internal: { ...stampedInternal, hasOnUpdate: true } }; }; } stamped[key] = stampedCol; } const result = Object.assign(stamped, { _: { name } }); if (indexFn) { const raw = indexFn(result); if (raw.length > 0) { const tableObj = result; const indexes = []; let primaryKeyDef; for (const item of raw) { if (item && typeof item === "object" && "_type" in item) { if (item._type === "primaryKey") { primaryKeyDef = item.build(); } else { indexes.push(item.build()); } } } if (primaryKeyDef) { for (const [key, col] of Object.entries(columns)) { if (col.__internal.isPrimaryKey) { throw new Error(`Column "${key}" has primaryKey() but table "${name}" also defines a composite primaryKey(). Use one or the other.`); } } tableObj.__primaryKey = primaryKeyDef; } if (indexes.length > 0) { tableObj.__indexes = indexes; } } } return result; } function toSnakeCase(str) { return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`); } function snakeCaseTable(tableName, columns, indexFn) { const converted = {}; for (const [key, col] of Object.entries(columns)) { const sqlName = toSnakeCase(key); const columnName = col.name || sqlName; const stampedInternal = { ...col.__internal, name: columnName, tableName }; const stampedCol = { name: columnName, __internal: stampedInternal, primaryKey() { return { ...this, __internal: { ...stampedInternal, isPrimaryKey: true } }; }, notNull() { return { ...this, __internal: { ...stampedInternal, isNotNull: true } }; }, unique() { return { ...this, __internal: { ...stampedInternal, isUnique: true } }; }, default(value) { return { ...this, __internal: { ...stampedInternal, hasDefault: true, defaultValue: value } }; }, defaultFn(fn) { return { ...this, __internal: { ...stampedInternal, hasDefault: true, defaultFn: fn } }; }, references(target) { return { ...this, __internal: { ...stampedInternal, referencesTable: target.__internal.tableName, referencesColumn: target.name } }; }, onDelete(action) { return { ...this, __internal: { ...stampedInternal, onDelete: action } }; }, onUpdate(action) { return { ...this, __internal: { ...stampedInternal, onUpdate: action } }; } }; if ("autoIncrement" in col) { stampedCol.autoIncrement = function() { return { ...this, __internal: { ...stampedInternal, isAutoIncrement: true } }; }; } if ("defaultNow" in col) { stampedCol.defaultNow = function() { return { ...this, __internal: { ...stampedInternal, hasDefaultNow: true } }; }; } if ("onUpdateTimestamp" in col) { stampedCol.onUpdateTimestamp = function() { return { ...this, __internal: { ...stampedInternal, hasOnUpdate: true } }; }; } converted[key] = stampedCol; } return table(tableName, converted, indexFn); } var snakeCase = { table: snakeCaseTable }; function primaryKey() { let columns = []; const builder = { _type: "primaryKey", on(...cols) { columns = cols; return builder; }, build() { if (columns.length === 0) { throw new Error("primaryKey() has no columns \u2014 call .on() before returning"); } return { columns: columns.map((c) => c.name) }; } }; return builder; } function index(name) { let columns = []; let isUnique = false; const builder = { _type: "index", on(...cols) { columns = cols; return builder; }, unique() { isUnique = true; return builder; }, build() { if (columns.length === 0) { throw new Error(`Index "${name}" has no columns \u2014 call .on() before returning`); } return { name, columns: columns.map((c) => c.name), unique: isUnique }; } }; return builder; } export { text, table, snakeCase, real, primaryKey, json, integer, index, date, boolean };