{"id":33898723,"url":"https://github.com/redvars/orm","last_synced_at":"2026-04-12T03:01:40.350Z","repository":{"id":47111483,"uuid":"143191074","full_name":"redvars/orm","owner":"redvars","description":"RED:VARS's ORM (Object–relational mapping) tool is built for Deno and provides transparent persistence for JavaScript objects to Postgres database.","archived":false,"fork":false,"pushed_at":"2025-11-11T11:58:31.000Z","size":1738,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-11T15:56:59.700Z","etag":null,"topics":["database","deno","javascript","odm","postgresql","sql","typescript"],"latest_commit_sha":null,"homepage":"https://redvars.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redvars.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["shivajivarma"]}},"created_at":"2018-08-01T18:05:16.000Z","updated_at":"2025-11-11T11:58:35.000Z","dependencies_parsed_at":"2024-05-13T04:31:12.324Z","dependency_job_id":"fb7cd38a-bb5b-46cc-bbaf-ee1482c5a1ed","html_url":"https://github.com/redvars/orm","commit_stats":{"total_commits":311,"total_committers":3,"mean_commits":"103.66666666666667","dds":0.022508038585209,"last_synced_commit":"34f0b9d93ff35c97b76a55a823640b84aac528db"},"previous_names":["anysols/anysols-odm","justaos/orm","justaos/odm","anysols/anysols-model","p4rm/odm","plt4rm/odm","redvars/orm"],"tags_count":160,"template":false,"template_full_name":null,"purl":"pkg:github/redvars/orm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redvars%2Form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redvars%2Form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redvars%2Form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redvars%2Form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redvars","download_url":"https://codeload.github.com/redvars/orm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redvars%2Form/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28385926,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T12:01:30.995Z","status":"ssl_error","status_checked_at":"2026-01-13T12:00:09.625Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","deno","javascript","odm","postgresql","sql","typescript"],"created_at":"2025-12-11T21:16:21.433Z","updated_at":"2026-01-18T11:48:02.503Z","avatar_url":"https://github.com/redvars.png","language":"TypeScript","readme":"# RESVARS ORM\n\n![GitHub release (with filter)](https://img.shields.io/github/v/release/redvars/orm?label=Release)\n[![Test](https://github.com/redvars/orm/workflows/Test/badge.svg)](https://github.com/redvars/orm/actions?workflow=Test)\n[![Coverage](https://codecov.io/gh/redvars/orm/branch/main/graph/badge.svg?token=OzlniGFmNp)](https://codecov.io/gh/redvars/orm)\n[![License](https://img.shields.io/github/license/redvars/orm.svg)](/LICENSE)\n[![Contributors](https://img.shields.io/github/contributors/redvars/orm.svg)]()\n\nRESVARS ORM (Object Relational Mapping) tool is built for Deno and provides\ntransparent persistence for JavaScript objects to Postgres database.\n\n- Supports all primitive data types (string, integer, float, boolean, date,\n  object, array, etc.).\n- Supports custom data types.\n- Supports table with multi-level inheritance.\n- Also supports interception on operations (create, read, update and delete).\n\n```ts\nimport { ORM } from \"jsr:@redvars/orm\";\n```\n\n## Database connection\n\n```ts\nconst odm = new ORM({\n  database: \"school-database\",\n  username: \"postgres\",\n  password: \"postgres\",\n  hostname: \"localhost\",\n  port: 5432,\n});\n\ntry {\n  const client: ORMClient = await odm.connect(\n    true, /* create database if not exists */\n  );\n  console.log(\"Client connected successfully\");\n  client.closeConnection();\n} catch (error) {\n  console.log(\"Error while establishing connection\", error);\n}\n```\n\n## Defining tables\n\nDefinition automatically includes `id` and `_table` fields on every table.\n\n```ts\nawait client.defineTable({\n  name: \"department\",\n  columns: [\n    {\n      name: \"name\",\n      type: \"string\",\n    },\n    {\n      name: \"code\",\n      type: \"string\",\n    },\n  ],\n});\n\nawait client.defineTable({\n  name: \"teacher\",\n  columns: [\n    {\n      name: \"name\",\n      type: \"string\",\n    },\n    {\n      name: \"badge_number\",\n      type: \"integer\",\n    },\n    {\n      name: \"age\",\n      type: \"integer\",\n    },\n    {\n      name: \"date_of_joining\",\n      type: \"date\",\n    },\n    {\n      name: \"department\",\n      type: \"uuid\",\n      foreign_key: {\n        table: \"department\",\n        column: \"id\",\n      },\n    },\n  ],\n});\n```\n\n### Unique constraint\n\n```ts\nawait client.defineTable({\n  name: \"student\",\n  columns: [\n    {\n      name: \"name\",\n      type: \"string\",\n    },\n    {\n      name: \"roll_no\",\n      type: \"integer\",\n      unique: true,\n    },\n    {\n      name: \"age\",\n      type: \"integer\",\n    },\n  ],\n  unique: [[\"name\", \"age\"]],\n});\n```\n\n## Querying\n\n```ts\nconst teacherTable = client.table(\"teacher\");\nfor (let i = 0; i \u003c 10; i++) {\n  const teacher = teacherTable.createNewRecord();\n  teacher.set(\"name\", randomNames());\n  teacher.set(\"badge_number\", i + 1);\n  teacher.set(\"age\", 10 * ((i + 1) % 2));\n  await teacher.insert();\n}\n\nlet records = await teacherTable.orderBy(\"badge_number\", \"DESC\").toArray();\n\nfor (const record of records) {\n  console.log(record.get(\"name\") + \" :: \" + record.get(\"badge_number\"));\n}\nconsole.log(\"Count :: \" + (await teacherTable.count()));\n```\n\n## Querying with compound 'OR' and 'AND' conditions\n\n```ts\n// Where 'age' is 10  and (name is 'a1' or 'roll_no' is 5)\n// SELECT * FROM public.teacher WHERE \"age\" = 10 AND (\"name\" = 'a1' OR \"roll_no\" = 5)\n\nconst selectQuery = teacherTable\n  .where(\"age\", 10)\n  .andWhere((compoundQuery) =\u003e {\n    compoundQuery\n      .where(\"name\", \"a1\")\n      .orWhere(\"badge_number\", \"5\");\n  });\n\nrecords = await selectQuery.toArray();\nconsole.log(records.map((t) =\u003e t.toJSON()));\n```\n\n#### Using cursor\n\n```ts\nconst recordCursor = await teacherTable\n  .select()\n  .orderBy(\"roll_no\", \"DESC\")\n  .execute();\n\nfor await (const record of recordCursor) {\n  console.log(record.get(\"name\") + \" :: \" + record.get(\"roll_no\"));\n}\n```\n\n## Intercepting database operations\n\nIntercept and compute student full name before insert and print all records\nafter\n\n```ts\nconst client = await odm.connect(true);\n\nawait client.defineTable({\n  name: \"student\",\n  columns: [\n    {\n      name: \"first_name\",\n      type: \"string\",\n    },\n    {\n      name: \"last_name\",\n      type: \"string\",\n    },\n    {\n      name: \"full_name\", /* Value computed in intercept */\n      type: \"string\",\n    },\n  ],\n});\n\nclass FullNameIntercept extends RecordInterceptor {\n  getName() {\n    return \"full-name-intercept\";\n  }\n\n  async intercept(\n    table: Table,\n    interceptType: TRecordInterceptorType,\n    records: Record[],\n    _context: TRecordInterceptorContext,\n  ) {\n    if (table.getName() === \"student\") {\n      console.log(`[collectionName=${table.getName()}, when=${interceptType}]`);\n      if (interceptType === \"BEFORE_INSERT\") {\n        for (const record of records) {\n          console.log(\n            `Full name field updated for :: ${record.get(\"first_name\")}`,\n          );\n          record.set(\n            \"full_name\",\n            `${record.get(\"first_name\")} ${record.get(\"last_name\")}`,\n          );\n        }\n      }\n      if (interceptType === \"AFTER_SELECT\") {\n        for (const record of records) {\n          console.log(JSON.stringify(record.toJSON(), null, 4));\n        }\n      }\n    }\n    return records;\n  }\n}\n\nodm.addInterceptor(new FullNameIntercept());\n\nconst studentTable = client.table(\"student\");\nconst studentRecord = studentTable.createNewRecord();\nstudentRecord.set(\"first_name\", \"John\");\nstudentRecord.set(\"last_name\", \"Doe\");\nawait studentRecord.insert();\nawait studentTable.toArray();\n/* This will print the following:\n[collectionName=student, operation=INSERT, when=BEFORE]\nFull name field updated for :: John\n[collectionName=student, operation=INSERT, when=AFTER]\n[collectionName=student, operation=SELECT, when=BEFORE]\n[collectionName=student, operation=SELECT, when=AFTER]\n{\n    \"id\": \"653c21bb-7d92-435e-a742-1da749f914dd\",\n    \"_table\": \"student\",\n    \"first_name\": \"John\",\n    \"last_name\": \"Doe\",\n    \"full_name\": \"John Doe\"\n}\n*/\n\nclient.closeConnection();\n```\n\n## Define custom field type\n\nAfter connection established, you can define custom field type.\n\n```ts\nconst client = await odm.connect(true);\n\nclass EmailType extends IDataType {\n  constructor() {\n    super(\"email\");\n  }\n\n  getNativeType(_definition: TColumnDefinition): TColumnDataType {\n    return \"VARCHAR\";\n  }\n\n  toJSONValue(value: string | null): string | null {\n    return value;\n  }\n\n  validateDefinition(_columnDefinition: TColumnDefinition) {\n    // Throw an error if something in definition is not meeting your expectation.\n  }\n\n  setValueIntercept(newValue: any): any {\n    return newValue;\n  }\n\n  async validateValue(value: unknown): Promise\u003cvoid\u003e {\n    const pattern = \"(.+)@(.+){2,}\\\\.(.+){2,}\";\n    if (\n      value \u0026\u0026\n      typeof value === \"string\" \u0026\u0026\n      !new RegExp(pattern).test(value)\n    ) {\n      throw new Error(\"Not a valid email\");\n    }\n  }\n}\n\nodm.addDataType(new EmailType());\n\nawait client.defineTable({\n  name: \"employee\",\n  columns: [\n    {\n      name: \"name\",\n      type: \"string\",\n    },\n    {\n      name: \"personal_contact\",\n      type: \"email\",\n    },\n    {\n      name: \"emp_no\",\n      type: \"uuid\",\n    },\n    {\n      name: \"salary\",\n      type: \"integer\",\n    },\n    {\n      name: \"birth_date\",\n      type: \"date\",\n    },\n    {\n      name: \"gender\",\n      type: \"boolean\",\n    },\n  ],\n});\n\nconst studentTable = client.table(\"employee\");\nconst student = studentTable.createNewRecord();\nstudent.set(\"personal_contact\", \"NOT_EMAIL_VALUE\");\nstudent.set(\"birth_date\", new Date());\ntry {\n  await student.insert(); // this will throw an error, because email is not valid\n  console.log(\"Student created\");\n} catch (error) {\n  console.log(error);\n}\n\nclient.closeConnection();\n```\n\n## Inheritance\n\n```ts\nconst client = await odm.connect(true);\n\nawait client.defineTable({\n  name: \"animal\",\n  columns: [\n    {\n      name: \"name\",\n      type: \"string\",\n    },\n  ],\n});\n\nconst animalTable = client.table(\"animal\");\nconst animal = animalTable.createNewRecord();\nanimal.set(\"name\", \"Puppy\");\nawait animal.insert();\n\nawait client.defineTable({\n  name: \"dog\",\n  inherits: \"animal\",\n  final: true,\n  columns: [\n    {\n      name: \"breed\",\n      type: \"string\",\n    },\n  ],\n});\n\nconst dogTable = client.table(\"dog\");\nconst husky = dogTable.createNewRecord();\nhusky.set(\"name\", \"Jimmy\");\nhusky.set(\"breed\", \"Husky\");\nawait husky.insert();\n\nconst animalCursor = await animalTable.execute();\n\nfor await (const animal of animalCursor()) {\n  console.log(animal.toJSON());\n}\n\nclient.closeConnection();\n```\n\n## Known limitations:\n\n## Data types\n\n| Data type    | Record.get             | Record.getJSONValue |\n|--------------|------------------------|---------------------|\n| **boolean**  | boolean                | boolean             |\n| **date**     | Temporal.PlainDate     | string              |\n| **datetime** | Temporal.PlainDateTime | string              |\n| **integer**  | number                 | number              |\n| **json**     | {}                     | {}                  |\n| **number**   | number                 | number              |\n| **string**   | string                 | string              |\n| **uuid**     | string                 | string              |\n\nCheck the examples \u003e\u003e [here](./examples) \u003c\u003c\n\n## Code of Conduct\n\n[Contributor Covenant](/CODE_OF_CONDUCT.md)\n","funding_links":["https://github.com/sponsors/shivajivarma"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredvars%2Form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredvars%2Form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredvars%2Form/lists"}