1.1.15 • Published 4 months ago

inibase v1.1.15

Weekly downloads
-
License
MIT
Repository
github
Last release
4 months ago

Inibase :pencil:

A file-based & memory-efficient, serverless, ACID compliant, relational database management system :fire:

Inibase banner

npmjs License Activity GitHub stars

Features

  • Lightweight 🪶
  • Minimalist :white_circle: (but powerful)
  • 100% TypeScript :large_blue_diamond:
  • Super-Fast :zap: (built-in caching system)
  • ATOMIC :lock: File lock for writing
  • Built-in form validation (+unique values :new: ) :sunglasses:
  • Suitable for large data :page_with_curl: (tested with 4M records)
  • Support Compression :eight_spoked_asterisk: (using built-in nodejs zlib)
  • Support Table Joins :link:
  • Low memory-usage :chart_with_downwards_trend: (3-5mb)
  • Safe :lock: (no sql or javascript injections)
  • Easy to use :bread:
  • ... and much more :rocket:

Usage

import Inibase from "inibase";
// const db = new Inibase("databaseName", ".", "es");
const db = new Inibase("databaseName");

// Get all items from "user" table
const users = await db.get("user");

// Read page 2 content
const users = await db.get("user", undefined, { page: 2, per_page: 15 });

// Get only required columns to improve speed
const users = await db.get("user", undefined, {
  columns: ["username", "address.street", "hobbies.name"],
});

// Get items from "user" table where "favoriteFoods" does not includes "Pizza" or "Burger"
const users = await db.get("user", { favoriteFoods: "![]Pizza,Burger" });

!NOTE Enjoy using Inibase? Consider sponsoring us via PayPal Your support helps us maintain and improve our services. Thank you! 🫰

Install

<npm|pnpm|yarn|bun> install inibase

!WARNING If you're using Windows, the following Unix commands are required: zcat, sed, gzip, and echo.

To use the missing commands, you need to install additional tools:

  • GnuWin32: Provides individual GNU utilities for Windows.
  • Cygwin: Offers a full Unix-like environment for Windows.

Alternatively, consider using the Windows Subsystem for Linux (WSL) to run a Linux environment on Windows. Learn more here.

How it works?

Inibase organizes data into databases, tables, and columns, each stored in separate files.

  • POST: New data is appended to column files efficiently.
  • GET: Data retrieval is optimized by reading files line-by-line.
  • PUT: Updates are streamlined, with only the relevant file being modified.
  • DELETE: Removes lines from column files for swift deletion.

This structure ensures efficient storage, retrieval, and updates, making our system scalable and high-performing for diverse datasets and applications.

Inibase CLI

npx inibase -p <databaseFolderPath>
# by default it will diplay a list of available commands (or type 'help')

Examples

interface {
  compression: boolean;
  cache: boolean;
  prepend: boolean;
  decodeID: boolean;
}
interface Field {
  id: number; // stored as a Number but displayed as a hashed ID
  key: string;
  required?: boolean;
  unique?: boolean | string; // boolean for simple uniqueness, string for grouped uniqueness
  regex?: RegExp; // Regular expression for custom validation
  type:
    | "string"
    | "number"
    | "boolean"
    | "date"
    | "email"
    | "url"
    | "password"
    | "html"
    | "ip"
    | "json"
    | "id";
}

interface TableField {
  id: number;
  key: string;
  required?: boolean;
  unique?: boolean | string; // Supports uniqueness constraints
  type: "table";
  table: string;
}

interface ArrayField {
  id: number;
  key: string;
  required?: boolean;
  unique?: boolean | string; // Supports uniqueness constraints
  type: "array";
  children: string | string[]; // Can be a single type or an array of types
}

interface ObjectOrArrayOfObjectsField {
  id: number;
  key: string;
  required?: boolean;
  unique?: boolean | string; // Supports uniqueness constraints
  regex?: RegExp; // For validation of object-level keys
  type: "object" | "array";
  children: Schema; // Nested schema for objects or arrays
}

