{"_id":"@aquapha/aq-orm","name":"@aquapha/aq-orm","dist-tags":{"latest":"2.4.5"},"versions":{"2.4.5":{"name":"@aquapha/aq-orm","version":"2.4.5","publishConfig":{"access":"public"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"license":"MIT","author":{"name":"aquapha"},"description":"AQ ORM core","repository":{"type":"git","url":"git+https://github.com/aquapha/aq-orm.git","directory":"packages/core"},"homepage":"https://github.com/aquapha/aq-orm#readme","bugs":{"url":"https://github.com/aquapha/aq-orm/issues"},"keywords":["orm","fivem","oxmysql","typescript","query-builder"],"peerDependencies":{"@overextended/oxmysql":"1.4.2"},"devDependencies":{"@types/node":"24.10.4","tsup":"8.5.1","typescript":"5.9.3","vitest":"4.0.16","@aq-orm/eslint":"1.0.0","@aq-orm/tsup":"1.0.0","@aq-orm/typescript":"1.0.0"},"scripts":{"test":"vitest run --typecheck.tsconfig tsconfig.test.json","build":"npx tsup","tsc":"npx tsc --noEmit","lint":"eslint . --ext .ts"},"_id":"@aquapha/aq-orm@2.4.5","_integrity":"sha512-fIh0OQTfLdRVcjmF7E6vQKz8prwb80P7konvi50s62qgyUByYjQz+pPBufYtqzfWJgtekNpTE+cLxgIO1/mhgw==","_resolved":"/tmp/08ab77cc9fa98e1742901c517b7421e9/aquapha-aq-orm-2.4.5.tgz","_from":"file:aquapha-aq-orm-2.4.5.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-fIh0OQTfLdRVcjmF7E6vQKz8prwb80P7konvi50s62qgyUByYjQz+pPBufYtqzfWJgtekNpTE+cLxgIO1/mhgw==","shasum":"262b17086e7e701a024880f71aefd16ebbc1079b","tarball":"https://registry.npmjs.org/@aquapha/aq-orm/-/aq-orm-2.4.5.tgz","fileCount":9,"unpackedSize":295038,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCNvOxz7T3enAjeL1QxTMzW6onMq8xxmNt04xynqqglBQIhAPfLfuabt4O+wQDyAS0PpJsNUiTTl1Tnpgs87HLcXL6N"}]},"_npmUser":{"name":"aquapha","email":"paulius@liniovas.lt"},"directories":{},"maintainers":[{"name":"aquapha","email":"paulius@liniovas.lt"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/aq-orm_2.4.5_1770755653306_0.529670235991982"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-10T20:34:13.203Z","2.4.5":"2026-02-10T20:34:13.465Z","modified":"2026-02-10T20:34:13.682Z"},"maintainers":[{"name":"aquapha","email":"paulius@liniovas.lt"}],"description":"AQ ORM core","homepage":"https://github.com/aquapha/aq-orm#readme","keywords":["orm","fivem","oxmysql","typescript","query-builder"],"repository":{"type":"git","url":"git+https://github.com/aquapha/aq-orm.git","directory":"packages/core"},"author":{"name":"aquapha"},"bugs":{"url":"https://github.com/aquapha/aq-orm/issues"},"license":"MIT","readme":"# @aquapha/aq-orm\n\nA lightweight, type-safe ORM for FiveM using oxmysql.\n\n## Table of Contents\n\n- [Prerequisites](#prerequisites)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Schema](#schema)\n  - [Defining Tables](#defining-tables)\n  - [Column Types](#column-types)\n  - [Column Modifiers](#column-modifiers)\n  - [Type Inference](#type-inference)\n- [Query Builder](#query-builder)\n  - [Select](#select)\n  - [Insert](#insert)\n  - [Update](#update)\n  - [Delete](#delete)\n- [Conditions](#conditions)\n  - [Comparison](#comparison)\n  - [Logical](#logical)\n  - [Other](#other)\n- [Aggregates](#aggregates)\n- [SQL Functions](#sql-functions)\n  - [sqlIf](#sqlif)\n  - [jsonObject](#jsonobject)\n  - [jsonExtract](#jsonextract)\n- [Transactions](#transactions)\n- [Raw SQL](#raw-sql)\n- [Driver](#driver)\n- [License](#license)\n\n## Prerequisites\n\nThis library requires [`@overextended/oxmysql`](https://github.com/overextended/oxmysql) as the database driver in your FiveM server.\n\n## Installation\n\n```bash\npnpm add @aquapha/aq-orm\n```\n\n## Quick Start\n\n```typescript\nimport { oxmysql } from \"@overextended/oxmysql\";\nimport {\n  Database,\n  Driver,\n  table,\n  int,\n  varchar,\n  boolean,\n  eq,\n} from \"@aquapha/aq-orm\";\n\n// Define schema\nconst users = table(\"users\", {\n  id: int(\"id\").primaryKey().autoIncrement(),\n  name: varchar(\"name\", 255).notNull(),\n  active: boolean(\"active\").default(true),\n});\n\n// Create database instance\nconst db = new Database(new Driver(oxmysql));\n\n// Query\nconst activeUsers = await db\n  .select(users)\n  .where(eq(users.columns.active, true))\n  .execute();\n```\n\n## Schema\n\n### Defining Tables\n\n```typescript\nimport { table, int, varchar, text, boolean, timestamp, json, enumCol } from \"@aquapha/aq-orm\";\n\nconst users = table(\"users\", {\n  id: int(\"id\").primaryKey().autoIncrement(),\n  name: varchar(\"name\", 255).notNull(),\n  email: varchar(\"email\").notNull().unique(),\n  role: enumCol(\"role\", [\"admin\", \"user\", \"moderator\"]).notNull(),\n  active: boolean(\"active\").default(true),\n  createdAt: timestamp(\"created_at\").notNull(),\n});\n\nconst posts = table(\"posts\", {\n  id: int(\"id\").primaryKey().autoIncrement(),\n  userId: int(\"user_id\").notNull(),\n  title: varchar(\"title\", 255).notNull(),\n  content: text(\"content\"),\n  metadata: json<{ tags: string[] }>(\"metadata\"),\n});\n```\n\n### Column Types\n\n| Builder                             | MySQL Type   | TypeScript Type |\n| ----------------------------------- | ------------ | --------------- |\n| `int(name)`                         | INT          | `number`        |\n| `bigint(name)`                      | BIGINT       | `number`        |\n| `varchar(name, length?)`            | VARCHAR(n)   | `string`        |\n| `text(name)`                        | TEXT         | `string`        |\n| `boolean(name)`                     | TINYINT(1)   | `boolean`       |\n| `date(name)`                        | DATE         | `Date`          |\n| `timestamp(name)`                   | TIMESTAMP    | `Date`          |\n| `datetime(name)`                    | DATETIME     | `Date`          |\n| `json<T>(name)`                     | JSON         | `T`             |\n| `decimal(name, precision?, scale?)` | DECIMAL(p,s) | `number`        |\n| `enumCol<T>(name, values)`          | VARCHAR(255) | `T` (union)     |\n\n### Column Modifiers\n\n```typescript\nint(\"id\").primaryKey();       // PRIMARY KEY\nint(\"id\").autoIncrement();    // AUTO_INCREMENT\nvarchar(\"name\").notNull();    // NOT NULL\nvarchar(\"email\").unique();    // UNIQUE\nboolean(\"active\").default(true); // DEFAULT value\n```\n\n### Type Inference\n\nInfer TypeScript types directly from your schema:\n\n```typescript\nimport type { Infer } from \"@aquapha/aq-orm\";\n\ntype User = Infer<typeof users>;\n// { id: number | null; name: string; email: string; active: boolean; createdAt: Date }\n```\n\n## Query Builder\n\n### Select\n\nBasic select — returns all columns:\n\n```typescript\nconst allUsers = await db.select(users).execute();\n```\n\nSelect specific columns:\n\n```typescript\nconst names = await db\n  .select(users)\n  .columns({ id: users.columns.id, name: users.columns.name })\n  .execute();\n```\n\nWhere conditions (multiple `.where()` calls are ANDed):\n\n```typescript\nconst filtered = await db\n  .select(users)\n  .where(eq(users.columns.active, true))\n  .where(gt(users.columns.age, 18))\n  .execute();\n```\n\nDistinct:\n\n```typescript\nconst uniqueNames = await db\n  .select(users)\n  .columns({ name: users.columns.name })\n  .distinct()\n  .execute();\n```\n\nOrder, limit, offset:\n\n```typescript\nconst page = await db\n  .select(users)\n  .orderBy(users.columns.createdAt, \"DESC\")\n  .limit(10)\n  .offset(20)\n  .execute();\n```\n\nJoins:\n\n```typescript\nconst results = await db\n  .select(users)\n  .columns({\n    userName: users.columns.name,\n    postTitle: posts.columns.title,\n  })\n  .innerJoin(posts, eq(users.columns.id, posts.columns.userId))\n  .execute();\n```\n\nTable aliases (useful for self-joins):\n\n```typescript\nconst e = employees.as(\"e\");\nconst m = employees.as(\"m\");\n\nconst withManagers = await db\n  .select(e)\n  .columns({\n    employeeName: e.columns.name,\n    managerName: m.columns.name,\n  })\n  .leftJoin(m, eq(e.columns.managerId, m.columns.id))\n  .execute();\n```\n\nGroup by and having:\n\n```typescript\nconst stats = await db\n  .select(users)\n  .columns({ status: users.columns.status })\n  .groupBy(users.columns.status)\n  .having(gt(count(), 5))\n  .execute();\n```\n\n### Insert\n\n```typescript\n// Single insert\nawait db\n  .insert(users)\n  .values({ name: \"John\", email: \"john@example.com\" })\n  .execute();\n\n// Batch insert\nawait db\n  .insert(users)\n  .values([\n    { name: \"John\", email: \"john@example.com\" },\n    { name: \"Jane\", email: \"jane@example.com\" },\n  ])\n  .execute();\n\n// Upsert (INSERT ON DUPLICATE KEY UPDATE)\nawait db\n  .insert(users)\n  .values({ id: 1, name: \"John\", email: \"john@example.com\" })\n  .onDuplicateKeyUpdate([\"name\", \"email\"])\n  .execute();\n```\n\n### Update\n\n```typescript\nawait db\n  .update(users)\n  .set({ active: false })\n  .where(eq(users.columns.id, 1))\n  .execute();\n```\n\n### Delete\n\n```typescript\nawait db.delete(users).where(eq(users.columns.id, 1)).execute();\n```\n\n## Conditions\n\nAll condition functions are used with `.where()` and `.having()`.\n\n```typescript\nimport { eq, neq, gt, gte, lt, lte, and, or, not, like, inArray, notInArray, isNull, isNotNull, between } from \"@aquapha/aq-orm\";\n```\n\n### Comparison\n\n| Function | SQL          | Example                                    |\n| -------- | ------------ | ------------------------------------------ |\n| `eq`     | `=`          | `eq(col, value)` or `eq(colA, colB)`       |\n| `neq`    | `!=`         | `neq(col, value)`                          |\n| `gt`     | `>`          | `gt(col, value)`                           |\n| `gte`    | `>=`         | `gte(col, value)`                          |\n| `lt`     | `<`          | `lt(col, value)`                           |\n| `lte`    | `<=`         | `lte(col, value)`                          |\n\n```typescript\n// Value comparison\n.where(eq(users.columns.id, 1))\n// WHERE users.id = 1\n\n// Column-to-column comparison\n.where(eq(orders.columns.userId, users.columns.id))\n// WHERE orders.user_id = users.id\n```\n\n### Logical\n\n| Function | SQL   | Description                     |\n| -------- | ----- | ------------------------------- |\n| `and`    | `AND` | All conditions must be true     |\n| `or`     | `OR`  | At least one must be true       |\n| `not`    | `NOT` | Negates a condition             |\n\n```typescript\n.where(and(\n  eq(users.columns.active, true),\n  gte(users.columns.age, 18)\n))\n// WHERE (users.active = 1 AND users.age >= 18)\n\n.where(or(\n  eq(users.columns.role, \"admin\"),\n  eq(users.columns.role, \"moderator\")\n))\n// WHERE (users.role = 'admin' OR users.role = 'moderator')\n\n.where(not(eq(users.columns.status, \"banned\")))\n// WHERE NOT (users.status = 'banned')\n```\n\n### Other\n\n| Function     | SQL             | Example                                    |\n| ------------ | --------------- | ------------------------------------------ |\n| `like`       | `LIKE`          | `like(col, \"John%\")`                       |\n| `inArray`    | `IN`            | `inArray(col, [\"a\", \"b\"])`                 |\n| `notInArray` | `NOT IN`        | `notInArray(col, [\"a\", \"b\"])`              |\n| `isNull`     | `IS NULL`       | `isNull(col)`                              |\n| `isNotNull`  | `IS NOT NULL`   | `isNotNull(col)`                           |\n| `between`    | `BETWEEN`       | `between(col, 10, 100)`                    |\n\n```typescript\n.where(like(users.columns.name, \"John%\"))\n// WHERE users.name LIKE 'John%'\n\n.where(inArray(users.columns.role, [\"admin\", \"moderator\"]))\n// WHERE users.role IN ('admin', 'moderator')\n\n.where(isNull(users.columns.deletedAt))\n// WHERE users.deleted_at IS NULL\n\n.where(between(products.columns.price, 10, 100))\n// WHERE products.price BETWEEN 10 AND 100\n```\n\n## Aggregates\n\n| Function  | SQL        | Example                         |\n| --------- | ---------- | ------------------------------- |\n| `count`   | `COUNT`    | `count()` or `count(col)`       |\n| `sum`     | `SUM`      | `sum(col)`                      |\n| `avg`     | `AVG`      | `avg(col)`                      |\n| `min`     | `MIN`      | `min(col)`                      |\n| `max`     | `MAX`      | `max(col)`                      |\n\n```typescript\nimport { count, sum, avg, min, max } from \"@aquapha/aq-orm\";\n```\n\nBasic aggregation:\n\n```typescript\nconst totals = await db\n  .select(products)\n  .columns({\n    total: count(),\n    lowest: min(products.columns.price),\n    highest: max(products.columns.price),\n  })\n  .execute();\n```\n\nWith GROUP BY, HAVING, and WHERE:\n\n```typescript\nconst revenue = await db\n  .select(orders)\n  .columns({\n    customerId: orders.columns.customerId,\n    totalSpent: sum(orders.columns.amount),\n    orderCount: count(),\n  })\n  .where(eq(orders.columns.status, \"completed\"))\n  .groupBy(orders.columns.customerId)\n  .having(gte(sum(orders.columns.amount), 1000))\n  .orderBy(sum(orders.columns.amount), \"DESC\")\n  .limit(10)\n  .execute();\n```\n\n## SQL Functions\n\n### sqlIf\n\nConditional logic using MySQL's `IF()` function:\n\n```typescript\nimport { sqlIf } from \"@aquapha/aq-orm\";\n\nconst results = await db\n  .select(users)\n  .columns({\n    id: users.columns.id,\n    status: sqlIf<string>(\n      gt(users.columns.balance, 1000),\n      \"premium\",\n      \"standard\"\n    ),\n  })\n  .execute();\n// SELECT users.id, IF(users.balance > 1000, 'premium', 'standard') AS status\n```\n\n### jsonObject\n\nBuild JSON objects from columns and values:\n\n```typescript\nimport { jsonObject } from \"@aquapha/aq-orm\";\n\nconst results = await db\n  .select(users)\n  .columns({\n    userData: jsonObject({\n      name: users.columns.name,\n      email: users.columns.email,\n    }),\n  })\n  .execute();\n// SELECT JSON_OBJECT('name', users.name, 'email', users.email) AS userData\n```\n\n### jsonExtract\n\nExtract values from JSON columns:\n\n```typescript\nimport { jsonExtract } from \"@aquapha/aq-orm\";\n\nconst results = await db\n  .select(posts)\n  .columns({\n    tags: jsonExtract(posts.columns.metadata, \"tags\"),\n  })\n  .execute();\n// SELECT JSON_EXTRACT(posts.metadata, '$.tags') AS tags\n\n// Full JSON path syntax also supported\njsonExtract(posts.columns.metadata, \"$.author.name\");\njsonExtract(posts.columns.metadata, \"$.tags[0]\");\n```\n\n## Transactions\n\n```typescript\nawait db\n  .transaction()\n  .add(db.insert(users).values({ name: \"John\" }))\n  .add(\n    db\n      .update(accounts)\n      .set({ balance: 100 })\n      .where(eq(accounts.columns.userId, 1)),\n  )\n  .execute();\n```\n\n## Raw SQL\n\n```typescript\nimport { sql } from \"@aquapha/aq-orm\";\n\n// Using sql tagged template\nconst userId = 1;\nconst query = sql`SELECT * FROM users WHERE id = ${userId}`;\nawait db.raw(query.sql, query.params);\n\n// Direct raw query\nawait db.raw(\"SELECT * FROM users WHERE id = ?\", [1]);\n```\n\n## Driver\n\n```typescript\nimport { oxmysql } from \"@overextended/oxmysql\";\nimport { Driver } from \"@aquapha/aq-orm\";\n\nconst driver = new Driver(oxmysql);\n\n// Methods\ndriver.execute(sql, params);  // Execute query\ndriver.prepare(sql, params);  // Prepared statement\ndriver.transaction(queries);  // Execute transaction\n```\n\n## License\n\n[MIT](../../LICENSE)\n","readmeFilename":"README.md","_rev":"1-c6ab0d0199ae381ab42b556daec5a853"}