Wednesday, December 16, 2015

Using Amazon DynamoDB inside of nodejs, entity frameworkish

Okay to all those wondering how do you integrate dynamodb with node and not lose your sanity I think I have the answer. I have a light background with entity framework and I'm not a huge fan with all of the routing that needs to get set up so here is my take on how to get going with minimal work and have a clean way of working with Dynamodb.

Goals of this design:
Keep plumbing/routing to a minimum
Write as little code as possible to get items from the database
Keep the class as clean as possible, datamembers for the class and functions for the class

Let's start with an example of a table with stock portfolio balances.

To start with create these classes -
1) database.js 
2) portfoliorepository.js
3) portfolio.js

Portfolio.js

First this is your class that does stuff! It has member variables, functions. What we want to do is add a special category for database variables. These can be treated as private if you like. They will represent what columns are in the database and will hold values to be written.

Ex:

function PortfolioBalance() {
    this.db = { 
        LoginName: "",
        Date: "",
        CashBalance: 0,
        CashPortfolioPercent: 0,
        PreviousCashPortfolioPercent: 0,
        ReturnRate: 0.0,
        StocksPercent: "",
        StocksQuantity: "",
        TotalPortfolioValue: "",
        TradesForDay: ""
    };
    //non database variables go here


    var parent = this;

    //class functions go here
}


PortfolioRepository.js 

Here is where stuff starts to get cool! The repository will only and should only be functions that query dynamoDB for data results. When the data gets returned we will use a function in database.js to create a list of 1 or more portfolio classes and return that. DO NOT add any other functions related to the class here! Also, do not create constructors for portfolio! As far as we are concerned, PortfolioBalance.db is the contract and all we need to populate portfolio balance. We can write a generic function in database.js to do this.


Ex:

var getPortfolioBalanceForUserOnDate = function ( loginName, date, callback ) {
    var search = {
        TableName: exports.table.Name,
        KeyConditions: {
            "LoginName": {
                "AttributeValueList": [{
                    "S": loginName
                }],
                "ComparisonOperator": "EQ"
            },

        },
        Limit: 1,
        ProjectionExpression: "#a,#b,#c,#d",
        ExpressionAttributeNames: { "#a": "StocksPercent",
                                    "#b": "CashPortfolioPercent",
                                    "#c" : "Date",
                                    "#d" : "PreviousCashPortfolioPercent"}

    };
   
    databaseLib.query( search, function( data, err ) {
        var objects = databaseLib.convertToObjects( data, err, function() { return new PortfolioBalance(); } );
        callback( objects, err ) ;
    });
};

Alright excitement level right now is 8/10. I will make that 10 on the next step. You can see this code deals with all your non-pretty dynamo db query stuff. That's all it should have and when it gets back a json result, that gets converted to a pretty list of PortfolioBalance() objects.

Database.js

Okay now we need some magic here to generate the classes.
For the convertToObjects( data, err, function() { return new PortfolioBalance(); } )

the code might be similar to follows ->


var initalizeObject = function ( object, dataItem ) {
    var itemsToFill = Object.keys(object.db);
   
    //this still needs to look for M/N/L and do the conversion!
    for ( var index = 0; index < itemsToFill.length; index++ ) {
        object.db[itemsToFill[index]] = dataItem[itemsToFill[index]];
    }
};

var convertToObjects = function( data, err, creationFunction ) {
    if ( err ) {
        return null;
    }   
   
    var objects = [];
   
    for ( var index = 0; index < data.Items.length; index++ ) {
        var newObject= creationFunction();                                  //create a new class object
        initalizeObject( newObject, data.Items[index] );     //initialize the class object based on the db member, and row from database
        objects.push( newObject);
    }
   
    return objects;
}; 



Some points here -> We are using object.db or portfoliobalance.db as a contract on what to grab from the query results. The code above does a straight copy meaning you will get myvalue: { n: 0 } or all the data type values amazon gives you. I am working on stripping these out in my database class inteligently so my class is as clean as possible. Also note, since object.db or portfolioBalance.db is a contract, we could also validate that the dataItem contains all expected keys! 


I may update this in the future with more code as I work on it, so hit me up in the comments if you are interested in more final code!

No comments:

Post a Comment