The unique property ensures that the values of a specific column or a group of columns are unique within a table. This property can be either a boolean or a string.

  • Boolean: Setting unique: true ensures that the values in the column are unique across all rows.
  • String: By setting a string value, you can group columns to enforce a combined uniqueness constraint. This is useful when you need to ensure that a combination of values across multiple fields is unique.
{
  key: "email",
  type: "string",
  required: true,
  unique: true, // Ensures all email values are unique
}
[
  {
    key: "firstName",
    type: "string",
    required: true,
    unique: "nameGroup", // Part of "nameGroup" uniqueness
  },
  {
    key: "lastName",
    type: "string",
    required: true,
    unique: "nameGroup", // Part of "nameGroup" uniqueness
  },
]
import Inibase from "inibase";
const db = new Inibase("/databaseName");

const userTableConfig = {
  compression: true,
  cache: true,
  prepend: false,
  decodeID: false
}

const userTableSchema = [
  {
    key: "username",
    type: "string",
    required: true,
  },
  {
    key: "email",
    type: "string",
    required: true,
  },
  {
    key: "age",
    type: "number",
    required: true,
  },
  {
    key: "isActive",
    type: "boolean",
    // required: false
  },
  {
    key: "hobbies",
    type: "array",
    children: [
      {
        key: "name",
        type: "string",
        // required: false
      },
      {
        key: "level",
        type: "string",
        // required: false
      },
    ],
  },
  {
    key: "favoriteFoods",
    type: "array",
    children: "string",
    // required: false
  },
  {
    key: "address",
    type: "object",
    children: [
      {
        key: "street",
        type: "string",
        // required: false
      },
      {
        key: "city",
        type: "string",
        // required: false
      },
      {
        key: "country",
        type: "string",
        // required: false
      },
    ],
  },
];

await db.createTable("user", userTableSchema, userTableConfig);
import Inibase from "inibase";
const db = new Inibase("/databaseName");

// this will change table name also in joined tables
await db.updateTable("user", undefined, {name: "userV2"});
import Inibase from "inibase";
import { setField } from "inibase/utils";

const db = new Inibase("/databaseName");

const userTableSchema = (await db.getTable("user")).schema;
setField("username", userTableSchema, {key: "fullName"});
await db.updateTable("user", newUserTableSchema);
import Inibase from "inibase";
import { unsetField } from "inibase/utils";

const db = new Inibase("/databaseName");

const userTableSchema = (await db.getTable("user")).schema;
unsetField("fullName", userTableSchema);
await db.updateTable("user", newUserTableSchema);
import Inibase from "inibase";
const db = new Inibase("/databaseName");

const productTableSchema = [
  {
    key: "title",
    type: "string",
    required: true,
  },
  {
    key: "price",
    type: "number",
  },
  {
    key: "createdBy",
    type: "table",
    table: "user",
    required: true,
  },
];

await db.createTable("product", productTableSchema);

const productTableData = [
  {
    title: "Product 1",
    price: 16,
    createdBy: "1d88385d4b1581f8fb059334dec30f4c",
  },
  {
    title: "Product 2",
    price: 10,
    createdBy: "5011c230aa44481bf7e8dcfe0710474f",
  },
];

const product = await db.post("product", productTableData);
// [
//   {
//     "id": "1d88385d4b1581f8fb059334dec30f4c",
//     "title": "Product 1",
//     "price": 16,
//     "createdBy": {
//       "id": "1d88385d4b1581f8fb059334dec30f4c",
//       "username": "user1",
//       "email": "user1@example.com",
//       ...
//     }
//   },
//   {
//     "id": "5011c230aa44481bf7e8dcfe0710474f",
//     "title": "Product 2",
//     "price": 10,
//     "createdBy": {
//       "id": "5011c230aa44481bf7e8dcfe0710474f",
//       "username": "user2",
//       ...
//     }
//   }
// ]
import Inibase from "inibase";
const db = new Inibase("/databaseName");

const userTableData = [
  {
    username: "user1",
    email: "user1@example.com",
    age: 25,
    isActive: true,
    hobbies: [
      { name: "Reading", level: "Intermediate" },
      { name: "Cooking", level: "Beginner" },
    ],
    favoriteFoods: ["Pizza", "Sushi", "Chocolate"],
    address: {
      street: "123 Main St",
      city: "Exampleville",
      country: "Sampleland",
    },
  },
  {
    username: "user2",
    email: "user2@example.com",
    age: 30,
    isActive: false,
    hobbies: [
      { name: "Gardening", level: "Advanced" },
      { name: "Photography", level: "Intermediate" },
    ],
    favoriteFoods: ["Burgers", null, "Salad"],
    address: {
      street: "456 Elm Rd",
      city: "Testington",
      country: "Demo Country",
    },
  },
];

