Skip to content
🔥 MetaphaseJS DEMO: super easy, efficient and agnostic client state manager for Javascript
TypeScript HTML CSS JavaScript
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.idea
analysis
build
jest-config
public
src
temp
.gitignore
.travis.yml
LICENSE
README.md
build.js
package.json
qrcode.jpg
tsconfig.json
tsconfig.prod.json
tsconfig.test.json
tslint.json
yarn.lock

README.md

MetaphaseJS Demo

Demostration of MetaphaseJS framework ( BETA VERSION ).

experimental Build Status Maintainability

NPM package

MetaphaseJS is a super easy, efficient and agnostic state manager for Javascript. It can be used with React, Angular o vanilla JS. In this demo React and Typescript have been used. ➡️Link to repository

Demo

Table of Contents

Why

  • State management is an issue solved decades ago in server-side environments using transactional and relational databases. This is not the case of client-side apps (browser) where it has remained unsolved until the advent of libraries/patterns like Redux/Flux
  • Client-state managers based on Flux architecture produce verbose and complicated code (inmutability adds levels of indirection and therefore complexity) and they are basically reinventing the wheel trying to recreate a sort of in-browser database
  • Store in Redux is essentially a big key-value object which is not appropiate for nested and relational data
  • There are other client databases like IndexDB, LovefieldDB, etc. but they are complicated (callbacks, asynchrony) or very elementary (localStorage)
  • The intention of MetaphaseJS is to apply the same server-side state management techniques to client-side apps.

Features

  • Simplicity: no callbacks, no asynchronous code, no functional nor inmutable complexities
  • Agnostic: it can be used with ReactJS, Angular, Vue, React Native, vanilla JS, etc. Just plug-and-play
  • State is a true relational SQLite database
  • State can be managed with SQL queries generated by Metaphase ORM (Object-Relational Mapper). It implements the following patterns:
  • State can be saved to a database file on disk
  • State can be designed and populated with any db tool that supports SQLite (even using a graphical UI without using code) and after that, it can be imported into an app
  • Great developer productivity and satisfacction. For example, an entire blog sistem could be developed in minutes
  • Ideal for statically generated content (i. e.: static blogs without a server database)
  • Comprehensive and switchable logger system. It can be turned off in production for better performance . A simple url query parameter controls the logger http://url-app?logger=true/false
  • Use of Reflection-Metadata API and Decorators to simplify model definitions (when Typescript is used)
  • In SQLite by default all operations are transactional. This means protection against race conditions when state is accessed by asynchronous writes

How

  • Sql.js is a Javascript library that uses Emscriptem/WebAssembly to recompile the SQLite C++ code to Javascript. This means you can create a SQLite database in browser and use all its functionality.
  • MetaphaseJS uses Sql.js to hold the application state in a in-memory SQLite database:
    1. You create classes for your models (also called entities)
    2. Set up relations between models
    3. Create collections of models
    4. Execute operations with models (CRUD)
  • You can use an ORM to execute queries, or raw SQL
  • You can load state:
    1. From a database file on disk
    2. From a database created at runtime by code
  • You can save the state to a file on disk
  • As always you can persist the state to a server using http requests.

Requirements

  • Modern browser
  • Yarn package manager (or NPM)

Installation

  • Clone the project
  • Run yarn install in the project directory

Usage

  • Run yarn start
  • Packages analysis (without gzip compression) yarn analysis ➡️ link

Entity-Relation State Diagram

Code

  1. Creation of models and relations in models.ts. (Models could have also been defined in individual files).
// File: models.ts

// ---------------------------------------------------------------------
// This is a simplified example and it is written in Typescript using decorators
// For regular Javascript you can define columns using "Column" class.
// (See tests)
// ---------------------------------------------------------------------

import {Model, column} from 'metaphasejs';

// User model definition (ids are automatically generated) -------------
export class User extends Model {

  @column()
  name: string;

  @column({notNullable: true, index: true}) // Example of db column attributes
  age: number;

  @column()
  admin: number;

  hasMany() {
    return [Post]; // Relation definition: User "has many" Post
  }
}

// Post model definition ------------------------------------------------
export class Post extends Model {

  @column()
  title: string;

  @column({dbType: DBtype.TEXT})
  content: string;

  hasMany() {
    return [Comment];
  }
}

// Comment model definition ---------------------------------------------
export class Comment extends Model {

  @column()
  author: string;

  @column()
  date: string;
}
  1. Definition of collections and relations in store.ts. This concept of "store" is not the same like in Redux. It is just a place where instances and collections of models are created, but they can be created in any other place in the application.
// File: store.ts

import {Collection} from 'metaphasejs';
import {User, Post, Comment} from 'models';

// Users collection -----------------------------------------------------
export const users = new Collection(User);
const user1 = new User({name: "user1", age: 11, admin: 1});
const user2 = new User({name: "user2", age: 22, admin: 1});
const user3 = new User({name: "user3", age: 33, admin: 1});
users.save(user1);
users.save(user2);
users.save(user3);

// Posts collection -----------------------------------------------------
export const posts = new Collection(Post);
const post1 = new Post({title: 'title post 1', content: 'content post 1'});
const post2 = new Post({title: 'title post 2', content: 'content post 2'});
const post3 = new Post({title: 'title post 3', content: 'content post 3'});
post1.belongsTo(user1);
post2.belongsTo(user1);
post3.belongsTo(user2);
posts.save(post1);
posts.save(post2);
posts.save(post3);

// Comments collection --------------------------------------------------
export const comments = new Collection(Comment);
const comment1 = new Comment({author: 'author1', date: '5/16/2018'});
const comment2 = new Comment({author: 'author2', date: '6/16/2018'});
comment1.belongsTo(post1);
comment2.belongsTo(post1);
comments.save(comment1);
comments.save(comment2);
  1. Operations with data

    a) Filtering:

// File: app.ts

import {users} from "store"
import {db} from "metaphasejs";

// Get all users
users.getAll();

// Get all users with children (related models)
users.getAll({children: true});

// Get all users using raw sql
db.execQuery('select * from users');

// Get user by id = 1
const user1 = users.getById(1);

// Get user with name 'user1'
users.getByFilter({name: 'user1'})

// Get user with name: 'user1', age: 11 and admin: 0
users.getByFilter({name: 'user1', age: 11, admin: 0});

// See tests for more examples

b) Create/Read/Update/Delete (CRUD):

// File app.ts

// user1 modification
user1.name = 'new name';

// Save/update user1 using an instance of Model class
user1.save();

// Save/update user1 using an instance of Collection class
users.save(user1);

// Delete user1 using an instance of Model class
user1.remove();

// Delete user1 using an instance of Collection class
users.remove(user1);

// TODO more examples

Credits

License

MIT

Back to top ⬆️

You can’t perform that action at this time.