Skip to content

seyacat/MapDB

Repository files navigation

MapDB

MapDB is a tool for managing relationships between objects like a database does.

Instalation

npm i --save @seyacat/mapdb

Import in project

const { MapDB } = require("@seyacat/mapdb");
const mdb = new MapDB();

as module

import { MapDB } from "@seyacat/mapdb";
const mdb = new MapDB();

Classes

MapDB: Main class, contains all the structure and data

  • constructor(config): config can contain tables structure and relationships, look examples below
  • get(name): return table by name
  • tables: contains Map of Tables.
  • createTable(name, options): create new table

Table: Contains the records and settings of a collection of objects.

  • mdb: parent MapDB object.

  • id: name of the id field.

  • name: unique table name.

  • options: contains fields configurations.

  • data: contains Map of records.

  • get() || getAll(): Without parameters returns array of all data

  • getAllByField(field, value): Get all data with field value;

  • get(Id): Return record with with Id

  • insert(object): Insert record function.

  • upsert(object): Update if exists or insert record function.

  • update(object): Update record function.

  • delete(object || id): delete record

  • onAny(function({record,event,field,prev}){}): Add callback function for any record event.

  • onChange(function({record,event,field,prev}){}): Add callback function for change FIELD event. Should be used only on single field change.

  • onInsert(function({record,event}){}): Add callback function for insert record event.

  • onUpdate(function({record,event,prev}){}): Add callback function for update record event.

Record: Is a proxy object created with Table.insert() method.

  • muted: boolena trapped property than disable callback it is true;
  • attach(object | id): reserved trapped function for attach relation on hasOne and hasMany properties.
  • detach(object | id): reserved trapped function for detach relation on hasOne and hasMany property.
  • ${fieldname}_data: A related field with hasMany or hasOne shows the id, [...] when you have many or null. To retrieve the data of a related field it is necessary to prepend "_data", this to avoid infinite loops.
  • [???] hasMany field with unknow content, seen on console.log()
  • [...] hasMany field with childs

Field Properties

  • id: name of the Id field.
  • unique.
  • required: non null.
  • match: validation regexp.
  • index: create an relation table for this field ${table}_${field}.
  • hasOne: property than contains table name for the record that has related a single parent.
  • hasMany: property than contains table name for the record that has related many children.
  • fhField: property than contains field name of related table, required on fields with hasMany and hasOne property.

Usage

Create main class

import { MapDB } from "@seyacat/mapdb";
const mdb = new MapDB();

Declare tables in a single JSON object

const config = {
  tables: {
    users: {
      fields: { connection: { hasOne: 'connections', fhField: 'user' } },
    },
    connections: {
      ...
    },
    ...
  },
  relationships: [...]
};

const mdb = new MapDB(config);

const messages = mdb.get('messages');
const messages = mdb.tables.get('messages');

Create Table with field properties

const emails = mdb.createTable("emails", {
  fields: { email: { unique: true } },
});

Simplified relationships

const config = {
  tables: {...},
  relationships: [
      //One room in table rooms has many users in table users
      ['one', 'room', 'rooms', 'many', 'users', 'users'],
      //One owner (users) has many rooms(rooms)
      ['one', 'owner', 'users', 'many', 'myrooms', 'rooms'],
      //One owner (users) has many messages(messages)
      ['one', 'user', 'users', 'many', 'messages', 'messages'],
      //One connection (connections) has one user (users)
      ['one', 'connection', 'connections', 'one', 'user', 'users'],
      //One connection (connections) has many messages (messages)
      ['one', 'connection', 'connections', 'many', 'messages', 'messages'],
      //One status (message_status) has many messages (messages)
      ['one', 'status', 'message_status', 'many', 'messages', 'messages'],
    ],
}

Create records

  const email1 = emails.insert({ email: "test@test.com" });
  const email2 = emails.insert({ email: "test@test.com" }); //<-- Thrown error

Edit record, treat it like any other object

  email1.email = "test@test.com" <--- Set data as normal object
  email1.email = "test@test.com" <--- Assing record on hasOne relationship
  email1.email = "test@test.com" <--- Append record on hasMany relationship

