Exporting the Model

We're having so much fun testing the app that we want to just keep going. But the whole point of writing these tests is so that we can define a model. We can use the model to create the UI and business logic for the app. Let's take some of the template functions we've written and move them to a model source file that can be used within the app.

Exporting Template Functions

Create a new file called src/model.js. Move the functions we've defined into that file. Notice that to do that, we need to know what j is. Before it was an instance of Jinaga, but now we'll define it as an alias for the Jinaga class itself.

const { Jinaga: j, ensure } = require("jinaga");

function postsByAuthor(author) {
    return j.match({
        type: "Blog.Post",
        author
    });
}

function tagsForPost(post) {
    return j.match({
        type: "Blog.Post.Tags",
        post
    });
}

function tagValues(postTags) {
    ensure(postTags).has("tags");

    return j.match(postTags.tags);
}

module.exports = {
    postsByAuthor,
    tagsForPost,
    tagValues
};

Now that we've exported all of the functions, we can import them into the test.

const { postsByAuthor, tagsForPost, tagValues } = require("./model");

Exporting Fact Classes

In the tests, we've been creating facts as JSON literals. But if we define a class, we can make it easier to create instances of a fact. Setting the type as a prototype field makes it static.

class User {
    constructor (
        publicKey
    ) {
        this.type = User.Type
        this.publicKey = publicKey
    }
}
User.Type = "Jinaga.User";

class Post {
    constructor (
        created,
        author
    ) {
        this.type = Post.Type;
        this.created = created;
        this.author = author;
    }
}
Post.Type = "Blog.Post";

module.exports = {
    User,
    Post
};

Then we can use the constructor to create instances.

const person = await j.fact(
    new User("---IF THIS WERE A REAL USER, THEIR PUBLIC KEY WOULD BE HERE---")
);

const post = await j.fact(
    new Post(new Date(), person)
);

And we can use the static type in template functions.

function postsByAuthor(author) {
    return j.match({
        type: Post.Type,
        author
    });
}

We can even define the template functions on the class prototype to keep things organized.

Post.byAuthor = function(author) {
    return j.match({
        type: Post.Type,
        author
    });
}

Then we can use that template function directly from the class.

const posts = await j.query(person, j.for(Post.byAuthor));

Isn't that neater?

Continue With

Starter Kits