UNPKG

type-surrealdb

Version:

Typescript support and class utils for SurrealDB

184 lines (183 loc) 7.71 kB
"use strict"; /* eslint-disable @typescript-eslint/no-explicit-any */ Object.defineProperty(exports, "__esModule", { value: true }); exports.TableSchema = void 0; exports.Field = Field; exports.Table = Table; exports.generateSurqlSchema = generateSurqlSchema; class TableSchema { } exports.TableSchema = TableSchema; function initializeSchema(constructor) { if (!constructor.SurrealdbSchema) { constructor.SurrealdbSchema = { tables: [], properties: {}, }; } else if (!constructor.SurrealdbSchema.properties) { constructor.SurrealdbSchema.properties = {}; } // Check if the class has a parent class with SurrealdbSchema const parentConstructor = Object.getPrototypeOf(constructor); if (parentConstructor === null || parentConstructor === void 0 ? void 0 : parentConstructor.SurrealdbSchema) { // Merge the parent's properties into the child's properties constructor.SurrealdbSchema.properties = Object.assign(Object.assign({}, parentConstructor.SurrealdbSchema.properties), constructor.SurrealdbSchema.properties); } // Process nested objects for (const [_key, value] of Object.entries(constructor.SurrealdbSchema.properties)) { if (value.type === 'object' && value.object) { // Ensure that nested schemas are initialized initializeSchema(value.object); } } } function Field(args) { return (target, propertyKey) => { if (!target || typeof propertyKey === 'undefined') { throw new Error('Invalid target or propertyKey in Field decorator.'); } let field; if (typeof args === 'string') { field = { type: args }; } else { field = Object.assign({}, args); } if (field.type === 'object' && 'object' in field) { field.properties = field.object.SurrealdbSchema.properties || {}; } initializeSchema(target.constructor); target.constructor.SurrealdbSchema.properties[propertyKey] = field; }; } /** * This will add the "name" field to the static schema object. While the name could be inferred from the class's * constructor, it is required because obfuscating the JS bundle in production builds changes the class names, and thus * produces inconsistent or duplicate SurrealDB table names. * @param name The table name in SurrealDB. This can be different from the class name */ function Table(config) { return (constructor) => { var _a; initializeSchema(constructor); if (typeof config === 'string') { constructor.SurrealdbSchema.tables = [config]; constructor.SurrealdbSchema.schemaMode = 'SCHEMALESS'; } else if (Array.isArray(config)) { constructor.SurrealdbSchema.tables = config; constructor.SurrealdbSchema.schemaMode = 'SCHEMALESS'; } else { constructor.SurrealdbSchema.tables = config.tables; constructor.SurrealdbSchema.schemaMode = (_a = config.schemaMode) !== null && _a !== void 0 ? _a : 'SCHEMALESS'; constructor.SurrealdbSchema.indexes = config.indexes; } }; } function generateSurqlSchema(entities, comments = false) { const schemaParts = []; // function addFieldDefinition(tableName, tableGeneric, fieldName, fieldConfig) { var _a; const fieldDefinition = [`DEFINE FIELD ${fieldName} ON ${tableName}`]; let fieldtype; if (fieldConfig.primary) { fieldtype = `record<${tableName}>`; } else if (fieldConfig.type === 'object' && 'properties' in fieldConfig) { fieldtype = `object`; } else if ('typed' in fieldConfig && fieldConfig.typed) { const fieldtyped = fieldConfig.typed === '$$generic' ? tableGeneric : fieldConfig.typed; fieldtype = `${fieldConfig.type}<${fieldtyped}>`; } else { fieldtype = fieldConfig.type === '$$generic' ? (tableGeneric !== null && tableGeneric !== void 0 ? tableGeneric : 'any') : ((_a = fieldConfig.type) !== null && _a !== void 0 ? _a : 'any'); } if (fieldConfig.optional) { fieldDefinition.push(`TYPE option<${fieldtype}>`); } else { fieldDefinition.push(`TYPE ${fieldtype}`); } if (fieldConfig.default) { fieldDefinition.push(`DEFAULT ${fieldConfig.default}`); } if (fieldConfig.value) { fieldDefinition.push(`VALUE ${fieldConfig.value}`); } if (fieldConfig.assertion) { fieldDefinition.push(`ASSERT ${fieldConfig.assertion}`); } schemaParts.push(`${fieldDefinition.join(' ')};`); // Recursively define nested fields if (fieldConfig.type === 'object' && 'properties' in fieldConfig) { for (const [nestedFieldName, nestedFieldConfig] of Object.entries(fieldConfig.properties)) { addFieldDefinition(tableName, tableGeneric, `${fieldName}.${nestedFieldName}`, nestedFieldConfig); } } } // function addIndexDefinition(tableName, fieldName, fieldConfig) { if (fieldConfig.primary || fieldConfig.indexed || fieldConfig.unique) { const indexDefinition = [ `DEFINE INDEX idx_${tableName}_${fieldName} ON ${tableName} FIELDS ${fieldName}`, ]; if (fieldConfig.primary || fieldConfig.unique) indexDefinition.push('UNIQUE'); schemaParts.push(`${indexDefinition.join(' ')};`); } } // function addTableIndexes(tableName, indexes) { indexes === null || indexes === void 0 ? void 0 : indexes.forEach(index => { var _a; const indexDefinition = [ `DEFINE INDEX ${(_a = index.name) !== null && _a !== void 0 ? _a : `idx_${tableName}_${index.fields.join('_')}`} ON ${tableName} FIELDS ${index.fields.join(', ')}`, ]; if (index.unique) indexDefinition.push('UNIQUE'); schemaParts.push(`${indexDefinition.join(' ')};`); }); } // start schema generation for (const entity of entities) { const { tables, schemaMode, indexes, properties } = entity.SurrealdbSchema; for (const table of tables) { let tableName; let tableGeneric; if (typeof table === 'string') { tableName = table; tableGeneric = undefined; } else { tableName = table.name; tableGeneric = table.generic; } if (comments) { schemaParts.push('-- ------------------------------'); schemaParts.push(`-- TABLE: ${tableName}`); schemaParts.push('-- ------------------------------\n'); } // Begin table definition schemaParts.push(`DEFINE TABLE ${tableName} ${schemaMode};`); if (comments) schemaParts.push(''); // Define fields & indexes for (const [fieldName, fieldConfig] of Object.entries(properties)) { // Define field addFieldDefinition(tableName, tableGeneric, fieldName, fieldConfig); // Define index addIndexDefinition(tableName, fieldName, fieldConfig); } // Define table indexes addTableIndexes(tableName, indexes); // Separate each table definition schemaParts.push('\n'); } } return schemaParts.join('\n'); }