Export the Model (JavaScript)

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 specification functions we've written and move them to a model source file that can be used within the app.

Exporting Specification Functions

Create a new file called src/shared/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("---Blog Creator---")
);

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

And we can use the static type in specification functions.

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

We can even define the specification 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 specification function directly from the class.

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

Isn't that neater?

Continue With

Export the Model (TypeScript)