Configuration over Coding

Configuration over Coding

Did you know CoC once unit test is success, your app usually ship with no bugs!

I prefer with configuration in javascript because javascript is a dynamically typed language. With this advantage we can easily deal with json, yaml or any configuration files. With configuration, i only have to write once, and next time only write when i required a new feature. But this ideal not really suitable work for many situation only for some situation that keep repeating same thing etc CMS System.

Example Configuration

Here is an example of my projects configuration model. This configuration would just handle all the CRUD, data-loader for performance, caching, admin app panel setting and the model definition. Example dataResolver is for data-loader here is load the associated table data example the products belongsTo the store. Service options is for CRUD, i can specify permission, multi create update or not.

const Sequelize = require('sequelize');

module.exports = {
    name: 'store',
    dataResolver: {
        before: (context) => {
            const { manyToMany } = context.app.get('populate');
            context._loaders = {
                products: undefined
            };

            context._loaders.products = manyToMany(
                context,
                {
                    through: 'store_product',
                    target: 'product',
                    sourceKey: 'storeId',
                    targetKey: 'productId'
                }
            );
        },
        joins: {
            products: () => async (data, context) => {
                data.products = await context._loaders.products(data.id)
            },
            geoloc: () => async (data, context) => {
                data.geoloc = `${data.geolat}, ${data.geolng}`;
            }
        }
    },
    serviceOptions: {
        events: ['modified'],
        paginate: {
            default: 12,
            max: 100
        },
        multi: false,
        permission: {
            create: 'store.service.create',
            update: false,
        },
    },
    modelOptions: {
        timestamps: true,
        freezeTableName: true,
        paranoid: true,
        tableName: 'store',
        schema: 'ordorex'
    },
    modelAttributes: {
        id: {
            type: Sequelize.INTEGER,
            primaryKey: true,
            autoIncrement: true
        },
        name: Sequelize.STRING,
        description: Sequelize.STRING,
        contact: Sequelize.STRING,
        vacancy: Sequelize.STRING,
        address: Sequelize.STRING,
        label: Sequelize.STRING,
        banner: Sequelize.JSONB,
        purchase_level: Sequelize.STRING,
        geolat: Sequelize.FLOAT,
        geolng: Sequelize.FLOAT,
        halal_type: Sequelize.STRING,
        business_type: Sequelize.STRING,
        payment_method: Sequelize.STRING,
        operation_hours: Sequelize.JSONB,

        numering: Sequelize.INTEGER,
        last_numering: Sequelize.INTEGER,
        table: {
            type: Sequelize.ARRAY(Sequelize.STRING),
            defaultValue: []
        },

        status: Sequelize.BOOLEAN,
        merchantId: {
            type: Sequelize.INTEGER,
            relation: {
                type: 'belongsTo',
                model: 'merchant',
                setting: {
                    onUpdate: 'CASCADE',
                    onDelete: 'CASCADE'
                }
            }
        },
        createdAt: Sequelize.DATE,
        updatedAt: Sequelize.DATE,
        deletedAt: Sequelize.DATE
    },
    adminSetting: {
        title: 'Store',
        sidebar: {
            display: 'Store',
            icon: 'store_mall_directory'
        },
        columns: [
            { title: 'Id', field: 'id', editable: 'never' },
            { title: 'Name', field: 'name' },
            { title: 'Description', field: 'description' },
            { title: 'Contact', field: 'contact' },
            { title: 'Vacancy', field: 'vacancy' },
            { title: 'Address', field: 'address' },
            { title: 'Status', field: 'status', type: 'boolean', queryType: 'boolean' },
            { title: 'Merchant', field: 'merchantId' }
        ]
    }
};

Why Configuration

With configuration i have only run once, and test once because is must work. You can write tests with all expected value mean all the situation you can expect just write and just work as your expected configured. The configuration if you do well, you may also controlling using database or some admin panel. Configuration also can make your folder clean and tidy instead of everything put together become messy when find need time to find.