{"_id":"@bwg-labs/drizzle-crud","_rev":"4-3d050a5f5af4a9b49b56269ae63761f0","name":"@bwg-labs/drizzle-crud","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"@bwg-labs/drizzle-crud","version":"0.1.0","keywords":["drizzle","orm","crud","sqlite","turso","typescript","database","pagination","validation","zod"],"author":{"name":"Bruno Garcia"},"license":"MIT","_id":"@bwg-labs/drizzle-crud@0.1.0","maintainers":[{"name":"brunowgarcia","email":"eu@brunowillian.com"}],"homepage":"https://github.com/brunowilliang/drizzle-crud#readme","bugs":{"url":"https://github.com/brunowilliang/drizzle-crud/issues"},"dist":{"shasum":"338b6fba3d37d83125bccc2971cd47535f25fd5d","tarball":"https://registry.npmjs.org/@bwg-labs/drizzle-crud/-/drizzle-crud-0.1.0.tgz","fileCount":53,"integrity":"sha512-zz3wZTSz0J2lpLl+Qm8UK0YcVxPoWzkr+FZgxukwvVit8du0lSK27iQNQmKYYwlvr0/g9MlZ4uqNbNgaOJYVPQ==","signatures":[{"sig":"MEQCIFoy7O4nPIvVVUtQt2mPzFAOuKAcd9+a5Pt2Y0sLiyk/AiBXX6yqxkRvENKxGHsMnRqxmQhItjx6EKECC4RKHq/Xkw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":113261},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"sjs":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"sjs":"./src/zod.ts","types":"./dist/zod.d.ts","import":"./dist/zod.js"}},"gitHead":"cdf7c02a7b29da9054df5d3752869da683e4705b","scripts":{"test":"bun test","build":"tsc --project tsconfig.json","db:pull":"drizzle-kit pull --config=exemples/drizzle.config.ts","db:push":"drizzle-kit push --config=exemples/drizzle.config.ts","db:studio":"drizzle-kit studio --config=exemples/drizzle.config.ts","db:migrate":"drizzle-kit migrate --config=exemples/drizzle.config.ts","test:watch":"bun test --watch","db:generate":"drizzle-kit generate --config=exemples/drizzle.config.ts"},"_npmUser":{"name":"brunowgarcia","email":"eu@brunowillian.com"},"repository":{"url":"git+https://github.com/brunowilliang/drizzle-crud.git","type":"git"},"_npmVersion":"10.8.2","description":"A TypeScript library that creates automated CRUD operations over Drizzle ORM, specifically for SQLite/Turso","directories":{},"_nodeVersion":"20.19.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^4.1.5","@types/bun":"latest","typescript":"^5.7.3","drizzle-orm":"^0.44.2","drizzle-zod":"^0.8.2","@biomejs/biome":"^2.2.2","@libsql/client":"^0.15.14"},"peerDependencies":{"zod":"^4.1.5","drizzle-orm":"^0.44.2","drizzle-zod":"^0.8.2"},"_npmOperationalInternal":{"tmp":"tmp/drizzle-crud_0.1.0_1756783612372_0.1349334406151046","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@bwg-labs/drizzle-crud","version":"0.1.1","keywords":["drizzle","orm","crud","sqlite","turso","typescript","database","pagination","validation","zod"],"author":{"name":"Bruno Garcia"},"license":"MIT","_id":"@bwg-labs/drizzle-crud@0.1.1","maintainers":[{"name":"brunowgarcia","email":"eu@brunowillian.com"}],"homepage":"https://github.com/brunowilliang/drizzle-crud#readme","bugs":{"url":"https://github.com/brunowilliang/drizzle-crud/issues"},"dist":{"shasum":"f0c3de418ae8431ab8a2269c249793ade5f841f0","tarball":"https://registry.npmjs.org/@bwg-labs/drizzle-crud/-/drizzle-crud-0.1.1.tgz","fileCount":53,"integrity":"sha512-b0CJlUgG5/zEEgoVKWUVq9esL+5clkDmkejTb7UnikBWO3eREUOnLuASBxJOvzexl+bV4PB246EFlvBDgpqQ2A==","signatures":[{"sig":"MEYCIQCRXeyrja/UgjkJOEWB+ilJv+KF9MmzDDZp3xZe2CLffgIhAIKIz/E8Htqh9Le1M2iLkyHS0EBwvqdICv624UvE28CK","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":116216},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"sjs":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"sjs":"./src/zod.ts","types":"./dist/zod.d.ts","import":"./dist/zod.js"}},"gitHead":"8521559c1def480b3a758512d7763fa63532a6ce","scripts":{"test":"bun test","build":"tsc --project tsconfig.json","db:pull":"drizzle-kit pull --config=exemples/drizzle.config.ts","db:push":"drizzle-kit push --config=exemples/drizzle.config.ts","db:studio":"drizzle-kit studio --config=exemples/drizzle.config.ts","db:migrate":"drizzle-kit migrate --config=exemples/drizzle.config.ts","test:watch":"bun test --watch","db:generate":"drizzle-kit generate --config=exemples/drizzle.config.ts"},"_npmUser":{"name":"brunowgarcia","email":"eu@brunowillian.com"},"repository":{"url":"git+https://github.com/brunowilliang/drizzle-crud.git","type":"git"},"_npmVersion":"10.8.2","description":"A TypeScript library that creates automated CRUD operations over Drizzle ORM, specifically for SQLite/Turso","directories":{},"_nodeVersion":"20.19.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^4.1.5","@types/bun":"latest","typescript":"^5.7.3","drizzle-orm":"^0.44.2","drizzle-zod":"^0.8.2","@biomejs/biome":"^2.2.2","@libsql/client":"^0.15.14"},"peerDependencies":{"zod":"^4.1.5","drizzle-orm":"^0.44.2","drizzle-zod":"^0.8.2"},"_npmOperationalInternal":{"tmp":"tmp/drizzle-crud_0.1.1_1757612200613_0.5390962173618579","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bwg-labs/drizzle-crud","version":"0.2.0","keywords":["drizzle","orm","crud","sqlite","turso","typescript","database","pagination","validation","zod"],"author":{"name":"Bruno Garcia"},"license":"MIT","_id":"@bwg-labs/drizzle-crud@0.2.0","maintainers":[{"name":"brunowgarcia","email":"eu@brunowillian.com"}],"homepage":"https://github.com/brunowilliang/drizzle-crud#readme","bugs":{"url":"https://github.com/brunowilliang/drizzle-crud/issues"},"dist":{"shasum":"5dc08be2540f895f0d270af84d724698008a1e24","tarball":"https://registry.npmjs.org/@bwg-labs/drizzle-crud/-/drizzle-crud-0.2.0.tgz","fileCount":53,"integrity":"sha512-GGE2XS/hFmPZg5hOkx9r3RDcVluJEE4efEHDPljJk0BkBrp48cSyLaR1oLyOPMYdrpQU6V6JmedwZWnhX3WLyw==","signatures":[{"sig":"MEYCIQCo0ec72hs0rnQyP2wgq6LH+zrU2EkY7HZfr4kOsovAAwIhAN4hvCidic3eUy3gwbL58SpSMl8V24aokYUtD9WCAPZ+","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":116446},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"sjs":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"sjs":"./src/zod.ts","types":"./dist/zod.d.ts","import":"./dist/zod.js"}},"gitHead":"cee5bda6d1085c8ef4d723458f4c6f98495b5c4b","scripts":{"test":"bun test","build":"tsc --project tsconfig.json","db:pull":"drizzle-kit pull --config=exemples/drizzle.config.ts","db:push":"drizzle-kit push --config=exemples/drizzle.config.ts","db:studio":"drizzle-kit studio --config=exemples/drizzle.config.ts","db:migrate":"drizzle-kit migrate --config=exemples/drizzle.config.ts","test:watch":"bun test --watch","db:generate":"drizzle-kit generate --config=exemples/drizzle.config.ts"},"_npmUser":{"name":"brunowgarcia","email":"eu@brunowillian.com"},"repository":{"url":"git+https://github.com/brunowilliang/drizzle-crud.git","type":"git"},"_npmVersion":"10.8.2","description":"A TypeScript library that creates automated CRUD operations over Drizzle ORM, specifically for SQLite/Turso","directories":{},"_nodeVersion":"20.19.4","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"zod":"^4.1.5","@types/bun":"latest","typescript":"^5.7.3","drizzle-orm":"^0.44.2","drizzle-zod":"^0.8.2","@biomejs/biome":"^2.2.2","@libsql/client":"^0.15.14"},"peerDependencies":{"zod":"^4.1.5","drizzle-orm":"^0.44.2","drizzle-zod":"^0.8.2"},"_npmOperationalInternal":{"tmp":"tmp/drizzle-crud_0.2.0_1757612794202_0.5035748255035566","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@bwg-labs/drizzle-crud","version":"0.2.1","description":"A TypeScript library that creates automated CRUD operations over Drizzle ORM, specifically for SQLite/Turso","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","keywords":["drizzle","orm","crud","sqlite","turso","typescript","database","pagination","validation","zod"],"author":{"name":"Bruno Garcia"},"license":"MIT","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/brunowilliang/drizzle-crud.git"},"homepage":"https://github.com/brunowilliang/drizzle-crud#readme","bugs":{"url":"https://github.com/brunowilliang/drizzle-crud/issues"},"scripts":{"build":"tsc --project tsconfig.json","test":"bun test","test:watch":"bun test --watch","db:push":"drizzle-kit push --config=exemples/drizzle.config.ts","db:pull":"drizzle-kit pull --config=exemples/drizzle.config.ts","db:studio":"drizzle-kit studio --config=exemples/drizzle.config.ts","db:generate":"drizzle-kit generate --config=exemples/drizzle.config.ts","db:migrate":"drizzle-kit migrate --config=exemples/drizzle.config.ts"},"exports":{".":{"sjs":"./src/index.ts","types":"./dist/index.d.ts","import":"./dist/index.js"},"./zod":{"sjs":"./src/zod.ts","types":"./dist/zod.d.ts","import":"./dist/zod.js"}},"peerDependencies":{"drizzle-orm":"^0.44.2","drizzle-zod":"^0.8.2","zod":"^4.1.5"},"devDependencies":{"@biomejs/biome":"^2.2.2","@libsql/client":"^0.15.14","@types/bun":"latest","drizzle-orm":"^0.44.2","drizzle-zod":"^0.8.2","typescript":"^5.7.3","zod":"^4.1.5"},"_id":"@bwg-labs/drizzle-crud@0.2.1","gitHead":"d7b53e7e39c2a4e0d2033f338cc95f82c60298e4","_nodeVersion":"20.19.4","_npmVersion":"10.8.2","dist":{"integrity":"sha512-5vQHp+9zUeNoJEq7EqBeQIaM5jtFqVK+ouo5VGzGz6XLjtrd3OoVhJCIALaE87aVMdIaTGmWmuZcgAJX1m8rRw==","shasum":"f74ee0dd8ac431503b249ef562bb32e25bc47a94","tarball":"https://registry.npmjs.org/@bwg-labs/drizzle-crud/-/drizzle-crud-0.2.1.tgz","fileCount":53,"unpackedSize":119022,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIH+66/OqpexKrml1Qgcn9sQRMD92ttR8aOWyrxIA+DEGAiEAj0NkaardUdu8h5F019OOLDeecwQJFw4+UtNTp/V6fkQ="}]},"_npmUser":{"name":"brunowgarcia","email":"eu@brunowillian.com"},"directories":{},"maintainers":[{"name":"brunowgarcia","email":"eu@brunowillian.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/drizzle-crud_0.2.1_1757618980308_0.2071815248974107"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-02T03:26:52.294Z","modified":"2025-09-11T19:29:40.687Z","0.1.0":"2025-09-02T03:26:52.539Z","0.1.1":"2025-09-11T17:36:40.857Z","0.2.0":"2025-09-11T17:46:34.388Z","0.2.1":"2025-09-11T19:29:40.499Z"},"bugs":{"url":"https://github.com/brunowilliang/drizzle-crud/issues"},"author":{"name":"Bruno Garcia"},"license":"MIT","homepage":"https://github.com/brunowilliang/drizzle-crud#readme","keywords":["drizzle","orm","crud","sqlite","turso","typescript","database","pagination","validation","zod"],"repository":{"type":"git","url":"git+https://github.com/brunowilliang/drizzle-crud.git"},"description":"A TypeScript library that creates automated CRUD operations over Drizzle ORM, specifically for SQLite/Turso","maintainers":[{"name":"brunowgarcia","email":"eu@brunowillian.com"}],"readme":"# Drizzle CRUD Factory\n\nA TypeScript library that creates automated CRUD operations over Drizzle ORM,\nspecifically for SQLite/Turso.\n\n## What is it?\n\nDrizzle CRUD Factory is an abstraction layer that automatically generates\ncomplete CRUD (Create, Read, Update, Delete) operations from your Drizzle\ntables. It adds essential features like:\n\n- ✅ **Complete CRUD operations** with TypeScript typing\n- 🔍 **Advanced search and filters**\n- 📄 **Automatic pagination**\n- ♻️ **Soft delete** (logical deletion)\n- ✅ **Validation** with Zod\n- 🪝 **Hooks** for customization\n- 🔐 **Multi-tenancy** with scope filters\n- 📦 **Bulk operations**\n\n## How it works?\n\n### 1. Define your Drizzle table\n\n```typescript\nimport { integer, sqliteTable, text } from \"drizzle-orm/sqlite-core\";\n\nexport const users = sqliteTable(\"users\", {\n  id: integer(\"id\").primaryKey({ autoIncrement: true }),\n  email: text(\"email\").notNull().unique(),\n  name: text(\"name\").notNull(),\n  role: text(\"role\", { enum: [\"admin\", \"user\"] }).notNull().default(\"user\"),\n  deletedAt: integer(\"deleted_at\", { mode: \"timestamp\" }),\n  createdAt: integer(\"created_at\", { mode: \"timestamp\" })\n    .notNull()\n    .default(sql`(unixepoch())`),\n});\n```\n\n### 2. Create the CRUD\n\n```typescript\nimport { drizzleCrud } from \"drizzle-crud\";\nimport { zod } from \"drizzle-crud/zod\";\n\n// Create the factory\nconst crud = drizzleCrud(db, { validation: zod() });\n\n// Generate CRUD for users table\nconst usersCrud = crud(users, {\n  searchFields: [\"name\", \"email\"], // Searchable fields\n  allowedFilters: [\"role\"], // Allowed filters\n  softDelete: { // Soft delete configuration\n    field: \"deletedAt\",\n    deletedValue: new Date(),\n    notDeletedValue: null,\n  },\n});\n```\n\n### 3. Use the generated operations\n\n```typescript\n// Create\nconst user = await usersCrud.create({\n  email: \"bruno@example.com\",\n  name: \"Bruno Garcia\",\n  role: \"admin\",\n});\n\n// Find by any field\nconst user = await usersCrud.findOne({ email: \"bruno@example.com\" });\n\n// List with pagination and filters\nconst result = await usersCrud.list({\n  page: 1,\n  perPage: 20,\n  search: \"bruno\",\n  filters: { role: \"admin\" },\n});\n\n// Filter using IN operator (e.g., countries)\nconst countries = [\"PT\", \"BR\", \"ES\"];\nconst usersFromCountries = await usersCrud.list({\n  filters: {\n    country: { in: countries }, // Get users from Portugal, Brazil or Spain\n  },\n});\n\n// Filter using NOT IN operator\nconst usersNotFromCountries = await usersCrud.list({\n  filters: {\n    country: { notIn: countries }, // Exclude users from these countries\n  },\n});\n\n// Update\nawait usersCrud.update(user.id, { name: \"Bruno G.\" });\n\n// Delete (soft delete)\nawait usersCrud.deleteOne(user.id);\n\n// Restore\nawait usersCrud.restore(user.id);\n```\n\n## Available methods\n\n### Basic operations\n\n- `create(data)` - Creates a record\n- `findOne(conditions)` - Finds a record by any field\n- `list(params)` - Lists with pagination, search and filters\n- `update(id, data)` - Updates a record\n- `deleteOne(id)` - Deletes a record (soft or hard delete)\n- `restore(id)` - Restores a deleted record\n- `permanentDelete(id)` - Permanently deletes\n\n### Bulk operations\n\n- `bulkCreate(items)` - Creates multiple records\n- `bulkDelete(ids)` - Deletes multiple records\n- `bulkRestore(ids)` - Restores multiple records\n\n## Advanced features\n\n### Complex filters\n\n```typescript\n// Comparison operators\nconst result = await usersCrud.list({\n  filters: {\n    age: { gt: 18, lte: 65 }, // greater than 18, less or equal to 65\n    status: { not: \"suspended\" }, // NOT equal\n    email: { like: \"%@company.com\" }, // LIKE pattern matching\n    createdAt: { gte: new Date(\"2024-01-01\") }, // Date comparisons\n  },\n});\n\n// IN and NOT IN operators\nconst result = await usersCrud.list({\n  filters: {\n    // Get users with specific roles\n    role: { in: [\"admin\", \"editor\"] }, // role IN ('admin', 'editor')\n\n    // Exclude users from specific countries\n    country: { notIn: [\"PT\", \"BR\", \"ES\"] }, // country NOT IN ('PT', 'BR', 'ES')\n  },\n});\n\n// Practical example: filtering by countries\nconst targetCountries = [\"PT\", \"BR\", \"ES\"];\n\n// Get users FROM these countries\nconst usersFromCountries = await usersCrud.list({\n  filters: {\n    country: { in: targetCountries },\n  },\n});\n\n// Get users NOT FROM these countries\nconst usersNotFromCountries = await usersCrud.list({\n  filters: {\n    country: { notIn: targetCountries },\n  },\n});\n\n// AND/OR logic\nconst result = await usersCrud.list({\n  filters: {\n    OR: [\n      { role: \"admin\" },\n      { department: \"IT\" },\n    ],\n  },\n});\n\n// Complex filters combining multiple operators\nconst result = await usersCrud.list({\n  filters: {\n    // All conditions must match (AND)\n    status: \"active\",\n    role: { in: [\"admin\", \"editor\"] },\n    country: { notIn: [\"US\", \"CA\"] },\n    age: { gte: 18, lt: 65 },\n\n    // OR conditions\n    OR: [\n      { department: \"IT\" },\n      { department: \"Engineering\" },\n    ],\n  },\n});\n```\n\n#### Available Filter Operators\n\n| Operator  | Description                                   | Example                                                      |\n| --------- | --------------------------------------------- | ------------------------------------------------------------ |\n| `equals`  | Equal to (default)                            | `{ status: \"active\" }` or `{ status: { equals: \"active\" } }` |\n| `not`     | Not equal to                                  | `{ status: { not: \"suspended\" } }`                           |\n| `gt`      | Greater than                                  | `{ age: { gt: 18 } }`                                        |\n| `gte`     | Greater than or equal                         | `{ age: { gte: 18 } }`                                       |\n| `lt`      | Less than                                     | `{ age: { lt: 65 } }`                                        |\n| `lte`     | Less than or equal                            | `{ age: { lte: 65 } }`                                       |\n| `in`      | Value in array ⚠️                             | `{ role: { in: [\"admin\", \"editor\"] } }`                      |\n| `notIn`   | Value not in array ⚠️                         | `{ country: { notIn: [\"PT\", \"BR\", \"ES\"] } }`                 |\n| `like`    | Pattern matching (case insensitive in SQLite) | `{ email: { like: \"%@company.com\" } }`                       |\n| `ilike`   | Pattern matching (not supported in SQLite)    | `{ name: { ilike: \"%garcia%\" } }`                            |\n| `notLike` | Exclude pattern                               | `{ name: { notLike: \"%admin%\" } }`                           |\n\n⚠️ **Note**: `in` and `notIn` operators only work with scalar string fields, not\nJSON arrays.\n\n#### Working with JSON Array Fields\n\nWhen filtering JSON array fields in SQLite, use `like`/`notLike` operators with\nquoted values:\n\n```typescript\n// Find users with \"BR\" in their countries array\nconst brazilUsers = await usersCrud.list({\n  filters: {\n    countries: { like: '%\"BR\"%' },\n  },\n});\n\n// Exclude users with \"PT\" in their countries array\nconst nonPortugueseUsers = await usersCrud.list({\n  filters: {\n    countries: { notLike: '%\"PT\"%' },\n  },\n});\n```\n\n**Important limitations**:\n\n- `notLike` also excludes NULL values\n- Direct NULL filters may not work with JSON fields\n- `in`/`notIn` do not search within JSON arrays\n\n### Hooks\n\n```typescript\nconst usersCrud = crud(users, {\n  hooks: {\n    // Before creating\n    beforeCreate: (data) => ({\n      ...data,\n      email: data.email.toLowerCase(),\n    }),\n\n    // Before updating\n    beforeUpdate: (data) => {\n      const { password, ...safe } = data;\n      return safe; // Remove password from updates\n    },\n\n    // Custom validation\n    validate: ({ operation, data, context }) => {\n      if (context.actor?.role === \"admin\") {\n        return false; // Admin skips validation\n      }\n      return true;\n    },\n  },\n});\n```\n\n### Multi-tenancy with Scope Filters\n\n```typescript\nconst projectsCrud = crud(projects, {\n  scopeFilters: {\n    // Filter by tenant automatically\n    tenantId: (value, actor) => {\n      return eq(projects.tenantId, actor.properties.tenantId);\n    },\n  },\n});\n\n// All operations will be filtered by tenant\nconst projects = await projectsCrud.list({}, {\n  actor: {\n    type: \"user\",\n    properties: { tenantId: 123 },\n  },\n});\n```\n\n### Pagination response\n\n```typescript\nconst result = await usersCrud.list({ page: 2, perPage: 20 });\n\n// Returns:\n{\n  results: User[],         // Data\n  page: 2,                // Current page\n  perPage: 20,            // Items per page\n  totalItems: 156,        // Total records\n  totalPages: 8,          // Total pages\n  hasNextPage: true,      // Has next page\n  hasPreviousPage: true,  // Has previous page\n}\n```\n\n## Validation\n\nThe library integrates with Zod for automatic validation based on schema:\n\n```typescript\nimport { z } from \"zod\";\n\n// Custom validation\nconst customValidation = {\n  ...zod(),\n  createInsertSchema: () =>\n    z.object({\n      email: z.email().transform((v) => v.toLowerCase()),\n      name: z.string().min(2).max(50),\n      password: z.string().min(8),\n    }),\n};\n\nconst crud = drizzleCrud(db, { validation: customValidation });\n```\n\n## Context and Security\n\nPass context to any operation:\n\n```typescript\n// Authenticated user context\nconst context = {\n  actor: {\n    type: \"user\",\n    properties: {\n      id: 123,\n      role: \"admin\",\n      tenantId: 456,\n    },\n  },\n  skipValidation: true, // Skip validation if needed\n};\n\n// Use context in any operation\nawait usersCrud.create(data, context);\nawait usersCrud.list({}, context);\n```\n\n## TypeScript\n\nThe library is 100% typed and automatically infers types:\n\n```typescript\n// Types inferred from Drizzle schema\nconst user = await usersCrud.create({\n  email: \"test@example.com\",\n  name: \"Test\",\n  role: \"admin\", // ✅ Validated against enum\n  // role: \"super\", // ❌ Type error\n});\n\n// user is fully typed\nconsole.log(user.id, user.email); // ✅ Autocomplete works\n```\n\n## Installation\n\n```bash\nnpm install drizzle-crud\n# or\nbun add drizzle-crud\n```\n\n## Dependencies\n\n- `drizzle-orm` - Base ORM\n- `@libsql/client` - SQLite/Turso client\n- `zod` (optional) - For validation\n\n## Why use it?\n\n1. **Reduces boilerplate**: Automatically generates all CRUD operations\n2. **Type-safe**: 100% typed with TypeScript\n3. **Flexible**: Hooks and configurations to customize behavior\n4. **Complete**: Pagination, search, filters, soft delete, everything included\n5. **Multi-tenant ready**: Native support for data isolation\n6. **Integrated validation**: With Zod or your own validator\n7. **Performance**: Optimized queries for SQLite\n\n## Common Issues & Solutions\n\n### Filtering JSON Arrays in SQLite\n\nSQLite stores JSON arrays as strings, so standard `in`/`notIn` operators don't\nwork for searching within arrays. Use `like`/`notLike` instead:\n\n```typescript\n// ❌ WRONG - This won't work\n{ countries: { in: ['BR'] } }\n\n// ✅ CORRECT - Use like with quotes\n{ countries: { like: '%\"BR\"%' } }\n{ countries: { notLike: '%\"PT\"%' } }\n```\n\n### Case Sensitivity\n\n- SQLite's `LIKE` is case-insensitive by default\n- `ILIKE` is not supported in SQLite\n\n### NULL Handling with JSON\n\n- `notLike` excludes NULL values\n- Direct NULL filters (`{ field: null }`) may not work with JSON fields\n\n## License\n\nMIT\n","readmeFilename":"README.md"}