v9.1.2
JUSTAOS's ORM (Object–relational mapping) tool is built for Deno and provides transparent persistence for JavaScript objects to Postgres database.
Attributes
Includes Deno configuration
Repository
Current version released
5 months ago
Versions
- v10.1.0Latest
- v10.0.0
- v10.0.0-pre.2
- v10.0.0-pre.1
- v10.0.0-pre.0
- v9.1.2
- v9.1.1
- v9.1.0
- v9.1.0
- v9.0.1
- v9.0.0
- v8.0.0
- v8.0.0
- v8.0.0-pre.9
- v8.0.0-pre.9
- v8.0.0-pre.8
- v8.0.0-pre.7
- v8.0.0-pre.6
- v8.0.0-pre.5
- v8.0.0-pre.5
- v8.0.0-pre.4
- v8.0.0-pre.3
- v8.0.0-pre.2
- v8.0.0-pre.1
- v7.2.0-pre.0
- v7.1.1
- v7.1.1
- v7.1.1-pre.3
- v7.1.1-pre.3
- v7.1.1-pre.2
- v7.1.1-pre.1
- v7.1.1-pre.0
- v7.1.1-pre.0
- v7.1.0
- v7.0.1
- v6.4.0
- v6.3.0
- v6.2.0
- v6.1.0
- v5.13.0
- v5.14.0
- v5.12.0
- v5.11.0
- v5.10.0
- v5.9.0
- v5.8.0
- v5.7.0
- v5.6.3
- v5.6.2
- v5.6.1
- v5.6.0
- v5.5.10
- v5.5.9
- v5.5.8
- v5.5.7
- v5.5.6
- v5.5.5
- v5.5.4
- v5.5.3
- v5.5.2
- v5.5.1
- v5.5.0
- v5.4.11
- v5.4.10
- v5.4.9
- v5.4.8
- v5.4.7
- v5.4.6
- v5.4.5
- v5.4.4
- v5.4.3
- v5.4.2
- v5.4.1
- v5.4.0
- v5.3.0
- v5.2.7
- v5.2.6
- v5.2.5
- v5.2.3
- v5.2.4
- v5.2.2
- v5.2.1
- v5.2.0
- v5.1.0
- v5.0.2
- v5.0.1
- v5.0.0
- v4.11.0
- v4.10.2
JUSTAOS’s ORM
JUSTAOS’s ORM (Object Relational Mapping) tool is built for Deno and provides transparent persistence for JavaScript objects to Postgres database.
- Supports all primitive data types (string, integer, float, boolean, date, object, array, etc).
- Supports custom data types.
- Supports table with multi-level inheritance.
- Also supports interception on operations (create, read, update and delete).
deno add @justaos/orm
import { ORM } from "@justaos/orm";
Database connection
const odm = new ORM({
database: "employee-database",
username: "postgres",
password: "postgres",
hostname: "localhost",
port: 5432,
});
let conn: ORMConnection | undefined;
try {
conn = await odm.connect(true /* create database if not exists */);
console.log("Connection established successfully");
} catch (error) {
console.log("Error while establishing connection", error);
}
if (conn) await conn.closeConnection();
Defining tables
await orm.defineTable({
name: "blog_post",
columns: [
{
name: "title",
type: "string",
},
{
name: "content",
type: "string",
},
],
});
await orm.defineTable({
name: "comment",
columns: [
{
name: "blog_post",
type: "reference",
},
{
name: "message",
type: "string",
},
],
});
Querying
await conn.defineTable({
name: "teacher",
columns: [
{
name: "name",
type: "string",
},
{
name: "roll_no",
type: "integer",
},
{
name: "age",
type: "integer",
},
],
});
const teacherTable = conn.table("teacher");
for (let i = 0; i < 10; i++) {
const teacher = teacherTable.createNewRecord();
teacher.set("name", "a" + (i + 1));
teacher.set("roll_no", i + 1);
teacher.set("age", 10 * ((i + 1) % 2));
await teacher.insert();
}
const records = await teacherTable
.select()
.orderBy("roll_no", "DESC")
.toArray();
for (const record of records) {
console.log(record.get("name") + " :: " + record.get("roll_no"));
}
console.log("Count :: " + (await teacherTable.count()));
await conn.closeConnection();
Querying with compound ‘OR’ and ‘AND’ conditions
// Where 'age' is 10 and (name is 'a1' or 'roll_no' is 5)
// SELECT * FROM public.teacher WHERE "age" = 10 AND ("name" = 'a1' OR "roll_no" = 5)
const selectQuery = teacherTable.select();
selectQuery.where("name", "a1");
const compoundOrQuery = selectQuery.compoundOr();
compoundOrQuery.where("roll_no", 4);
compoundOrQuery.where("roll_no", 2);
records = await selectQuery.toArray();
console.log(records.map((t) => t.toJSON()));
Using cursor
const recordCursor = await teacherTable
.select()
.orderBy("roll_no", "DESC")
.execute();
for await (const record of recordCursor) {
console.log(record.get("name") + " :: " + record.get("roll_no"));
}
Intercepting database operations
Intercept and compute student full name before insert and print all records after
const conn = await odm.connect(true);
await conn.defineTable({
name: "student",
columns: [
{
name: "first_name",
type: "string",
},
{
name: "last_name",
type: "string",
},
{
name: "full_name", /* Value computed in intercept */
type: "string",
},
],
});
class FullNameIntercept extends DatabaseOperationInterceptor {
getName() {
return "full-name-intercept";
}
async intercept(
tableName: string,
operation: DatabaseOperationType,
when: DatabaseOperationWhen,
records: Record[],
_context: DatabaseOperationContext,
) {
if (tableName === "student") {
console.log(
`[collectionName=${tableName}, operation=${operation}, when=${when}]`,
);
if (operation === "INSERT") {
if (when === "BEFORE") {
for (const record of records) {
console.log(
`Full name field updated for :: ${record.get("first_name")}`,
);
record.set(
"full_name",
`${record.get("first_name")} ${record.get("last_name")}`,
);
}
}
}
if (operation === "SELECT") {
if (when === "AFTER") {
for (const record of records) {
console.log(JSON.stringify(record.toJSON(), null, 4));
}
}
}
}
return records;
}
}
odm.addInterceptor(new FullNameIntercept());
const studentTable = conn.table("student");
const studentRecord = studentTable.createNewRecord();
studentRecord.set("first_name", "John");
studentRecord.set("last_name", "Doe");
await studentRecord.insert();
await studentTable.select().toArray();
/* This will print the following:
[collectionName=student, operation=INSERT, when=BEFORE]
Full name field updated for :: John
[collectionName=student, operation=INSERT, when=AFTER]
[collectionName=student, operation=SELECT, when=BEFORE]
[collectionName=student, operation=SELECT, when=AFTER]
{
"id": "653c21bb-7d92-435e-a742-1da749f914dd",
"_table": "student",
"first_name": "John",
"last_name": "Doe",
"full_name": "John Doe"
}
*/
await conn.closeConnection();
Define custom field type
After connection established, you can define custom field type.
odm.addDataType(
new (class extends DataType {
constructor() {
super("email", "VARCHAR");
}
toJSONValue(value: string | null): string | null {
return value;
}
validateDefinition(_columnDefinition: ColumnDefinition) {
return true;
}
setValueIntercept(newValue: any): any {
return newValue;
}
async validateValue(value: unknown): Promise<void> {
const pattern = "(.+)@(.+){2,}\\.(.+){2,}";
if (
value &&
typeof value === "string" &&
!new RegExp(pattern).test(value)
) {
throw new Error("Not a valid email");
}
}
})(),
);
await conn.defineTable({
name: "student",
columns: [
{
name: "name",
type: "string",
},
{
name: "personal_contact",
type: "email",
},
{
name: "emp_no",
type: "uuid",
},
{
name: "salary",
type: "integer",
},
{
name: "birth_date",
type: "date",
},
{
name: "gender",
type: "boolean",
},
],
});
const studentTable = conn.table("student");
const student = studentTable.createNewRecord();
student.set("personal_contact", "test");
student.set("birth_date", new Date());
try {
await student.insert();
console.log("Student created");
} catch (error) {
console.log(error.toJSON());
}
Inheritance
await conn.defineTable({
name: "animal",
columns: [
{
name: "name",
type: "string",
},
],
});
const animalTable = conn.table("animal");
const animal = animalTable.createNewRecord();
animal.set("name", "Puppy");
await animal.insert();
await conn.defineTable({
name: "dog",
inherits: "animal",
final: true,
columns: [
{
name: "breed",
type: "string",
},
],
});
const dogTable = conn.table("dog");
const husky = dogTable.createNewRecord();
husky.set("name", "Jimmy");
husky.set("breed", "Husky");
await husky.insert();
const animalCursor = await animalTable.select().execute();
for await (const animal of animalCursor()) {
console.log(animal.toJSON());
}
await conn.closeConnection();
Data type | Record.get | Record.getJSONValue |
---|---|---|
date | Temporal.PlainDate | string |
datetime | Temporal.PlainDateTime | string |
integer | number | number |
json | {} | {} |
number | number | number |
string | string | string |
Check the examples >> here <<