UNPKG

adba

Version:
192 lines (191 loc) 9.08 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { Model } from 'objection'; import { deepMerge } from 'dbl-utils'; import { className } from './model-utilities'; /** * Generates SQLite models using Knex and the provided options for parsing and formatting. * @param knexInstance - The Knex instance connected to the SQLite database. * @param opts - The options containing parse and format functions. * @returns A promise that resolves to a record of models. */ export function generateSQLiteModels(knexInstance_1) { return __awaiter(this, arguments, void 0, function* (knexInstance, opts = {}) { const models = {}; const { relationsFunc, squemaFixings, parseFunc, formatFunc } = opts; try { // Query database structures from SQLite const structures = yield knexInstance('sqlite_master') .whereIn('type', ['table', 'view']) .select('name', 'type'); for (const { name: structureName, type } of structures) { // Get column information const columns = yield knexInstance.raw(`PRAGMA table_info("${structureName}")`).then(res => res.rows || res); const foreignKeys = yield knexInstance.raw(`PRAGMA foreign_key_list("${structureName}")`).then(res => res.rows || res); // Define a dynamic model class const DynamicModel = class extends Model { /** * Returns the table name for the model. */ static get tableName() { return structureName; } /** * Constructs the JSON schema based on the table structure. * @returns The JSON schema object for the table. */ static get jsonSchema() { const requiredFields = []; const schemaProperties = {}; for (const column of columns) { const format = mapSqliteTypeToJsonFormat(column.type, column.name); const type = mapSqliteTypeToJsonType(column.type); const property = { type: type !== 'buffer' ? type : undefined }; if (column.notnull && !column.dflt_value) { requiredFields.push(column.name); } if (column.comment) { property.description = column.comment; } if (/^(INT|INTEGER|REAL)$/i.test(column.type) && column.unsigned) { property.minimum = 0; } const lengthMatch = column.type.match(/\((\d+)\)/); if (lengthMatch && property.type === 'string' && lengthMatch[1]) { property.maxLength = parseInt(lengthMatch[1], 10); } property.$comment = [type, format].filter(Boolean).join('.'); const prefix = type === 'buffer' ? 'x-' : ''; schemaProperties[prefix + column.name] = property; } if (typeof squemaFixings === 'function') { const r = squemaFixings(structureName, schemaProperties); if (r) deepMerge(schemaProperties, r); } return { type: 'object', properties: schemaProperties, required: requiredFields.length ? requiredFields : undefined, }; } /** * Constructs relation mappings for the model. * @returns An object containing relation mappings. */ static get relationMappings() { const relations = {}; for (const fk of foreignKeys) { const RelatedModel = Object.values(models).find((Model) => Model.tableName === fk.table); if (!RelatedModel) { throw new Error(`${structureName}: Model for table ${fk.table} not found`); } relations[`${fk.table}`] = { relation: Model.BelongsToOneRelation, modelClass: RelatedModel, join: { from: `${structureName}.${fk.from}`, to: `${fk.table}.${fk.to}`, }, }; } if (typeof relationsFunc === 'function') { const r = relationsFunc(structureName, relations); if (r) Object.assign(relations, r); } return relations; } /** * Parses the database JSON. * @param json - The JSON object from the database. * @returns The parsed JSON object. */ $parseDatabaseJson(json) { json = super.$parseDatabaseJson(json); return typeof parseFunc === 'function' ? parseFunc(structureName, json) : json; } /** * Formats the JSON object for the database. * @param json - The JSON object to be formatted. * @returns The formatted JSON object. */ $formatDatabaseJson(json) { json = super.$formatDatabaseJson(json); return typeof formatFunc === 'function' ? formatFunc(structureName, json) : json; } }; const pascalCaseName = className(structureName); const suffix = type === 'table' ? 'Table' : 'View'; const modelName = `${pascalCaseName}${suffix}Model`; Object.defineProperty(DynamicModel, 'name', { value: modelName }); DynamicModel.knex(knexInstance); models[modelName] = DynamicModel; } } catch (err) { console.error('Error generating models:', err); } return models; }); } /** * Maps SQLite data types to corresponding JSON Schema types. * @param sqliteType - The SQLite data type. * @returns The JSON Schema type. */ export function mapSqliteTypeToJsonType(sqliteType) { const baseType = sqliteType.replace(/\([\d,]+\)/, '').toUpperCase(); const typeMap = { BOOLEAN: 'boolean', BINARY: 'buffer', BLOB: 'buffer', BIGINT: 'integer', INT: 'integer', INT2: 'integer', INT8: 'integer', INTEGER: 'integer', MEDIUMINT: 'integer', SMALLINT: 'integer', TINYINT: 'integer', DECIMAL: 'number', DOUBLE: 'number', FLOAT: 'number', NUMERIC: 'number', REAL: 'number', CHARACTER: 'string', CLOB: 'string', DATE: 'string', DATETIME: 'string', NCHAR: 'string', NVARCHAR: 'string', TEXT: 'string', TIME: 'string', VARCHAR: 'string', }; return typeMap[baseType] || 'string'; } /** * Maps SQLite data types to corresponding JSON Schema formats. * @param sqliteType - The SQLite data type. * @param colName - The column name for potential additional format inference. * @returns The JSON Schema format if applicable. */ export function mapSqliteTypeToJsonFormat(sqliteType, colName) { const baseType = sqliteType.replace(/\([\d,]+\)/, '').toUpperCase(); const typeMap = { DATE: 'date', DATETIME: 'datetime', TIME: 'time', }; return typeMap[baseType] || undefined; }