@db-essentials/base

2.0.2 • Public • Published

Description

Lightweight and fast local json database manager

  • supports all CRUD operations
  • comprehensive querying syntax
  • built-in seeder to quickly populate your database up to thousands of records
  • a command line tool to run dabase queries from terminal
  • 'persist' or 'no_persist' mode if you want to block write operations
  • base package comes with no dependencies
  • easily extensible, dedicated database modules are under way

Installation

    npm install @db-essentials/base --save

    or

    yarn add @db-essentials/base

HTTP methods

Method Http Verb Description
find GET Returns all matching records
find_one GET Returns the first matching record
count GET Returns the number of matching records
delete_one DELETE Deletes matching record filters
delete_many DELETE Deletes multiple records, returns an array of deleted id's
save_one POST Saves a record
save_many POST Saves multiple records
update_one PUT Updates the first matching record
update_many PUT Updates all matching records

Client

Example with fetch API

// with query parameters

await fetch("somedomain/find/items?_only=price,name,updated_at&_limit=10");

// with body

await fetch("somdedomain/update_one/items", {
  method: "PUT",
  body: JSON.stringify({
    _id: 12,
    _set: {
      price: 169.99,
    },
  }),
});

Server

// Basic setup with express.js

const app = require("express")();

const { Connection, Query } = require("@db-essentials/base");

app.get("/", async (req, res) => {
  const conn = await Connection.create({
    database: "public/db",
    label: "default",
    mode: "no_persist",
  });

  const query = await Query.create({
    connection: conn,
    url: "find/test_data",
    body: null,
  });

  const data = await query.run();

  res.status(200).send(data);
});

app.listen(4000, () => console.log("listening on port 4000"));

This is just a most basic example. The key parts however are:

Connection
Argument Accepts Description
label any unique string An identifier for this particular connection, since you can have many of them running simultaneously.
database string A valid path to your local json files directory.
mode persist, no_persist It tells whether you want to persist write / delete / update operations or not.
Query
Argument Accepts Description
connection object An instance of active connection.
url string A url that includes a valid http method (see above), name of the collection you wish to address and optional search query.
body string A stringified body object when performing write / update operations.

Query builidng

General

Query operators always start with underscore

// _exists, _type, _lte, etc...

so they can later be separated and parsed. In general regular field names should not start with underscores.

Nested properties can be accessed using dot notation:

const q = "?field1.nested.value._gte=10";

Array values should be comma separated. Example of selecting fields to return:

const q = "?_only=field1,field2,field3,nested.field1,nested.nested.field3"; // etc...

Some operators precede the field name and some come after:

const q = "?_nor.field=value"

// vs

const q = "?field.someNestedField._in=1,2,3,4"

/*

Search params use a regular '?' and '&' syntax. Some operators allow multiple conditions:

const q =
  "somedomain/find/items?_nor.itemName._in=name1,name2,name3&_nor.someValue._gte=100&optonalField._exists=true";

Same example but using request body object

const body = JSON.stringify({
  _nor: {
    itemName: {
      _in: ["name1", "name2", "name3"],
    },
    someValue: {
      _gte: 100,
    },
  },
  optionalField: {
    _exists: true,
  },
});

Request filters

These are treated as reserved keywords and you should avoid using them as database field names. Filters can access deep nested fields as well

field.nested.nested._exists = true;

Any record has an autogenerated _id field, which holds a numeric value. It'a special field, every other underscore starting fields area treated as operators.

Param Usage Description
_gt field._gt=[any] Greater than target
_gte field._gte=[any] Equal or greater than target
_lt field._lt=[any] Lower than target
_lte field._lte=[any] Equal or lower than target
_in field._in=[array] Equal to target or one of comma separated target values
_not_in field._not_in=[array] Different than target or comma separated target values
_equals field._equals=[any] Equal to target
_not_equal field._not_equal=[any] Different than target
_exists field._exists=[boolean] Checks if the value exists, pass true or false
_type field._type=[string] Checks if the value is of given type: string, null, date, ...etc.
You can also pass an array of types to evaluate, field._type=null,date
_regex field._regex=[string] Evaluates value based on a regex expression
_array_match field._array_match=[any] Checks if an array field contains the requested value
_array_all field._array_all=[array] Checks if an array field contains all requested values
_array_size field._array_size=[number] Checks if the array field is of specified size
_and _and.field=[any] Filters out records that don't match all conditions : _and.name=someName&_and.value._gt=4
_or _or.field=[any] Returns records that match at least one condition : _or.fieldName=value&_or.orOtherField._gt=4
_nor _nor.field=[any] Filters out records that match the conditions: _nor.name=book&_nor.price._gt=19.99

Response modifiers

These are treated as reserved keywords and you should avoid using them as database table field names.

Param Usage Description
_only _only=[array] Specifies which fields should be included with the response. Accepts comma separated fields or a single field. Use either this or '_except'
_except _except=[array] Specifies which fields not to icnlude with the response. Accepts comma separated fields or a single field. Use either this or '_only'
_skip _skip=[number] How many records to skip. Accepts an integer value.
_limit _limit=[number] Caps results number to a specified integer value.
_sort _sort.field=[number] Sorts data by a specified field, should be either 1 (ascending order) or -1 (descending order).
_slice _slice=[array] Gets a range of records.
_array_slice _array_slice.field=[num] Specifies how many values to return from an array field.

Insert and update

Operators to be used inside a body object of POST or PUT http requests

Param Usage Description
_set _set.field=[any] Updateds a value to the target value, should be used with http PUT call
_inc _inc.field=[number] Increments a number value by specified positive or negative value.
_cdate _cdate.field._type=[string] Updates a field to a current date or timestamp, _cdate.updated_at._type=date or _cdate.updated_at._type=timestamp.
_save _save=[array] Specifies an array of records to be inserted into database

Run from terminal

Run a database query using a built-in command line interface

Include this line in you package json scripts

The path argument point to you local files

{
  "scripts": {
    "query": "db-essentials-query path=./PATH/TO/LOCAL_DATABASE mode=persist"
  }
}

A query must be wrapped in quotes

    npm run

    // or

    yarn query "find/users?_only=name,age&_limit=15" true

    // pass true at the end if you want to see the result as a string, otherwise you can leave it

Seeders

You can use a built-in command line script to seed your local database.

Setup

Add a line to your package.json scripts as shown in the example below.

  • first argument is the path to a directory in your app where seeders are stored.
  • second argument is the path which points to your local database files directory.
  • the third argument tells whether it should persist the data, by default it does
{
  "scripts": {
    "seed": "db-essentials-seed path/to/seeders path/to/database_files persist"
  }
}

Usage

    // table name is required

    /*
      count number is optional, defaults to 1
      if no number is specified it will run a single seed
      if you want to seed a fixed number of data at once, an array of objects, usually that's what you need
    */

    npm run seed users 77

    npm run seed categories // creates database records from an array of objects returned from the seeder

    or

    yarn seed users 77

