parpeoficial/stackerjs-orm

View on GitHub
src/Util.js

Summary

Maintainability
C
1 day
Test Coverage
import { DB } from "stackerjs-db";

export class Util 
{
    static async makeEntity(defaultEntity, attributes, withs = []) 
    {
        if (Array.isArray(withs)) withs = this.prepareAssociations(withs);

        let entity = Object.create(defaultEntity),
            properties = {
                _attributes: {
                    value: attributes
                }
            },
            relations = {};

        this.makeEntityFields(properties, attributes, defaultEntity.metadata());
        Object.defineProperties(entity, properties);

        await this.makeEntityRelations(
            relations,
            entity,
            defaultEntity.metadata(),
            withs
        );
        Object.defineProperties(entity, relations);

        return entity;
    }

    static fieldValueParser(type, value) 
    {
        if (type === "boolean") return value === 1;
        else if (type === "date") return value ? new Date(value) : null;
        else if (type === "json") 
        {
            try 
            {
                return JSON.parse(value);
            }
            catch (err) 
            {
                return value;
            }
        }
        else if (type === "created_at" || type === "updated_at")
            return value ? value * 1000 : null;

        return value;
    }

    static MANYMANYAssociation(entity, relation, withs = []) 
    {
        let expr = DB.Factory.getQueryCriteria();
        let queryBuilder = DB.Factory.getQueryBuilder()
            .select()
            .from(relation.table)
            .set(`${relation.referencedEntity.metadata().table}.*`)
            .join(
                "INNER",
                relation.referencedEntity.metadata().table,
                `${relation.table}.${relation.referencedField} = ` +
                `${relation.referencedEntity.metadata().table}.id`
            )
            .where(expr.eq(relation.field, entity["_attributes"]["id"]));

        return () =>
            queryBuilder
                .execute()
                .then(results =>
                    Promise.all(results.map(result =>
                        this.makeEntity(
                            relation.referencedEntity,
                            result,
                            withs
                        ))));
    }

    static HASONEAssociation(entity, relation, withs = []) 
    {
        let expr = DB.Factory.getQueryCriteria();
        let queryBuilder = DB.Factory.getQueryBuilder()
            .select()
            .from(relation.referencedEntity.metadata().table)
            .set("*")
            .where(expr.eq(
                relation.referencedField,
                entity["_attributes"][relation.field]
            ))
            .limit(1);

        return () =>
            queryBuilder.execute().then(results => 
            {
                if (results.length <= 0) return Promise.resolve(null);

                return this.makeEntity(
                    relation.referencedEntity,
                    results[0],
                    withs
                );
            });
    }

    static HASMANYAssociation(entity, relation, withs = []) 
    {
        let expr = DB.Factory.getQueryCriteria();
        let queryBuilder = DB.Factory.getQueryBuilder()
            .select()
            .from(relation.referencedEntity.metadata().table)
            .set("*")
            .where(expr.eq(
                relation.referencedField,
                entity["_attributes"][relation.field]
            ));

        return () =>
            queryBuilder
                .execute()
                .then(results =>
                    Promise.all(results.map(result =>
                        this.makeEntity(
                            relation.referencedEntity,
                            result,
                            withs
                        ))));
    }

    static makeEntityFields(properties, attributes, metadata) 
    {
        metadata.fields.forEach(field => 
        {
            if (typeof attributes[field.name] !== "undefined") 
            {
                let name = field.alias ? field.alias : field.name;
                properties[name] = {
                    enumerable: true,
                    writable: true,
                    value: this.fieldValueParser(
                        field.type,
                        attributes[field.name]
                    )
                };
                properties._attributes.value[
                    field.name
                ] = this.fieldValueParser(field.type, attributes[field.name]);
            }
        });
    }

    static async makeEntityRelations(
        properties,
        entity,
        metadata,
        withs
    ) 
    {
        await Promise.all(metadata.relations.map(async relation => 
        {
            let relationGetter = chainedWiths => 
            {
                if (relation.type === "HASMANY")
                    return this.HASMANYAssociation(
                        entity,
                        relation,
                        chainedWiths
                    )();
                else if (
                    relation.type === "HASONE" ||
                    relation.type === "BELONGSTO"
                )
                    return this.HASONEAssociation(
                        entity,
                        relation,
                        chainedWiths
                    )();
                else if (relation.type === "MANYMANY")
                    return this.MANYMANYAssociation(
                        entity,
                        relation,
                        chainedWiths
                    )();

                return null;
            };

            properties[relation.name] = {
                enumerable: typeof withs[relation.name] !== "undefined"
            };

            if (withs[relation.name])
                properties[relation.name].value = await relationGetter(withs[relation.name]);
            else properties[relation.name].get = relationGetter;
        }));
    }

    static prepareAssociations(withs) 
    {
        let associations = {};
        withs.forEach(w => 
        {
            w = w.split(".");
            if (w[1]) associations[w[0]] = this.prepareAssociations(w.slice(1));
            else associations[w[0]] = {};
        });

        return associations;
    }
}