0.2.0 • Published 5 years ago

elcy v0.2.0

Weekly downloads
1
License
MIT
Repository
github
Last release
5 years ago

Elcy

codecov Build Status

Elcy is an ORM for typescript and javascript. Elcy is highly influenced by Entity Framework and NHibernate.

Installation

To be updated...

Supported Database

  • Sql Server
  • Sqlite (not yet)

How to use

Create the Model

Entity on your model is mark with @Entity class decorator.

To add database columns, you simply need to add decorator to your entity properties. Elcy has several column decorator for defining your column with specific column type:

  • @StringColumn : string column type.
  • @BooleanColumn : boolean column type.
  • @NumberColumn : integer column type.
  • @DecimalColumn : decimal column type.
  • @ApproximateNumberColumn : approximate number column type. ex: float
  • @IdentifierColumn : uuid column type.
  • @DateColumn : date column type.
  • @EnumColumn : not implemented yet
  • @EmbeddedColumn : not implemented yet

Here several other decorator for entity property:

  • @CreatedDate: a date column type used to store entity creation date.
  • @ModifiedDate: a date column type used to store entity last modified date.
  • @ColumnDescription: add description to column.
  • @DeletedColumn: a boolean column type used for soft delete indicator.
  • @NullableColumn: mark column nullable.
  • @PrimaryKey: mark column as one of the entity primary key.

Example:

import {Entity} from "elcy/Decorator/Entity";
import { PrimaryKey } from "Elcy/Decorator/Column/PrimaryKey";
import { NumberColumn } from "Elcy/Decorator/Column/NumberColumn";
import { DateColumn } from "Elcy/Decorator/Column/DateColumn";
import { IdentifierColumn } from "Elcy/Decorator/Column/IdentifierColumn";
import { UUID } from "Elcy/Data/UUID";

@Entity()
export class Order {
    @PrimaryKey()
    @IdentifierColumn()
    public OrderId: UUID;

    @NumberColumn({ columnType: "bigint" })
    public Amount: number;

    @DateColumn()
    public OrderDate: Date;
    @CreatedDate()
    public CreatedDate: Date;
    @ModifiedDate()
    public ModifiedDate: Date;
    @DeletedColumn()
    public isDeleted: boolean;
}

Create a Context

a Context represents a session with the database, allowing us to query and save data. Define a context that derives from Elcy/Data/DbContext and exposes a typed DbSet for each class in our model. Elcy has defined DbContext that you could used for each support db under Elcy/Driver.

Example:

import { MssqlDbContext } from "Elcy/Driver/Mssql";

export class MyDb extends MssqlDbContext {
    constructor() {
        super(() => new MssqlDriver({
            host: "localhost\\SQLSERVER",
            database: "mydb",
            port: 1433, // example
            user: "xxx",
            password: "xxx",
        }));
    }
    public entityTypes = [Order]; // all entities that will be loaded using this context.
    public orders: DbSet<Order> = this.set(Order); // exposed typed DbSet for Order model.
}

Reading Data

Elcy used Linq-like syntax to read data from database. Example:

(
    async() => {
        const db = new MyDb();

        // select top 10 order with Amount > 10 order by amount desc.
        const orders = await db.orders.take(10).where(o => o.Amount > 10).orderBy([o => o.Amount, "DESC"]).toArray();

        // count all orders
        const count = await db.orders.count();
        
        // where with parameter
        const maxAmount = 10;
        const count = await db.orders.parameters({ maxAmount }).where(o => o.Amount < maxAmount).count();
    }
)();

Below are the supported query expression syntax:

  • where(predicate: (item: T) => boolean): Queryable<T>
  • distinct(): Queryable<T>
  • include(...includes: Array<(item: T) => any>): Queryable<T>
  • orderBy(...selectors: IQueryableOrderDefinition<T>[]): Queryable<T>
  • skip(skip: number): Queryable<T>
  • take(take: number): Queryable<T>
  • select<TReturn>(selector: ((item: T) => TReturn)): Queryable<TReturn>
  • selectMany<TReturn>(selector: (item: T) => TReturn[]): Queryable<TReturn>
  • groupBy<K>(keySelector: (item: T) => K): Queryable<IGroupArray<T, K>>: limitation. groupBy(..).toArray() will not work.
  • union(array2: Queryable<T>, isUnionAll?: boolean): Queryable<T>
  • intersect(array2: Queryable<T>): Queryable<T>
  • except(array2: Queryable<T>): Queryable<T>
  • toArray()
  • sum()
  • count()
  • max()
  • min()
  • avg()
  • all()
  • any()
  • first()
  • innerJoin: not yet supported
  • rightJoin: not yet supported
  • leftJoin: not yet supported
  • fullJoin: not yet supported
  • pivot: not yet supported

Writing Data

Create:

(
    async() => {
        const db = new MyDb();

        // example 1: create and attach
        const order = new Order();
        order.OrderId = UUID.new();
        order.Amount = 10;
        db.add(order);

        // example 2
        const order2 = db.orders.new(UUID.new());
        order2.Amount = 10;

        db.saveChanges();
    }
)();

Update

(
    async() => {
        const db = new MyDb();

        const order = db.orders.first();
        order.Amount += 1;
        
        await db.saveChanges();
    }
)();

Delete

(
    async() => {
        const db = new MyDb();

        const order = db.orders.first();
        db.delete(order);
        await db.saveChanges();
    }
)();

Transaction

(
    async() => {
        const db = new MyDb();

        await db.transaction(o => {
            // your code goes here
        });
    }
)();