Newer
Older
ServerGenerator / src / DataAccessGenerator.ts
@peter peter on 12 Sep 2020 3 KB Added create operation.
import { Collection, Entity, Property } from "./MySchema";
import { FileWrite } from "./app";
import { modelModuleName } from "./ModelGenerator";

export function generateDataAccess(collections: Collection[]): FileWrite[] {
    return collections.map(generateDataAccessFile);
}

export function dataAccessModuleName(collection: Collection): string {
    return `${collection.name}DataAccess`;
}

function generateDataAccessFile(collection: Collection): FileWrite {
    const definitions: string[] = [
        defineImports(collection),
        defineSave(collection),
        defineParseEntity(collection.entities),
        defineParseCollection(collection),
        defineLoad(collection),
        defineGeneral(),
    ];

    return {
        location: dataAccessModuleName(collection) + ".ts",
        content: definitions.join("\n\n") + "\n",
    };
}

function defineImports(collection: Collection): string {
    const entity = collection.entities;
    return `import { ${collection.name}, ${entity.name} } from "./${modelModuleName(collection)}";
import * as fs from "fs";`;
}

function defineSave(collection: Collection): string {
    return `export function save(fileName: string, collection: ${collection.name}): void {
    const content = JSON.stringify({ ...collection, $schema: "./${collection.name.toLowerCase()}.schema.json" });
    fs.writeFileSync(fileName, content);
}`;
}

function defineGeneral(): string {
    return `function parseArrayProperty<O, T>(fieldName: keyof O, itemParser: (item: any) => T, data: any): T[]
{
    if(fieldName in data)
    {
        const valueList = data[fieldName];
        if(Array.isArray(valueList))
        {
            return valueList.map(itemParser);
        }
    }
    return [];
}

function parsePrimitiveProperty<O, T = string | number>(type: T extends string ? "string" : "number", fieldName: keyof O, defaultValue: T, obj: any): T
{
    if(fieldName in obj)
    {
        const fieldValue = obj[fieldName];
        if(typeof fieldValue === type)
        {
            return fieldValue;
        }
    }
    return defaultValue;
}

function canReadFile(path: string): boolean {
    try {
        fs.accessSync(path, fs.constants.R_OK);
        return true;
    } catch (error) {
        return false;
    }
}`;
}

function defineParseEntity(entity: Entity): string {
    const propParser = entity.properties.map(p => parseStringProperty(entity.name, p)).join("\n");
    return `function parse${entity.name}(data: any): ${entity.name}
{
    return {
        id: parsePrimitiveProperty<${entity.name}, number>("number", "id", 0, data),
${propParser}
    };
}`;
}

function parseStringProperty(entityName: string, property: Property): string {
    return `\t\t${property.key}: parsePrimitiveProperty<${entityName}, string>("string", "${property.key}", "", data),`;
}

function defineParseCollection(collection: Collection): string {
    return `function parse${collection.name}(data: any): ${collection.name} {
    return {
        nextId: parsePrimitiveProperty<${collection.name}, number>("number", "nextId", 1, data),
        items: parseArrayProperty<${collection.name}, ${collection.entities.name}>("items", parse${collection.entities.name}, data),
    };
}`;
}

function defineLoad(collection: Collection): string {
    return `export function load(fileName: string): ${collection.name} {
    if (!canReadFile(fileName)) {
        return {
            items: [],
            nextId: 1,
        };
    }
    const content = fs.readFileSync(fileName).toString();
    const data = JSON.parse(content);
    return parse${collection.name}(data);
}`;
}