Question

I'm using the driven object model tool CodeFluentEntities in order to deploy a model to a DataBase engine.

I'm thinking about using localStorage database engines (like IndexedDB or Web SQL) in order to store my datas for a web application without server.

I looked into the documentation but it seems to me a little poor... I think I understood the basic principles like the injection points that are Produce() and Terminate() but what about the target directory of the actual production ?

In my case, which is Javascript source code files, how can I specify correctly (in a referenced manner) where to generate them ? And does it have to be in an external project, or could I just fill a directory in an other project (which is the .vsproj of my webapp, per example) ?

Can the documentation integrate a sample of code regarding this aspects, or someone can redirect me to an article fitting my needs ?

Was it helpful?

Solution

The Template approach

According to your needs, I suggest you to use a template instead of developing your custom Producer because of, among others, deployment reasons. Using the template producer (shipped with CodeFluent Entities) you can quickly and easily create complex scripts by taking advantage of the CodeFluent Entities meta model.

This producer is based on CodeFluent Entities' template engine and allow you to generate text files (JavaScript in your case) at production time. As a reminder, A template is simply a mixture of text blocks and control logic that can generate an output file

This producer takes care of all common operations : update the project (.XXproj) to add your generated files, add missing references, etc. You can find thereafter an example to generate an IndexDB script file based on a CodeFluent Entities model (demonstration purposes only). Here's the template source file :

[%@ reference name="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Core.dll" %]
[%@ namespace name="System" %]
[%@ namespace name="System.Linq" %]
[%@ namespace name="CodeFluent.Model" %]

var context = {};
context.indexedDB = {};
context.indexedDB.db = null;

context.indexedDB.open = function () {
    var version = 11;
    var request = indexedDB.open([%=Producer.Project.DefaultNamespace%], version);

    request.onupgradeneeded = function (e) {
        var db = e.target.result;
        e.target.transaction.onerror = context.indexedDB.onerror;
        [%foreach(Entity entity in Producer.Project.Entities){
            string properties = String.Join(", ", entity.Properties.Where(p => !p.IsPersistenceIdentity).Select(p => "\"" + p.Name + "\""));
        %]
        if (db.objectStoreNames.contains("[%=entity.Name%]")) {
            db.deleteObjectStore("[%=entity.Name%]"); 
        }

        var store = db.createObjectStore("[%=entity.Name%]",
          { keyPath: "id", autoIncrement: true });

        store.createIndex([%=properties %], { unique: false });[%}%]
    };

    request.onsuccess = function (e) {
        context.indexedDB.db = e.target.result;
    };

    request.onerror = context.indexedDB.onerror;
};
    [%foreach(Entity entity in Producer.Project.Entities){
        string parameters = String.Join(", ", entity.Properties.Where(p => !p.IsPersistenceIdentity).Select(p => p.Name));%]
context.indexedDB.[%=entity.Name%] = {}

    context.indexedDB.[%=entity.Name%].add = function ([%= parameters %]) {
    var db = context.indexedDB.db;
    var trans = db.transaction(["[%=entity.Name%]"], "readwrite");
    var store = trans.objectStore("[%=entity.Name%]");
    var request = store.put({
    [% 
        foreach (Property property in entity.Properties.Where(p => !p.IsPersistenceIdentity)) {%]
        "[%=property.Name%]": [%=property.Name%], [%}%]
        "timeStamp": new Date().getTime()
    });

    request.onsuccess = function (e) {
        console.log(e.value);
    };

    request.onerror = function (e) {
        console.log(e.value);
    };
};

context.indexedDB.[%=entity.Name%].delete = function (id) {
    var db = context.indexedDB.db;
    var trans = db.transaction(["[%=entity.Name%]"], "readwrite");
    var store = trans.objectStore("[%=entity.Name%]");

    var request = store.delete(id);

    request.onsuccess = function (e) {
        console.log(e);
    };

    request.onerror = function (e) {
        console.log(e);
    };
};

context.indexedDB.[%=entity.Name%].loadAll = function () {
    var db = context.indexedDB.db;
    var trans = db.transaction(["[%=entity.Name%]"], "readwrite");
    var store = trans.objectStore("[%=entity.Name%]");

    var keyRange = IDBKeyRange.lowerBound(0);
    var cursorRequest = store.openCursor(keyRange);

    request.onsuccess = function (e) {
        // not implemented
    };

    request.onerror = function (e) {
        console.log(e);
    };
};
[%}%]

function init() {
    context.indexedDB.open(); // initialize the IndexDB context.
}

window.addEventListener("DOMContentLoaded", init, false);

Then you need to configure your CodeFluent Entities Project by adding the Template Producer and define the template above as the source file.

If you consider the following model :

Just build it to generate the IndexDB script file in the target project (a web application for example) and you'll be able to manipulate the generated API like this :

context.indexedDB.Contact.add("Peter", "Boby")
context.indexedDB.Product.add("Tablet")
context.indexedDB.Product.add("Computer")
context.indexedDB.Contact.delete(1)
context.indexedDB.Product.loadAll()

The custom Producer approach

Nevertheless, if ever you need to target a technology or platform that isn't supported by CodeFluent Entities natively, you may create your own custom producer by implementing the IProducer interface :

public interface IProducer
{
    event Producer.OnProductionEventHandler Production;

    void Initialize(Project project, Producer producer);
    void Produce();
    void Terminate();
}

First of all, you need to understand that the CodeFluent Entitie Build engine calls each of your configured producers one by one to generate your code.

Firstly, CodeFluent Entities calls the Initialize method for each producers. It takes as a parameter an instance of the CodeFluent Entities project and the current producer. Then it calls the Product method following the same process. It's the right place to implement your generation logic. Finally, you could implement a finalize logic in the Terminate method.

CodeFluent provides some base classes that implement the IProducer interface such as BaseProducer which is located in CodeFluent.Producers.CodeDom assembly that provides behaviors like "add missing references" or "update Visual Studio project (.XXproj).

In addition, here's a blog post that can help you to integrate a custom producer to the modeler.

The Sub-Producer approach

An other approach might be to develop a custom Sub-Producer but, in my opinion, it is not suitable according to your needs.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top