Example

Seeder is just a function that returns an object or array of objects structured after you database model schema. Since it would bring an unncessary overhead the package has no built-in fake data generator. There are devoted packages like https://github.com/faker-js/faker you can try.

// products.js

// your seeder logic

const getRandomNumber = (min, max) =>
  Math.floor(Math.random() * (max - min + 1) + min);

const getRandomArrayElement = (arr) =>
  arr[Math.floor(Math.random() * arr.length)];

const items = [
  "Bag",
  "Battery Pack",
  "Camera",
  "Charger",
  "Cooker",
  "Electric Car",
  "Flash Drive",
  "Fridge",
  "Frying Pan",
  "Headphones",
  "Keyboard",
  "Microphone",
  "Monitor",
  "Mouse",
  "Multitool",
  "Notebok",
  "Phone",
  "Power Bank",
  "Printer",
  "Soundsystem",
  "Speakers",
  "SSD",
  "Tablet",
  "Telescope",
  "TV",
  "Vacuum Cleaner",
  "Wallet",
  "Watch",
];

const adjectives = [
  "Aluminium",
  "Cheap",
  "Elite",
  "Flexible",
  "Gaming",
  "Hybrid",
  "Mega",
  "Mini",
  "Mobile",
  "Modern",
  "Pro",
  "Slim",
  "Smart",
  "Ultra",
  "Universal",
  "Waterproof",
  "Wireless",
];

const brands = [
  "Apple",
  "Dell",
  "Essentials",
  "Hitachi",
  "HP",
  "Huawei",
  "IBM",
  "Ilyama",
  "LG",
  "Microsoft",
  "Nintendo",
  "Philips",
  "Samsung",
  "Sony",
];

// function that returns a seeder object

module.exports = async () => {
  // as you might await smth here

  return {
    name: `${getRandomArrayElement(brands)} ${getRandomArrayElement(
      adjectives
    )} ${getRandomArrayElement(items)}`,
    published: getRandomArrayElement([true, false]),
    created: new Date().toISOString(),
    in_stock: getRandomNumber(100, 0),
    sold: getRandomNumber(1001, 0),
    price: (getRandomNumber(2001, 1) + getRandomNumber(2001, 1)).toFixed(2),
  };
};

Returning an array of objects in a single seed

// fetch data from external source or create your own

module.exports = () => {
  return [
    {
      name: "LG Modern Headphones",
      in_stock: 45,
    },
    {
      name: "Samsung Ultra SSD",
      in_stock: 125,
    },
    {
      name: "Apple Slim Wallet",
      in_stock: 15,
    },
    // ...etc
  ];
};

Readme

Keywords

Package Sidebar

Install

npm i @db-essentials/base

Weekly Downloads

2

Version

2.0.2

License

MIT

Unpacked Size

54.4 kB

Total Files

38

Last publish

Collaborators

  • pogodisco