Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | import {library} from '@feasibleone/blong'; import type {TObject} from 'typebox'; interface IColumnSchema { type?: string; format?: string; maxLength?: number; default?: unknown; } export default library( ({config}) => { function addColumn( // eslint-disable-next-line @typescript-eslint/no-explicit-any table: any, columnName: string, prop: IColumnSchema, isNullable: boolean, ): void { // eslint-disable-next-line @typescript-eslint/no-explicit-any let column: any; if (columnName.endsWith('Id') && prop.type === 'integer') { column = table.increments(columnName); return; } switch (prop.type) { case 'string': if (prop.format === 'date-time' || prop.format === 'datetime') column = table.dateTime(columnName); else if (prop.format === 'date') column = table.date(columnName); else if (prop.format === 'time') column = table.time(columnName); else if (prop.format === 'uuid') column = table.uuid(columnName); else if (prop.maxLength != null && prop.maxLength > 255) column = table.text(columnName); else column = table.string(columnName, prop.maxLength ?? 255); break; case 'number': column = table.double(columnName); break; case 'integer': column = table.integer(columnName); break; case 'boolean': column = table.boolean(columnName); break; case 'array': case 'object': column = table.json(columnName); break; default: column = table.text(columnName); break; } if (isNullable) column.nullable(); else column.notNullable(); if (prop.default !== undefined) column.defaultTo(prop.default); } return async function schemaTableSync( tableName: string, schema: TObject, options: {dropColumns?: boolean} = {}, ): Promise<{created: boolean; added: string[]; dropped: string[]}> { // eslint-disable-next-line @typescript-eslint/no-explicit-any const knex = (config as Record<string, any>)?.context?.queryBuilder; if (!knex) throw new Error('Knex queryBuilder not available in adapter context'); const required = new Set(schema.required ?? []); const schemaProps = Object.keys(schema.properties); const exists = await knex.schema.hasTable(tableName); if (!exists) { // eslint-disable-next-line @typescript-eslint/no-explicit-any await knex.schema.createTable(tableName, (table: any) => { for (const [name, prop] of Object.entries(schema.properties)) { addColumn(table, name, prop as IColumnSchema, !required.has(name)); } }); return {created: true, added: schemaProps, dropped: []}; } const columnInfo = await knex(tableName).columnInfo(); const existingColumns = new Set(Object.keys(columnInfo)); const added: string[] = []; const dropped: string[] = []; // eslint-disable-next-line @typescript-eslint/no-explicit-any await knex.schema.alterTable(tableName, (table: any) => { for (const [name, prop] of Object.entries(schema.properties)) { if (!existingColumns.has(name)) { addColumn(table, name, prop as IColumnSchema, true); added.push(name); } } if (options.dropColumns) { for (const col of existingColumns) { if (!schemaProps.includes(col)) { table.dropColumn(col); dropped.push(col); } } } }); return {created: false, added, dropped}; }; }, ); |