const users = await db.post("user", userTableData);
// [
//   {
//     "id": "1d88385d4b1581f8fb059334dec30f4c",
//     "username": "user1",
//     "email": "user1@example.com",
//     "age": 25,
//     "isActive": true,
//     "hobbies": {
//       "name": [
//         "Reading",
//         "Cooking"
//       ],
//       "level": [
//         "Intermediate",
//         "Beginner"
//       ]
//     },
//     "favoriteFoods": [
//       "Pizza",
//       "Sushi",
//       "Chocolate"
//     ],
//     "address": {
//       "street": "123 Main St",
//       "city": "Exampleville",
//       "country": "Sampleland"
//     }
//   },
//   {
//     "id": "5011c230aa44481bf7e8dcfe0710474f",
//     "username": "user2",
//     ...
//   },
//   ...
// ]
import Inibase from "inibase";
const db = new Inibase("/databaseName");

const user = await db.get("user", "1d88385d4b1581f8fb059334dec30f4c");
// {
//     "id": "1d88385d4b1581f8fb059334dec30f4c",
//     "username": "user1",
//     "email": "user1@example.com",
//     "age": 25,
//     "isActive": true,
//     "hobbies": {
//         "name": [
//             "Reading",
//             "Cooking"
//         ],
//         "level": [
//             "Intermediate",
//             "Beginner"
//         ]
//     },
//     "favoriteFoods": [
//         "Pizza",
//         "Sushi",
//         "Chocolate"
//     ],
//     "address": {
//         "street": "123 Main St",
//         "city": "Exampleville",
//         "country": "Sampleland"
//     }
// }
import Inibase from "inibase";
const db = new Inibase("/databaseName");

const users = await db.get("user", { favoriteFoods: "[]Pizza" });
// [
//   {
//     "id": "1d88385d4b1581f8fb059334dec30f4c",
//     "username": "user1",
//     "email": "user1@example.com",
//     "age": 25,
//     "isActive": true,
//     "hobbies": {
//       "name": [
//         "Reading",
//         "Cooking"
//       ],
//       "level": [
//         "Intermediate",
//         "Beginner"
//       ]
//     },
//     "favoriteFoods": [
//       "Pizza",
//       "Sushi",
//       "Chocolate"
//     ],
//     "address": {
//       "street": "123 Main St",
//       "city": "Exampleville",
//       "country": "Sampleland"
//     }
//   },
//   ...
// ]
import Inibase from "inibase";
const db = new Inibase("/databaseName");

// Get all "user" columns except "username" & "address.street"
const users = await db.get("user", undefined, {
  columns: ["!username", "!address.street"],
});
import Inibase from "inibase";
const db = new Inibase("/databaseName");

// set "isActive" to "false" for all items in table "user"
await db.put("user", { isActive: false });

// set "isActive" to "true" for specific "user" by id
await db.put("user", { isActive: false }, "1d88385d4b1581f8fb059334dec30f4c");

// set "isActive" to "true" in table "user" by criteria (where "isActive" is equal to "true")
await db.put("user", { isActive: false }, { isActive: true });
import Inibase from "inibase";
const db = new Inibase("/databaseName");

// delete all items in "user" table
await db.delete("user");

// delete a specific "user" by id
await db.put("user", "1d88385d4b1581f8fb059334dec30f4c");

// delete "user" by criteria (where "isActive" is equal to "false")
await db.put("user", { isActive: false });
import Inibase from "inibase";
const db = new Inibase("/databaseName");

// get the sum of column "age" in "user" table
await db.sum("user", "age");

// get the sum of column "age" by criteria (where "isActive" is equal to "false") in "user" table
await db.sum("user", ["age", ...], { isActive: false });
import Inibase from "inibase";
const db = new Inibase("/databaseName");

// get the biggest number of column "age" in "user" table
await db.max("user", "age");