Examples

One to Many example

const { MapDB } = require("@seyacat/mapdb");
const mdb = new MapDB();

const games = mdb.createTable("games", {
  fields: {
    name: { unique: true },
    rooms: { hasMany: "rooms", fhField: "game" },
  },
});
const rooms = mdb.createTable("rooms", {
  fields: {
    name: { unique: true },
    game: { hasOne: "games", fhField: "rooms", required: true },
    players: { hasMany: "players", fhField: "room" },
  },
});
const players = mdb.createTable("players", {
  fields: {
    room: { hasOne: "rooms", fhField: "players" },
  },
});

const game1 = games.insert({ name: "juego1", desc: "j1" });
const game2 = games.insert({ name: "juego2", desc: "j1" });

const room1 = rooms.insert({ game: game1.id });
const room2 = rooms.insert({ name: "room2", game: game1.id });
room2.test = "hola";

//SHOW OBJECTS WITHOUT RELATED DATA
console.log(game1);
/*{
  id: '5384c954acbd25b15d6fb7e5f1b5c178762c837d',
  name: 'juego1',
  desc: 'j1',
  rooms: null
}*/
console.log(room1);
/*{
  id: 'fd050c21a227a6db7774f03d5091e8f25ec969d9',
  game: '5384c954acbd25b15d6fb7e5f1b5c178762c837d',
  name: null,
  players: null
}*/

//SHOW RELATED DATA
console.log(game1.rooms_data);
/*[
  {
    id: 'fd050c21a227a6db7774f03d5091e8f25ec969d9',
    game: '5384c954acbd25b15d6fb7e5f1b5c178762c837d',
    name: null,
    players: null
  },
  {
    id: '9c855aed893508ac0eb485e7d9d447985b776b81',
    name: 'room2',
    game: '5384c954acbd25b15d6fb7e5f1b5c178762c837d',
    players: null,
    test: 'hola'
  }
]*/
console.log(room1.game_data);
/*{
  id: '5384c954acbd25b15d6fb7e5f1b5c178762c837d',
  name: 'juego1',
  desc: 'j1',
  rooms: null
}*/

Many to Many example

const { MapDB } = require("@seyacat/mapdb");
const mdb = new MapDB();

const cursos = mdb.createTable("cursos", {
  fields: {
    name: { unique: true },
    estudiantes: { hasMany: "estudiantes", fhField: "cursos" },
  },
});

const estudiantes = mdb.createTable("estudiantes", {
  fields: {
    name: { unique: true },
    cursos: { hasMany: "cursos", fhField: "estudiantes" },
  },
});

const curso1 = cursos.insert({ name: "matematicas" });
const curso2 = cursos.insert({ name: "fisica" });
const curso3 = cursos.insert({ name: "quimica" });
const estudiante1 = estudiantes.insert({ name: "juan" });
const estudiante2 = estudiantes.insert({ name: "pedro" });
const estudiante3 = estudiantes.insert({ name: "maria" });
curso1.attach("estudiantes", estudiante1.id);
curso1.attach("estudiantes", estudiante2.id);
estudiante2.attach("cursos", curso2.id);
estudiante2.detach("cursos", curso1.id);

//SHOW RELATED DATA
console.log(curso1.estudiantes_data);
/*[
  {
    id: '2af0fc5c3717a64cf8edf4595ba02ce548768a08',
    name: 'juan',
    cursos: null
  }
]*/
console.log(estudiante1.cursos_data);
/*[
  {
    id: '2d390151184d7a49a3980ba47ebbaae32d5ca598',
    name: 'matematicas',
    estudiantes: null
  }
]*/

Test

Integrated tesr with mocha

npm run test

Support

Write without problem to seyacat@gmail.com or create an issue.

Roadmap

  • Better docs.
  • Typescript types.
  • Delete records.
  • Validate fields.
  • Redis Database integration.

Contributing

Mail to seyacat@gmail.com

Authors

Santiago Andrade (seyacat)
You can follow the develop of this live on twitch 22:00 GMT-5 https://www.twitch.tv/seyacat

License

ISC

Project status

Early Stage

About

Simple memory relational database on Javascript

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published