DEV Community

loading...
Cover image for DBless with Nucleoid runtime
Nucleoid

DBless with Nucleoid runtime

canmingir profile image Can Mingir Updated on ・4 min read

Well, you have to store somewhere.

Traditionally, a programming runtime processes functionalities, and as a result, it sends SQL statements to RDBMS. Even tough, there are alternative options arising in recent market such as NoSQL, Data Grid, in-memory database etc., they are still part of the same architecture of; programming runtime and persistence unit has to be separated.

Nucleoid is a declarative programming runtime with gathering both of processing and storing into the same runtime, so, it doesn’t require external database.

Nucleoid doesn’t require code files to compile, instead it receives ES6 (JavaScript) statements as declarative statements like databases receive SQL statements. Each > is an entry into the system.


> a = 1
Enter fullscreen mode Exit fullscreen mode

First of, it runs the statement(s) in the state, which is the exact same as all JavaScript engines do, assigning a variable to value of 1.

Before closing the transaction, if the variable is part of other assignment, it runs dependents based on the graph, where all dependent information is held.

> a = 1
> b = a + 2
> c = b + 3
> a = 2
Enter fullscreen mode Exit fullscreen mode

Alt Text

Since a is adjacent to b in the graph, the runtime reruns b = a + 2 , and updates b to 4 in the state along with a is being 2 in the state, and the same flow for c. If there is no logical conflict like circular dependency, it stores each statement as received on the disk as finalizing the transaction.

Alt Text

This algorithm parts from traditional way of storing and caching because databases usually cache data as it stores in the similar structure, but in this case, memory holds value of the variable, and disk stores statements as cumulative representation. This algorithm is also commonly used in event sourcing/CQRS, as event being received, the algorithm stores the event, and updates its result.

Performance

Since the state is already in memory, processing becomes faster because traditional programming runtime requires retrieving data regardless from database or cache server. Also, as mentioned, Nucleoid appends statements as received, and appending data on the file is the fastest disk operation. In addition, since there is no network communication required, it cuts that from the equation. For a trade off, it requires just-in-time compiling and computing on dependency graph as well as increases space complexity of storage on the hard drive.

Operations

Nucleoid supports all database operations in ES6 (JavaScript) syntax including relationships.

Relationships

Relationships of objects are defined similar to database’s relationships, but it requires to define in declarative syntax.

One-to-One

One-to-one’s defined as referring object’s property to another object instance.

> class Driver {}
> class Vehicle {}
> driver1 = new Driver();
> vehicle1 = new Vehicle();
> driver1.vehicle = vehicle1;
Enter fullscreen mode Exit fullscreen mode

Bidirectional relationships requires additional declaration in order to keep both side synced, so not recommended unless absolutely required, associative entity may be used as alternative.

Still all the declarations are applicable to the property:

> Vehicle.type = "CAR"
> driver1.vehicle.type
"CAR"
Enter fullscreen mode Exit fullscreen mode

One-to-Many

One-to-Many is defined in two ways:

List as in One’s side

It is a list created as property:

> class Customer {}
> class Order {}
> Customer.orders = [];
> customer1 = new Customer();
> order1 = new Order();
> customer1.orders.push(order1);
Enter fullscreen mode Exit fullscreen mode

Property as in Many’s side

It is a property created, which refers to other instance:

> class Employee {}
> class Project {}
> employee1 = new Employee()
> project1 = new Project();
> project1.employee = employee1;
Enter fullscreen mode Exit fullscreen mode

Many-to-Many

Many-to-Many is relatively straightforward as only possible with associative entity without carrying any additional constraint.

> class Passenger {}
> class Flight {}
> class Ticket {}
> passenger1 = new Passenger();
> flight1 = new Flight();
> ticket1 = new Ticket();
> ticket1.passenger = passenger1
> ticket1.flight = flight1;
> flight2 = new Flight();
> ticket2 = new Ticket();
> ticket2.passenger = passenger1
> ticket2.flight = flight2;
Enter fullscreen mode Exit fullscreen mode

Queries

Queries is done with functional programming.

The runtime stores each instance into its class list like driver1 = new Driver() will be part of Drivers.

One-to-One

> Drivers.filter(d=>d.state== "GA").filter(d=>d.vehicle.year > 2010)
// Finds drivers in GA state with card younger than 2010
Enter fullscreen mode Exit fullscreen mode

One-to-Many

> Orders.filter( o => o.price > 100 && o.customer.id == 192)
// Finds orders with bigger than $100 prize of customer with id 192
Enter fullscreen mode Exit fullscreen mode

Other direction

> Customers.find(c=>c.id == 192).orders.filter(o=>o.price > 100)
Enter fullscreen mode Exit fullscreen mode

Many-to-Many

Tickets.filter(t => t.passenger.id == 6912 && t.flight.destination == "LA")
// Finds ticket of passenger with id 6912 for destination to FL
Enter fullscreen mode Exit fullscreen mode

These examples from nucleoid.org/tutorial


Alt Text

Nucleoid is open source (Apache 2.0), a runtime environment that allows declarative programming written in ES6 (JavaScript) syntax. Since statements are declarative, the runtime provides logical integrity and persistency as hiding technical details.

Join community at gitlab.com/nucleoid/nucleoid

Discussion (0)

pic
Editor guide