// get the biggest number of column "age" by criteria (where "isActive" is equal to "false") in "user" table
await db.max("user", ["age", ...], { isActive: false });
import Inibase from "inibase";
const db = new Inibase("/databaseName");

// get the smallest number of column "age" in "user" table
await db.min("user", "age");

// get the smallest number of column "age" by criteria (where "isActive" is equal to "false") in "user" table
await db.min("user", ["age", ...], { isActive: false });
import Inibase from "inibase";
const db = new Inibase("/databaseName");

// order users by the age column
await db.get("user", undefined, { sort: "age" });

// order users by the age and username columns
await db.get("user", undefined, { sort: ["age", "username"] });
await db.get("user", undefined, { sort: {age: -1, username: "asc"} });

Benchmark

Bulk

101001000
POST11 ms (0.66 mb)5 ms (1.02 mb)24 ms (1.44 mb)
GET29 ms (2.86 mb)24 ms (2.81 mb)36 ms (0.89 mb)
PUT21 ms (2.68 mb)16 ms (2.90 mb)12 ms (0.63 mb)
DELETE14 ms (0.82 mb)13 ms (0.84 mb)2 ms (0.17 mb)

Single

101001000
POST45 ms (1.07 mb)12 ms (0.52 mb)11 ms (0.37 mb)
GET200 ms (2.15 mb)192 ms (2.72 mb)190 ms (2.31 mb)
PUT49 ms (3.22 mb)17 ms (2.98 mb)17 ms (3.06 mb)
DELETE118 ms (0.59 mb)113 ms (0.51 mb)103 ms (3.14 mb)

Default testing uses a table with username, email, and password fields, ensuring password encryption is included in the process To run benchmarks, install typescript & tsx globally and run benchmark by default bulk, for single use benchmark --single|-s

Roadmap

  • Actions:
    • GET:
      • Pagination
      • Criteria
      • Columns
      • Sort
    • POST
    • PUT
    • DELETE
    • SUM
    • MAX
    • MIN
  • Schema supported types:
    • String
    • Number
    • Boolean
    • Date
    • Email
    • Url
    • Table
    • Object
    • Array
    • Password
    • IP
    • HTML
    • Id
    • JSON
  • TO-DO:
    • Use new Map() instead of Object
    • Ability to search in JSON fields
    • Re-check used exec functions
    • Use smart caching (based on N° of queries)
    • Commenting the code
    • Add Backup feature (generate a tar.gz)
    • Add Custom field validation property to schema (using RegEx?)
  • Features:

License

MIT

1.0.0-rc.126

6 months ago

1.0.0-rc.127

6 months ago

1.0.0-rc.128

6 months ago

1.0.0-rc.122

7 months ago

1.0.0-rc.123

7 months ago

1.0.0-rc.124

7 months ago

1.0.0-rc.125

7 months ago

1.0.0-rc.120

7 months ago

1.0.0-rc.121

7 months ago

1.1.1

6 months ago

1.1.0

6 months ago

1.1.9

6 months ago

1.1.8

6 months ago

1.1.7

6 months ago

1.1.6

6 months ago

1.1.5

6 months ago

1.1.4

6 months ago

1.1.3

6 months ago

1.1.2

6 months ago

1.1.12

5 months ago

1.1.11

5 months ago

1.1.10

5 months ago

1.1.15

4 months ago

1.1.14

4 months ago

1.1.13

5 months ago

1.0.0-rc.97

8 months ago

1.0.0-rc.99

8 months ago

1.0.0-rc.98

8 months ago

1.0.0-rc.108

7 months ago

1.0.0-rc.109

7 months ago

1.0.0-rc.104

8 months ago

1.0.0-rc.105

7 months ago

1.0.0-rc.106

7 months ago

1.0.0-rc.107

7 months ago

1.0.0-rc.100

8 months ago

1.0.0-rc.101

8 months ago

1.0.0-rc.102

8 months ago

1.0.0-rc.103

8 months ago

1.0.0-rc.119

7 months ago

1.0.0-rc.115

7 months ago

1.0.0-rc.116

7 months ago

1.0.0-rc.117

7 months ago

1.0.0-rc.118

7 months ago

1.0.0-rc.111

