nuvira-parser
Version:
Nuvira Database. New Database format (Readable & Easy to use), (Inbuilt Schema & constraints & rules & relations).
191 lines (167 loc) • 5.47 kB
text/typescript
interface JsonRecord {
[key: string]: any;
}
export class Convertor {
private format: 'JSON' | 'XML' | 'YAML' | 'SQL' | 'CSV';
constructor({ format }: { format: 'JSON' | 'XML' | 'YAML' | 'SQL' | 'CSV' }) {
this.format = format;
}
/**
* Main entry point for conversion.
* @param data - The input data to be converted.
* @returns Converted data in the specified format.
*/
async convert(data: any): Promise<any> {
const normalizedData = this.normalizeInput(data);
switch (this.format) {
case 'JSON':
return this.jsonConvertor(normalizedData);
default:
throw new Error(`Format "${this.format}" is not supported.`);
}
}
/**
* JSON Conversion Logic
* @param data - The normalized input data to be converted.
* @returns JSON converted to Nuvira format.
*/
private jsonConvertor(data: JsonRecord[]): string {
const schema = this.generateSchema(data);
const records = this.generateRecords(data);
return `@schema\n${schema}\n@end\n\n@records\n${records}\n@end`;
}
/**
* Generate the @schema section from the input data.
* @param data - Array of JSON records.
* @returns Schema in Nuvira format.
*/
private generateSchema(data: JsonRecord[]): string {
const types: Record<string, Set<string>> = {};
data.forEach((record) => {
Object.entries(record).forEach(([key, value]) => {
const type = this.inferType(value);
if (!types[key]) types[key] = new Set();
types[key].add(type);
});
});
return Object.entries(types)
.map(([key, typeSet]) => {
const type = [...typeSet].join(' | ');
return `${key} -> ${type}`;
})
.join('\n');
}
/**
* Generate the @records section from the input data.
* @param data - Array of JSON records.
* @returns Records in Nuvira format.
*/
private generateRecords(data: JsonRecord[]): string {
return data
.map((record, index) => {
const formattedFields = Object.entries(record)
.map(([key, value]) => `${key}${this.formatValue(value)}`)
.join(' ');
return `#${index} -> ${formattedFields}`;
})
.join('\n');
}
/**
* Helper: Infer the type of a value.
* @param value - The value to analyze.
* @returns Nuvira-compatible type.
*/
/**
* Helper: Infer the type of a value.
* @param value - The value to analyze.
* @returns Nuvira-compatible type.
*/
private inferType(value: any): string {
if (value === null) return 'Null';
if (value === undefined) return 'undefined';
if (typeof value === 'boolean') return 'Boolean';
if (typeof value === 'number') return 'Number';
if (typeof value === 'string') {
if (this.isValidDate(value)) return 'Date';
return 'String';
}
if (value instanceof Date) return 'Date';
if (Buffer.isBuffer(value)) return 'Binary';
if (Array.isArray(value)) {
const elementTypes = new Set(value.map((item) => this.inferType(item)));
if (elementTypes.size === 1) {
return `${[...elementTypes][0]}Array`;
}
return 'AnyArray';
}
if (typeof value === 'object') {
if (Array.isArray(Object.values(value)[0])) {
return 'ObjectArray';
}
return 'Object';
}
return 'Any';
}
/**
* Helper: Format a value into Nuvira format.
* @param value - The value to format.
*/
private formatValue(value: any): string {
if (value === null) return '(NULL);';
if (value === undefined) return '();';
if (typeof value === 'boolean') return value ? '(TRUE);' : '(FALSE);';
if (typeof value === 'number') return `(${value});`;
if (typeof value === 'string') {
if (this.isValidDate(value)) {
const parsedDate = this.parseDate(value);
if (parsedDate) return `(${parsedDate.toISOString()});`;
}
return `("${value}");`;
}
if (value instanceof Date) return `(${value.toISOString()});`;
if (Buffer.isBuffer(value)) return `(<Buffer ${[...value].join(' ')}>);`;
if (Array.isArray(value)) {
return `[ ${value
.map((item, index) => `_${index}${this.formatValue(item).slice(0, -1)};`)
.join(' ')} ];`;
}
if (typeof value === 'object') {
const objectProperties = Object.entries(value)
.map(([key, val]) => `${key}${this.formatValue(val).slice(0, -1)};`)
.join(' ');
return `{ ${objectProperties} };`;
}
return `("${value}");`;
}
/**
* Helper: Check if a value is a valid date.
* @param value - The value to check.
*/
private isValidDate(value: string): boolean {
return !isNaN(Date.parse(value));
}
/**
* Helper: Parse a date string into a Date object.
* @param value - The date string to parse.
*/
private parseDate(value: string): Date | null {
if (!isNaN(Date.parse(value))) {
return new Date(value);
}
return null;
}
/**
* Normalize input data: Wrap single objects into an array if necessary.
* @param data - Input data to normalize.
* @returns Array of records.
*/
private normalizeInput(data: any): JsonRecord[] {
if (Array.isArray(data)) {
return data;
}
if (typeof data === 'object' && data !== null) {
return [data];
}
throw new Error('Input data must be an object or an array of objects.');
}
}