{"id":47699219,"url":"https://github.com/chronicstone/drizzle-resource","last_synced_at":"2026-04-03T19:00:59.151Z","repository":{"id":347457255,"uuid":"1194117670","full_name":"ChronicStone/drizzle-resource","owner":"ChronicStone","description":null,"archived":false,"fork":false,"pushed_at":"2026-03-30T15:58:13.000Z","size":2248,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-03T03:29:40.381Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://drizzle-resource.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChronicStone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-28T00:05:38.000Z","updated_at":"2026-04-01T19:12:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"bb7908ff-8924-4b56-8923-422265cfb16d","html_url":"https://github.com/ChronicStone/drizzle-resource","commit_stats":null,"previous_names":["chronicstone/drizzle-resource"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ChronicStone/drizzle-resource","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChronicStone%2Fdrizzle-resource","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChronicStone%2Fdrizzle-resource/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChronicStone%2Fdrizzle-resource/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChronicStone%2Fdrizzle-resource/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChronicStone","download_url":"https://codeload.github.com/ChronicStone/drizzle-resource/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChronicStone%2Fdrizzle-resource/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31371633,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T17:53:18.093Z","status":"ssl_error","status_checked_at":"2026-04-03T17:53:17.617Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":[],"created_at":"2026-04-02T17:01:38.791Z","updated_at":"2026-04-03T19:00:59.101Z","avatar_url":"https://github.com/ChronicStone.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# drizzle-resource\n\n**Schema-driven query resources for [Drizzle ORM](https://orm.drizzle.team).** One typed contract for filtering, sorting, search, pagination, hydration, and facets — define it once, query it consistently across every table endpoint.\n\nInstead of reimplementing sort params, WHERE builders, count queries, and filter sidebars for each endpoint, you declare a resource and get a stable, typed API that handles the entire query pipeline.\n\n## Features\n\n- **🔒 Type-safe field paths** — sort keys, filter fields, search fields, and facet paths are all inferred from your Drizzle schema and declared relations. Typos fail at compile time.\n- **🔍 Filter trees** — AND/OR nested conditions with 11 operators (`is`, `isAnyOf`, `contains`, `between`, `before`, `after`, …)\n- **📄 Pagination** — 1-based page + size with configurable defaults\n- **↕️ Sorting** — multi-column, default sort, per-resource disabled paths\n- **🔎 Free-text search** — ILIKE across configurable field paths, with separate `allowed` and `defaults` lists\n- **🗂️ Facets** — bucket counts for filter sidebars, traveling in the same request as the main query\n- **🛡️ Scope enforcement** — tenant constraints and auth filters that merge into every request and cannot be bypassed\n- **⚙️ Staged pipeline** — ids → rows → facets, each stage replaceable independently via `strategy.*`\n- **🚀 Performance tuning** — built-in SQL helpers for custom `strategy.ids` when you need a hand-tuned query\n\n## Install\n\n```sh\nnpm install drizzle-resource    # npm\npnpm add drizzle-resource       # pnpm\nbun add drizzle-resource        # bun\n```\n\nRequires `drizzle-orm \u003e= 1.0.0-beta` as a peer dependency.\n\n## Quick start\n\n```ts\nimport { createQueryEngine } from \"drizzle-resource\";\nimport { db, schema, relations } from \"./db\";\n\n// 1. Create the engine — once, shared across all resources\nconst engine = createQueryEngine({ db, schema, relations }).withContext\u003c{ orgId: string }\u003e();\n\n// 2. Define a resource\nexport const ordersResource = engine.defineResource(\"orders\", {\n  relations: {\n    customer: true,\n    orderLines: { with: { product: true } },\n  },\n  query: {\n    // Scope merges into every request — client cannot bypass it\n    scope: (f, ctx) =\u003e f.is(\"customer.orgId\", ctx.orgId),\n    search: {\n      allowed: [\"reference\", \"customer.name\", \"orderLines.product.name\"],\n      defaults: [\"reference\", \"customer.name\"],\n    },\n    sort: {\n      defaults: [{ key: \"createdAt\", dir: \"desc\" }],\n      disabled: [\"orderLines.product.name\"], // m2m sort paths — disable until benchmarked\n    },\n    facets: {\n      allowed: [\"status\", \"customer.name\"],\n    },\n    defaults: {\n      pagination: { pageSize: 25 },\n    },\n  },\n});\n\n// 3. Query it\nconst result = await ordersResource.query({\n  context: { orgId: \"acme\" },\n  request: {\n    pagination: { pageIndex: 1, pageSize: 25 },\n    sorting: [{ key: \"createdAt\", dir: \"desc\" }],\n    search: { value: \"laptop\", fields: [] },\n    filters: [\n      { type: \"condition\", key: \"status\", operator: \"isAnyOf\", value: [\"pending\", \"processing\"] },\n    ],\n    facets: [{ key: \"status\", mode: \"exclude-self\", limit: 10 }],\n  },\n});\n\n// result.rows     — typed hydrated rows\n// result.rowCount — total matching rows before pagination\n// result.facets   — bucket counts per requested facet\n```\n\n## Four query methods\n\n| Method                      | Use when                                     |\n| --------------------------- | -------------------------------------------- |\n| `resource.query(...)`       | Full pipeline — ids + rows + optional facets |\n| `resource.queryIds(...)`    | Page ids + count only (caching, batching)    |\n| `resource.queryRows(...)`   | Hydrate a known id list without re-selecting |\n| `resource.queryFacets(...)` | Facets independently from the page           |\n\n## Documentation\n\nFull docs, benchmark results, and performance guide at **[drizzle-resource.vercel.app](https://drizzle-resource.vercel.app)**.\n\n## Quality checks\n\n```sh\nbun run format\nbun run lint\nbun run typecheck\nbun run test\nbun run build\nbun run ci\n```\n\n`bun run ci` runs the package checks plus Twoslash verification for the docs.\n\n## Release workflow\n\nThis repository now uses Changesets for versioning and changelog generation.\n\n```sh\n# add a release note\nbun run changeset\n\n# inspect pending releases\nbun run release:status\n```\n\nOn GitHub, `.github/workflows/release.yml` creates or updates a release PR from pending changesets. Once that PR is merged into `main`, the workflow publishes to npm and generates GitHub releases.\n\nTo keep npm provenance enabled, configure npm trusted publishing for this repository/workflow in npm settings.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchronicstone%2Fdrizzle-resource","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchronicstone%2Fdrizzle-resource","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchronicstone%2Fdrizzle-resource/lists"}