7 months ago

1.0.0-rc.112

7 months ago

1.0.0-rc.113

7 months ago

1.0.0-rc.114

7 months ago

1.0.0-rc.110

7 months ago

1.0.0-rc.93

8 months ago

1.0.0-rc.92

8 months ago

1.0.0-rc.91

9 months ago

1.0.0-rc.96

8 months ago

1.0.0-rc.95

8 months ago

1.0.0-rc.94

8 months ago

1.0.0-rc.90

9 months ago

1.0.0-rc.89

9 months ago

1.0.0-rc.88

9 months ago

1.0.0-rc.86

9 months ago

1.0.0-rc.85

9 months ago

1.0.0-rc.84

9 months ago

1.0.0-rc.83

9 months ago

1.0.0-rc.87

9 months ago

1.0.0-rc.81

9 months ago

1.0.0-rc.80

10 months ago

1.0.0-rc.79

10 months ago

1.0.0-rc.71

1 year ago

1.0.0-rc.70

1 year ago

1.0.0-rc.68

1 year ago

1.0.0-rc.67

1 year ago

1.0.0-rc.66

1 year ago

1.0.0-rc.69

1 year ago

1.0.0-rc.75

1 year ago

1.0.0-rc.74

1 year ago

1.0.0-rc.73

1 year ago

1.0.0-rc.72

1 year ago

1.0.0-rc.78

11 months ago

1.0.0-rc.77

12 months ago

1.0.0-rc.76

12 months ago

1.0.0-rc.60

1 year ago

1.0.0-rc.59

1 year ago

1.0.0-rc.58

1 year ago

1.0.0-rc.64

1 year ago

1.0.0-rc.63

1 year ago

1.0.0-rc.62

1 year ago

1.0.0-rc.61

1 year ago

1.0.0-rc.65

1 year ago

1.0.0-rc.57

1 year ago

1.0.0-rc.56

1 year ago

1.0.0-rc.55

1 year ago

1.0.0-rc.54

1 year ago

1.0.0-rc.53

1 year ago

1.0.0-rc.52

1 year ago

1.0.0-rc.51

1 year ago

1.0.0-rc.50

1 year ago

1.0.0-rc.49

1 year ago

1.0.0-rc.48

1 year ago

1.0.0-rc.47

1 year ago

1.0.0-rc.46

1 year ago

1.0.0-rc.45

1 year ago

1.0.0-rc.42

1 year ago

1.0.0-rc.44

1 year ago

1.0.0-rc.43

1 year ago

1.0.0-rc.40

1 year ago

1.0.0-rc.39

1 year ago

1.0.0-rc.38

1 year ago

1.0.0-rc.35

1 year ago

1.0.0-rc.34

1 year ago

1.0.0-rc.37

1 year ago

1.0.0-rc.36

1 year ago

1.0.0-rc.31

2 years ago

1.0.0-rc.33

2 years ago

1.0.0-rc.32

2 years ago

1.0.0-rc.29

2 years ago

1.0.0-rc.30

2 years ago

1.0.0-rc.28

2 years ago

1.0.0-rc.27

2 years ago

1.0.0-rc.26

2 years ago

1.0.0-rc.24

2 years ago

1.0.0-rc.25

2 years ago

1.0.0-rc.23

2 years ago

1.0.0-rc.20

2 years ago

1.0.0-rc.22

2 years ago

1.0.0-rc.21

2 years ago

1.0.0-rc.9

2 years ago

1.0.0-rc.7

2 years ago

1.0.0-rc.8

2 years ago

1.0.0-rc.13

2 years ago

1.0.0-rc.12

2 years ago

1.0.0-rc.11

2 years ago

1.0.0-rc.10

2 years ago

1.0.0-rc.17

2 years ago

1.0.0-rc.16

2 years ago

1.0.0-rc.15

2 years ago

1.0.0-rc.19

2 years ago

1.0.0-rc.18

2 years ago

1.0.0-rc.6

2 years ago

1.0.0-rc.5

2 years ago

1.0.0-rc.4

2 years ago

1.0.0-rc.3

2 years ago

1.0.0-rc.0

2 years ago

1.0.0-rc.2

2 years ago

1.0.0-rc.1

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago