# Preview

[**SchemaJS**](https://github.com/Schema-JS/schema-js) is an open-source database system built on V8, the JavaScript engine, using JavaScript/TypeScript as its query language. This approach minimizes context switching between technologies, allowing for consistent use of the same language across your application stack.

Let's create your first database in under five minutes.

## Install SchemaJS

Install SchemaJS on your system using one of the terminal commands below

{% tabs %}
{% tab title="macOS" %}

```sh
curl -fsSL https://schemajs.com/install.sh | sh
```

{% endtab %}

{% tab title="Windows" %}

```powershell
irm https://schemajs.com/install.ps1 | iex
```

{% endtab %}

{% tab title="Linux" %}

```sh
curl -fsSL https://schemajs.com/install.sh | sh
```

{% endtab %}
{% endtabs %}

After installation, you should have the `schemajs` executable available on your system path. You can verify the installation by running:

```
schemajs --help
```

## Hello World

SchemaJS supports both JavaScript and [TypeScript](https://www.typescriptlang.org/) natively, letting you implement your database using either language. To get started with your first "Hello World", refer to the following documentation.

After successfully installing `schemajs`, navigate to the folder where you’d like to initialize boilerplate code and run the following command:

```sh
$ schemajs init
```


# Setting up your environment

## Init Command

SchemaJS provides with `schemajs init` as a way to easily initialize the boilerplate necessary for the database server to spin up. All you need to do is run `schemajs init` inside the folder where you would like your database schemas to be placed.

## Foundational

To use SchemaJS effectively, your database implementation needs to follow specific structural patterns. This ensures that the engine can correctly interpret and execute your database logic.

We *recommend* you create a workspace folder. You can do this by running the following command:

```
cd documents && mkdir schemajs-workspace && cd schemajs-workspace
```

After creating the folder `schemajs-workspace` you will need to create a `SchemaJS.toml` inside it, which will contain all the configuration, and most importantly, the schemas you would like to load in the engine. For the sake of simplicity during this section, we will just load our `public` schema. Our `SchemaJS.toml` will look like this:

```toml
[workspace]
databases = [
    "./public"
]
```

and inside `schemajs-workspace` we will create the following folders

```
- ./public
- ./public/tables
```

You can do this by running the following command

```
mkdir -p public/tables
```

After having followed the steps above, your environment should look like this:

```
- schemajs-workspace
    - SchemaJS.toml
    - public
        - tables
```


# Hello World

Also known as "Your First Table"

{% hint style="info" %}
Read about ["Setting up your environment"](/getting-started/setting-up-your-environment) before writing your first table.
{% endhint %}

## Content

* You will create a table called `books`
* You will insert a row
* You will query the inserted row

## Example Table

After having set-up your environment, we will create a table called **books.** For this, we will create a file named `books.ts` inside your `tables` folder. It will look like this:

{% code title="./public/tables/books.ts" %}

```typescript
export default function main() {
    const { Table, Column } = SchemaJS;
    return new Table("books")
        .addColumn(new Column("id").string())
        .addColumn(new Column("name").string())
        .addColumn(new Column("author").string())
}
```

{% endcode %}

## Insert a row

After having created our table, we will run the engine by executing the following terminal command from the root of where our `SchemaJS.toml` is.

```
schemajs start
```

<div align="left" data-full-width="false"><figure><img src="https://3857732323-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgNrwDrQ1Jjmi890Wdo6L%2Fuploads%2FGHmkIHxv4Y8RC7rBpaeS%2Fout.png?alt=media&amp;token=2dbac1c4-f1ad-40ab-80e9-6be6a40fb3e8" alt="" width="188"><figcaption></figcaption></figure></div>

***

> Running `start` will open up a REPL after having initialized our database.

In our REPL, we will type `use` to access the table. For this, we will first need to access the database and then the table context.

`use("public")`

`use("books")`

<div align="left"><figure><img src="https://3857732323-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgNrwDrQ1Jjmi890Wdo6L%2Fuploads%2FfZr0YdBpWiZzeWLZqwn8%2Fimage.png?alt=media&amp;token=cc304d0b-3f0c-407f-a3f8-0b58266b8ac0" alt="" width="188"><figcaption></figcaption></figure></div>

and finally, after being in the context of the table **books,** we will proceed to run the following Javascript code.

```javascript
SchemaJS.insert({ id: "SOME-ID", "name": "The Lord of the Rings", "author": "J.R.R Tolkien" });
```

## Querying a row

Finally, to query a row, we can run the following JS command:

```javascript
SchemaJS.query(
  new SchemaJS.QueryBuilder()
    .and((and) => and.where("author", "=", "The Lord of the Rings"))
)
.then((res) => {
  SchemaJS.print(JSON.stringify(res));
});
```

<figure><img src="https://3857732323-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgNrwDrQ1Jjmi890Wdo6L%2Fuploads%2FL5HCCtBetdnH0kLfTNQD%2Fout.png?alt=media&amp;token=dd34a134-9fdd-450b-8d20-a38a877711cb" alt=""><figcaption></figcaption></figure>


# TypeScript Support

Typescript is a first class language in SchemaJS, just like JavaScript. No configuration is required to write schemas in Typescript, as they are automatically handled by the internal runtime.


# Module Imports

SchemaJS allows users to write modular code following the ES standard.&#x20;

```typescript
import * from "./module.ts"
```

## Online imports

It is possible to import modules from URLs, such as the following:

```typescript
import { SJS_HELLO_WORLD } from "https://gist.githubusercontent.com/andreespirela/c482ff9571967ad87d669de2116da670/raw/446ab06eff7fc561453184409e62da53063823c3/index.ts"
```


# Custom Queries

Custom queries in **SchemaJS** offer a flexible way to define specialized database operations, simplifying the complexities of traditional database procedures without relying on raw SQL. These queries allow developers to create custom logic that can be easily reused and adapted within the application, enhancing efficiency while keeping the codebase clean and maintainable.

## Motivation

The motivation behind **SchemaJS** custom queries is to move away from the complexities and rigidity of traditional SQL procedures by allowing developers to write powerful database operations directly in JavaScript. This approach not only simplifies the process of defining and executing database logic, but also unlocks new possibilities by integrating the vast ecosystem of JavaScript libraries and tools.

## Calling Custom Queries

Custom queries can be called via:

* gRPC


# Hooks

Hooks in **SchemaJS** allow developers to define custom logic that is automatically executed before or after specific table operations. They provide a powerful way to inject additional behavior, such as validation, logging, transformations, or external API calls, into the lifecycle of database interactions. By using hooks, you can extend the functionality of your tables and ensure that certain tasks are performed consistently and automatically whenever data is inserted, updated, or deleted.

## Motivation

The primary motivation behind hooks in **SchemaJS** is to decouple backend logic from core database operations and automate repetitive or complex database scripts in a streamlined and maintainable manner. By using hooks, developers can define automated behaviors that execute at specific points during a table’s lifecycle—such as before inserting a new record or after updating a row—without cluttering application code or manually managing these tasks with external scripts.

## Defining

Hooks in **SchemaJS** are defined using the `.on()` method, which allows you to attach custom logic to specific table operations. Hooks can be set up for different events, such as **inserts**, **updates**, or **deletes**, and are triggered automatically when those operations occur. These hooks can execute any custom logic you need, such as data validation, transformation, or triggering external services.

```typescript
new Table("orders")
    .addColumn(new Column("id").string())
    .addColumn(new Column("productId").string())
    .addColumn(new Column("quantity").number())
    .on("insert", async (rows) => {
        for(let newOrder of rows) {
            // Automatically update report summary after a new order is inserted
            await updateSalesReport(newOrder.productId, newOrder.quantity);
        }
    });
```


# SchemaJS Global

`globalThis.SchemaJS` is a global object in **SchemaJS** that serves as the primary interface for interacting with the database environment. It provides access to essential APIs and tools, such as the `QueryBuilder`, `Table`, and `Column` classes, as well as utility methods like `query` for executing database queries. By attaching these core functionalities to the global scope, **SchemaJS** allows developers to easily build, query, and manage database tables and schemas within any JavaScript environment, ensuring that the database context and operations are accessible throughout the application.

```typescript
const { Table, Column, .. } = SchemaJS;
```


# Table

In **SchemaJS**, the `Table` global represents the structure of a database table, defining its columns and the queries that can be performed on it. It provides an interface for easily constructing, manipulating, and querying database tables, making it highly flexible for various use cases.

## Constructor

```typescript
new Table(tblName: string);
```

## addColumn

Adds a [column](/reference-guides/schemajs-global/column) to the table. Columns define the structure of each entry in the table, such as the data type and constraints.

```typescript
table.addColumn(col: Column);
```

## addQuery

Defines a custom query for the table. This query can be executed later, allowing dynamic and specific data retrieval operations.

```typescript
table.addQuery("findById", async (req) => {
    let query = new QueryBuilder().where("id", "=", req.id);
    return await query(query);
});
```

## on

The `.on()` method in the `Table` global allows you to register hooks (event listeners) that execute custom logic when specific actions, such as inserts, occur on the table. It provides a way to extend or modify the behavior of table operations, like inserting new rows, by running custom code before or after the operation completes.

```typescript
table.on("insert", (rows: any[]) => {
        console.log("Insertion detected", rows);
});
```


# Column

The `Column` class in **SchemaJS** defines the structure and properties of a column within a table. Each column has a name, data type, optional default value, and additional properties such as whether it is required or acts as a primary key. The `Column` class provides several methods for customizing the behavior and constraints of the column, making it flexible and powerful for defining database schemas.

## Constructor

```typescript
new Column(name: string, dataType?: DataTypes)
```

## string

Sets the column's data type to `String`.

```typescript
column.string()
```

## boolean

Sets the column's data type to `Boolean`.

```typescript
column.boolean()
```

## require

Whether the column is required to exist during insertion.

```typescript
column.require(data: boolean)
```

## withComment

Adds a comment or description to the column for documentation purposes.

```typescript
column.withComment(comment: string)
```

## withDefaultValue

Sets a default value for the column. The value is validated to ensure it matches the column's data type.

```typescript
column.withDefaultValue(val: any)
```

{% hint style="info" %}
The value is validated to ensure it matches the column's data type.
{% endhint %}


# DataTypes

The `DataTypes` enum in **SchemaJS** defines the supported data types for columns in a table. It is used to specify what kind of data each column can hold, such as strings or boolean values. Enums like this provide a clear and type-safe way of working with predefined values, ensuring consistency and avoiding invalid types.

```typescript
export enum DataTypes {
    Uuid = "Uuid",
    String = "String",
    Boolean = "Boolean",
    Number = "Number"
}
```


# QueryBuilder

The `QueryBuilder` class in **SchemaJS** is designed to help you easily construct complex queries for interacting with tables in your database. It provides methods to build `WHERE`, `AND`, and `OR` conditions, allowing for powerful filtering and querying. The `QueryBuilder` class allows users to define conditions programmatically, making it easy to dynamically generate queries and control how data is retrieved from the database.

## Constructor

<pre class="language-typescript"><code class="lang-typescript"><strong>new QueryBuilder(dbName?: string, tableName?: string)
</strong></code></pre>

{% hint style="info" %}
If `dbName` or `tableName` are not passed, the constructor attempts to use the global context (`SJS_CONTEXT`) for the current database and table.
{% endhint %}

{% hint style="info" %}
Using this class from a *custom query or a hook* already injects \`**`SJS_CONTEXT`**`` `. ``You do not need to pass \`**dbName**\` or \`**tableName**\`
{% endhint %}

## where

Adds a `WHERE` condition to the query. The condition specifies the column key, the filter type, and the value to compare against.

```typescript
builder.where(key: string, filter_type: string, value: any)
```

## and

Adds an `AND` condition, grouping multiple conditions under an `AND` clause. The callback allows the user to add more conditions to the `AND` clause using a new `QueryBuilder` instance.

```typescript
builder.and((b) => {
    b.where("age", "=", 30);
    b.where("country", "=", "USA");
});
```

## or

Adds an `OR` condition, grouping multiple conditions under an `OR` clause. The callback allows the user to add more conditions to the `OR` clause using a new `QueryBuilder` instance.

```typescript
builder.or((b) => {
    b.where("status", "=", "inactive");
    b.where("last_login", "<", "2023-01-01");
});
```


# query

The `query` static getter in **SchemaJS** provides a method for executing queries built with the `QueryBuilder`. It ensures that only queries constructed using the `QueryBuilder` class can be executed, offering a layer of validation before performing the actual query operation. The method then retrieves the results by calling the internal `searchRows` function, which queries the specified database and table using the built query.

```typescript
const query = new QueryBuilder("public", "books")
    .where("author_age", "=", 25)
    .build();

// Execute the query
SchemaJS.query(query).then((rows) => {
    SchemaJS.print(rows);
});
```


# rawInsert

The `rawInsert` function in **SchemaJS** is a low-level, asynchronous method designed to insert data directly into a database and table without relying on the global context (`SJS_CONTEXT`). It provides flexibility for inserting data into any specified table by directly specifying the database and table names. This makes `rawInsert` ideal for use cases where the global context is not available or necessary, such as when performing batch operations, dynamic inserts, or when a more direct approach is preferred over the built-in [`insert`](/reference-guides/schemajs-global/insert) method.

```typescript
function rawInsert(dbName: string, tableName: string, data: any);
```


# insert

The `insert` method in **SchemaJS** is a higher-level API that provides a convenient way to insert data into a database and table using the context provided by `globalThis.SJS_CONTEXT`. It ensures that the correct database and table are referenced from the context, offering a more user-friendly and streamlined way of inserting data compared to the lower-level [`rawInsert`](/reference-guides/schemajs-global/rawinsert) method. This method is designed to handle scenarios where the global context is already defined, making it easy to insert data without needing to explicitly specify the database or table every time.

```typescript
function insert(row: any);
```

```typescript
SchemaJS.insert({ id: "", book_name: "", ... })
```


# print

The `print` method in **SchemaJS** is a static utility function used to output messages to the console. It provides a simple and consistent way to log information or display messages during the execution of queries, table operations, or other database interactions. This method can be useful for debugging, monitoring, or providing feedback to the developer or user.

```typescript
function print(msg: string);
```


