@hono-crud/drizzle 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/dist/index.js +2 -2
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# @hono-crud/drizzle
|
|
2
2
|
|
|
3
|
+
## 0.1.16
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 29f12a3: fix(security): scope aggregate/search/export/bulk-patch verbs to the caller's tenant
|
|
8
|
+
|
|
9
|
+
`GET /resource/aggregate`, `GET /resource/search`, `GET /resource/export`, and
|
|
10
|
+
`PATCH /resource/bulk` built their WHERE clause from the parsed request filters
|
|
11
|
+
**without** applying the model's `multiTenant` owner filter. Only `ListEndpoint`
|
|
12
|
+
re-applied the tenant scope in its handler; these four verbs did not (and
|
|
13
|
+
`ExportEndpoint` overrides `ListEndpoint.handle`, so it didn't inherit it). A
|
|
14
|
+
caller could therefore aggregate, search, export, or bulk-patch across **every
|
|
15
|
+
tenant's rows**, regardless of `Model.multiTenant`.
|
|
16
|
+
|
|
17
|
+
Owner-scoping is now centralized in a single auditable core helper,
|
|
18
|
+
`applyTenantScope` (plus `applyTenantScopeToAggregateFilters` for the aggregate
|
|
19
|
+
`Record`-shaped WHERE), which `ListEndpoint` and all four verbs call after
|
|
20
|
+
parsing filters and before running the query. Each verb now enforces tenant
|
|
21
|
+
presence (`validateTenantId`, 400 `TENANT_REQUIRED` when required) and ANDs the
|
|
22
|
+
owner equality into the adapter WHERE — so a tenant's aggregate counts, search
|
|
23
|
+
hits, export rows, and bulk-patch matches are confined to its own rows.
|
|
24
|
+
|
|
25
|
+
A second leak on the same verbs is also closed: `search` and `export` loaded
|
|
26
|
+
`?include=` relations WITHOUT the owner `scope` that `list`/`read` pass, so an
|
|
27
|
+
embedded related row could cross tenants even when the parent rows were scoped.
|
|
28
|
+
All three adapters (drizzle, memory, prisma) now thread `getRelationScope(...)`
|
|
29
|
+
into the search/export relation loader, matching List.
|
|
30
|
+
|
|
31
|
+
Covered by a new cross-adapter conformance cell (`extended-verb-tenant-scoping`)
|
|
32
|
+
asserting per-tenant aggregate counts (incl. a grouped aggregation), search /
|
|
33
|
+
export / bulk-patch isolation, the `TENANT_REQUIRED` contract, AND that
|
|
34
|
+
`?include=` on search/export never embeds another tenant's related row — across
|
|
35
|
+
the memory and drizzle legs.
|
|
36
|
+
|
|
37
|
+
## 0.1.15
|
|
38
|
+
|
|
39
|
+
### Patch Changes
|
|
40
|
+
|
|
41
|
+
- 26a6ecf: fix(security): scope batch verbs to the caller's tenant
|
|
42
|
+
|
|
43
|
+
`batchDelete`, `batchUpdate`, and `batchRestore` operated on a client-supplied
|
|
44
|
+
id list without applying the model's `multiTenant` owner filter — unlike the
|
|
45
|
+
single-row verbs, which get it via core-injected `additionalFilters`. A caller
|
|
46
|
+
could delete, update, or restore **another tenant's rows** by passing their ids.
|
|
47
|
+
|
|
48
|
+
Core now enforces tenant presence in each batch handler (`validateTenantId`,
|
|
49
|
+
400 `TENANT_REQUIRED` when required), and exposes `getTenantScopeFilter()` which
|
|
50
|
+
each adapter ANDs into its batch WHERE (drizzle/memory) or `findMany` lookup
|
|
51
|
+
(prisma). Cross-tenant ids now fall through to `notFound`; the row is untouched.
|
|
52
|
+
|
|
53
|
+
Covered by a new cross-adapter conformance cell (`batch-tenant-scoping`).
|
|
54
|
+
|
|
3
55
|
## 0.1.14
|
|
4
56
|
|
|
5
57
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {getTableColumns,between,isNull,isNotNull,notInArray,inArray,lte,lt,gte,gt,ne
|
|
1
|
+
import {getTableColumns,between,isNull,isNotNull,notInArray,inArray,lte,lt,gte,gt,ne,eq,sql,and,desc,asc,or}from'drizzle-orm';import {resolveRelationValueAsync,loadRelationsForItem,batchLoadRelations,assertNever,CreateEndpoint,getLogger,ReadEndpoint,UpdateEndpoint,DeleteEndpoint,ListEndpoint,buildCursorPage,RestoreEndpoint,BatchCreateEndpoint,BatchUpdateEndpoint,BatchDeleteEndpoint,BatchRestoreEndpoint,UpsertEndpoint,BatchUpsertEndpoint,BulkPatchEndpoint,VersionHistoryEndpoint,VersionReadEndpoint,VersionCompareEndpoint,VersionRollbackEndpoint,AggregateEndpoint,isFilterOperator,computeAggregations,SearchEndpoint,searchInMemory,ExportEndpoint,ImportEndpoint,CloneEndpoint,CONTEXT_KEYS,ConfigurationException,decodeCursor}from'hono-crud/internal';import {z as z$1}from'zod';function G(o){return o}function g(...o){return and(...o)}function J(...o){return or(...o)}var Ke=["sqlite","pg","mysql"];function z(o){if(!o.model.table)throw new Error(`Model ${o.model.tableName} does not have a table reference`);return o.model.table}function p(o,e){let n=getTableColumns(o),t=n[e];if(!t)throw new Error(`Column '${e}' not found in table. Available columns: ${Object.keys(n).join(", ")}`);return t}function he(o){return {resolveRelation:e=>e.table??null,fetchRelated:(e,n,t,r)=>{let i=[inArray(p(e,n),t)];return r?.tenantField!=null&&r.tenantValue!=null&&i.push(eq(p(e,r.tenantField),r.tenantValue)),r?.excludeDeletedField!=null&&i.push(isNull(p(e,r.excludeDeletedField))),o.select().from(e).where(i.length===1?i[0]:and(...i))}}}async function Qe(o,e,n,t){let r=t.table;if(!r)return e;let i=he(o),s=await resolveRelationValueAsync(e,t,r,i.fetchRelated);return {...e,[n]:s}}async function fe(o,e,n,t){return loadRelationsForItem(e,n,he(o),t)}async function v(o,e,n,t){return batchLoadRelations(e,n,he(o),t)}function W(o,e,n="sqlite"){let t=p(o,e.field);switch(e.operator){case "eq":return eq(t,e.value);case "ne":return ne(t,e.value);case "gt":return gt(t,e.value);case "gte":return gte(t,e.value);case "lt":return lt(t,e.value);case "lte":return lte(t,e.value);case "in":return inArray(t,e.value);case "nin":return notInArray(t,e.value);case "like":return B(t,String(e.value).replace(/%/g,""),n,{caseSensitive:true});case "ilike":return B(t,String(e.value).replace(/%/g,""),n);case "null":return e.value?isNull(t):isNotNull(t);case "between":{let[r,i]=e.value;return between(t,r,i)}default:return assertNever(e.operator)}}function S(o){return Number(o[0]?.count)||0}async function V(o){let{db:e,table:n,filters:t,dialect:r,searchFields:i=[],softDeleteConfig:s,defaultPerPage:a=20,extraConditions:l=[],cursorField:c}=o,u=[];if(s?.enabled){let y=p(n,s.field);t.options.onlyDeleted?u.push(isNotNull(y)):t.options.withDeleted||u.push(isNull(y));}for(let y of t.filters){let k=W(n,y,r);k&&u.push(k);}if(t.options.search&&i.length>0){let y=t.options.search,k=i.map(Oe=>B(p(n,Oe),y,r));u.push(J(...k));}u.push(...l);let d=u.length>0?g(...u):void 0,D=await e.select({count:sql`count(*)`}).from(n).where(d),f=S(D),h=c!==void 0&&(t.options.cursor!==void 0||t.options.limit!==void 0),C=d,w=false;if(h&&t.options.cursor){let y=decodeCursor(t.options.cursor);y!==null&&(C=g(d,gt(p(n,c),y)),w=true);}let M=e.select().from(n).where(C);if(t.options.order_by){let y=p(n,t.options.order_by),k=t.options.order_by_direction==="desc"?desc:asc;M=M.orderBy(k(y));}if(h){let y=t.options.limit||t.options.per_page||a;return {records:await M.limit(y+1),totalCount:f,page:0,perPage:y,totalPages:0,cursor:{limit:y,applied:w}}}let R=t.options.page||1,T=t.options.per_page||a,Y=await M.limit(T).offset((R-1)*T),Q=Math.ceil(f/T);return {records:Y,totalCount:f,page:R,perPage:T,totalPages:Q}}function ee(o,e){return {result:o,result_info:{page:e.page,per_page:e.perPage,total_count:e.totalCount,total_pages:e.totalPages,has_next_page:e.page<e.totalPages,has_prev_page:e.page>1}}}async function te(o,e,n,t,r){let i=[];for(let a of r){let l=t[a];l!==void 0&&i.push(eq(n(a),l));}return i.length===0?null:(await o.select().from(e).where(g(...i)).limit(1))[0]||null}function B(o,e,n,t){if(t?.caseSensitive)switch(n){case "pg":return sql`POSITION(${e} IN ${o}) > 0`;case "mysql":return sql`LOCATE(${e}, ${o}) > 0`;default:return sql`INSTR(${o}, ${e}) > 0`}switch(n){case "pg":return sql`POSITION(LOWER(${e}) IN LOWER(${o})) > 0`;case "mysql":return sql`LOCATE(LOWER(${e}), LOWER(${o})) > 0`;default:return sql`INSTR(LOWER(${o}), LOWER(${e})) > 0`}}function m(o){let e=o;if(e._tx)return e._tx;if(e.db)return e.db;let n=e.context?.get?.(CONTEXT_KEYS.db);if(n)return n;throw new ConfigurationException(`Database not configured. Either:
|
|
2
2
|
1. Set db property: db = myDb;
|
|
3
3
|
2. Use middleware: c.set(CONTEXT_KEYS.db, myDb);
|
|
4
|
-
3. Use factory: createDrizzleCrud(db, meta)`)}var j=class extends CreateEndpoint{db;useTransaction=false;getDb(){return m(this)}getTable(){return z(this._meta)}getRelatedTable(e){return e.table}async create(e,n){let t=n??this.getDb(),r=this.getTable(),i=this.applyManagedInsertFields(e,"drizzle");return (await t.insert(r).values(i).returning())[0]}async createNested(e,n,t,r,i){let a=i??this.getDb(),s=this.getRelatedTable(t);if(!s)return getLogger().warn(`Related table not found for ${n}. Add 'table' to the relation config.`),[];let l=Array.isArray(r)?r:[r],d=[];for(let c of l){if(typeof c!="object"||c===null)continue;let u={...c,id:crypto.randomUUID(),[t.foreignKey]:e},D=await a.insert(s).values(u).returning();D[0]&&d.push(D[0]);}return d}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}},P=class extends ReadEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async read(e,n,t){let r=this.getTable(),i=this.getColumn(this.lookupField),a=this.getSoftDeleteConfig(),s=[eq(i,e)];if(n)for(let[c,u]of Object.entries(n))s.push(eq(this.getColumn(c),u));a.enabled&&s.push(isNull(this.getColumn(a.field)));let l=await this.getDb().select().from(r).where(g(...s)).limit(1);return l[0]?await he(this.getDb(),l[0],this._meta,t):null}},I=class extends UpdateEndpoint{db;useTransaction=false;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}getRelatedTable(e){return e.table}async findExisting(e,n,t){let r=t??this.getDb(),i=this.getTable(),a=this.getColumn(this.lookupField),s=this.getSoftDeleteConfig(),l=[eq(a,e)];if(n)for(let[c,u]of Object.entries(n))l.push(eq(this.getColumn(c),u));return s.enabled&&l.push(isNull(this.getColumn(s.field))),(await r.select().from(i).where(g(...l)).limit(1))[0]||null}async update(e,n,t,r){let i=r??this.getDb(),a=this.getTable(),s=this.getColumn(this.lookupField),l=this.getSoftDeleteConfig(),d=[eq(s,e)];if(t)for(let[u,D]of Object.entries(t))d.push(eq(this.getColumn(u),D));return l.enabled&&d.push(isNull(this.getColumn(l.field))),(await i.update(a).set(this.applyManagedUpdateFields(n)).where(g(...d)).returning())[0]||null}async processNestedWrites(e,n,t,r,i){let a=i??this.getDb(),s=this.getRelatedTable(t);if(!s)return getLogger().warn(`Related table not found for ${n}. Add 'table' to the relation config.`),{created:[],updated:[],deleted:[],connected:[],disconnected:[]};let l={created:[],updated:[],deleted:[],connected:[],disconnected:[]},d=p(s,t.foreignKey),c=p(s,"id");if(r.create){let u=Array.isArray(r.create)?r.create:[r.create];for(let D of u){if(typeof D!="object"||D===null)continue;let f={...D,id:crypto.randomUUID(),[t.foreignKey]:e},h=await a.insert(s).values(f).returning();h[0]&&l.created.push(h[0]);}}if(r.update)for(let u of r.update){if(!u.id||!(await a.select().from(s).where(g(eq(c,u.id),eq(d,e))).limit(1))[0])continue;let{id:f,...h}=u,C=await a.update(s).set(h).where(eq(c,f)).returning();C[0]&&l.updated.push(C[0]);}if(r.delete)for(let u of r.delete)(await a.delete(s).where(g(eq(c,u),eq(d,e))).returning())[0]&&l.deleted.push(u);if(r.connect)for(let u of r.connect)(await a.update(s).set({[t.foreignKey]:e}).where(eq(c,u)).returning())[0]&&l.connected.push(u);if(r.disconnect)for(let u of r.disconnect)(await a.update(s).set({[t.foreignKey]:null}).where(g(eq(c,u),eq(d,e))).returning())[0]&&l.disconnected.push(u);return l}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}},_=class extends DeleteEndpoint{db;useTransaction=false;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}getRelatedTable(e){return e.table}async findForDelete(e,n,t){let r=t??this.getDb(),i=this.getTable(),a=this.getColumn(this.lookupField),s=this.getSoftDeleteConfig(),l=[eq(a,e)];if(n)for(let[c,u]of Object.entries(n))l.push(eq(this.getColumn(c),u));return s.enabled&&l.push(isNull(this.getColumn(s.field))),(await r.select().from(i).where(g(...l)).limit(1))[0]||null}async delete(e,n,t){let r=t??this.getDb(),i=this.getTable(),a=this.getColumn(this.lookupField),s=this.getSoftDeleteConfig(),l=[eq(a,e)];if(n)for(let[d,c]of Object.entries(n))l.push(eq(this.getColumn(d),c));return s.enabled&&l.push(isNull(this.getColumn(s.field))),s.enabled?(await r.update(i).set({[s.field]:new Date}).where(g(...l)).returning())[0]||null:(await r.delete(i).where(g(...l)).returning())[0]||null}async countRelated(e,n,t,r){let i=r??this.getDb(),a=this.getRelatedTable(t);if(!a)return 0;let s=p(a,t.foreignKey),l=await i.select({count:sql`count(*)`}).from(a).where(eq(s,e));return S(l)}async deleteRelated(e,n,t,r){let i=r??this.getDb(),a=this.getRelatedTable(t);if(!a)return 0;let s=p(a,t.foreignKey);return (await i.delete(a).where(eq(s,e)).returning()).length}async nullifyRelated(e,n,t,r){let i=r??this.getDb(),a=this.getRelatedTable(t);if(!a)return 0;let s=p(a,t.foreignKey);return (await i.update(a).set({[t.foreignKey]:null}).where(eq(s,e)).returning()).length}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}},A=class extends ListEndpoint{db;dialect="sqlite";supportsCursorPagination=true;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async list(e){let n=await V({db:this.getDb(),table:this.getTable(),filters:e,dialect:this.dialect,searchFields:this.searchFields,softDeleteConfig:this.getSoftDeleteConfig(),defaultPerPage:this.defaultPerPage,cursorField:this.isCursorPaginationActive()?this.cursorField||"id":void 0}),t={relations:e.options.include||[],scope:this.getRelationScope(e.options.withDeleted)};if(n.cursor){let{items:i,result_info:a}=buildCursorPage({rows:n.records,limit:n.cursor.limit,totalCount:n.totalCount,cursorField:this.cursorField||"id",cursorApplied:n.cursor.applied});return {result:await v(this.getDb(),i,this._meta,t),result_info:a}}let r=await v(this.getDb(),n.records,this._meta,t);return ee(r,n)}},q=class extends RestoreEndpoint{db;useTransaction=false;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async restore(e,n,t){let r=t??this.getDb(),i=this.getTable(),a=this.getColumn(this.lookupField),s=this.getSoftDeleteConfig(),l=[eq(a,e)];if(n)for(let[c,u]of Object.entries(n))l.push(eq(this.getColumn(c),u));return l.push(isNotNull(this.getColumn(s.field))),(await r.update(i).set({[s.field]:null}).where(g(...l)).returning())[0]||null}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}};var U=class extends BatchCreateEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}async batchCreate(e){let n=this.getTable(),t=e.map(i=>this.applyManagedInsertFields(i,"drizzle"));return await this.getDb().insert(n).values(t).returning()}},F=class extends BatchUpdateEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async batchUpdate(e){let n=this.getTable(),t=this.getColumn(this.lookupField),r=this.getSoftDeleteConfig(),i=[],a=[];for(let s of e){let l=[eq(t,s.id)];r.enabled&&l.push(isNull(this.getColumn(r.field)));let d=await this.getDb().update(n).set(this.applyManagedUpdateFields(s.data)).where(g(...l)).returning();d[0]?i.push(d[0]):a.push(s.id);}return {updated:i,notFound:a}}},Z=class extends BatchDeleteEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async batchDelete(e){let n=this.getTable(),t=this.getColumn(this.lookupField),r=this.getSoftDeleteConfig(),i=[inArray(t,e)];r.enabled&&i.push(isNull(this.getColumn(r.field)));let a;r.enabled?a=await this.getDb().update(n).set({[r.field]:new Date}).where(g(...i)).returning():a=await this.getDb().delete(n).where(g(...i)).returning();let s=a,l=new Set(s.map(c=>String(c[this.lookupField]))),d=e.filter(c=>!l.has(c));return {deleted:s,notFound:d}}},L=class extends BatchRestoreEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async batchRestore(e){let n=this.getTable(),t=this.getColumn(this.lookupField),r=this.getSoftDeleteConfig(),i=[inArray(t,e),isNotNull(this.getColumn(r.field))],s=await this.getDb().update(n).set({[r.field]:null}).where(g(...i)).returning(),l=new Set(s.map(c=>String(c[this.lookupField]))),d=e.filter(c=>!l.has(c));return {restored:s,notFound:d}}};function Et(o){return o.split(/\s+/).filter(e=>e.length>0)}var N=class extends UpsertEndpoint{db;dialect="sqlite";getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async findExisting(e){return te(this.getDb(),this.getTable(),n=>this.getColumn(n),e,this.getUpsertKeys())}async create(e){let n=this.getTable(),t=this.applyManagedInsertFields(e,"drizzle");return (await this.getDb().insert(n).values(t).returning())[0]}async update(e,n){let t=this.getTable(),r=this._meta.model.primaryKeys[0],i=e[r];return (await this.getDb().update(t).set(this.applyManagedUpdateFields(n)).where(eq(this.getColumn(r),i)).returning())[0]}async nativeUpsert(e,n){let t=this.getTable(),r=this.getUpsertKeys(),i=this._meta.model.primaryKeys[0],a=this.getSoftDeleteConfig(),s=this.getTimestampsConfig(),l=this.applyManagedInsertFields(e,"drizzle"),d={};for(let[C,w]of Object.entries(e))!r.includes(C)&&C!==i&&(this.createOnlyFields?.includes(C)||(d[C]=w));s.enabled&&(d[s.updatedAt]=Date.now());let c=r.map(C=>this.getColumn(C)),u;a.enabled&&(u=isNull(this.getColumn(a.field)));let D=Object.keys(d).length>0?d:{[i]:sql`${this.getColumn(i)}`},f=this.getDb().insert(t).values(l);return this.dialect==="mysql"?{data:(await f.onDuplicateKeyUpdate({set:D}).returning())[0],created:false}:{data:(await f.onConflictDoUpdate({target:c,set:D,where:u}).returning())[0],created:false}}},$=class extends BatchUpsertEndpoint{db;dialect="sqlite";getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async findExisting(e){return te(this.getDb(),this.getTable(),n=>this.getColumn(n),e,this.getUpsertKeys())}async create(e){let n=this.getTable(),t=this.applyManagedInsertFields(e,"drizzle");return (await this.getDb().insert(n).values(t).returning())[0]}async update(e,n){let t=this.getTable(),r=this._meta.model.primaryKeys[0],i=e[r];return (await this.getDb().update(t).set(this.applyManagedUpdateFields(n)).where(eq(this.getColumn(r),i)).returning())[0]}async nativeBatchUpsert(e,n){if(e.length===0)return {items:[],createdCount:0,updatedCount:0,totalCount:0};let t=this.getTable(),r=this.getUpsertKeys(),i=this._meta.model.primaryKeys[0],a=this.getTimestampsConfig(),s=e.map(h=>this.applyManagedInsertFields(h,"drizzle")),l={},d=e[0];for(let h of Object.keys(d))!r.includes(h)&&h!==i&&(this.createOnlyFields?.includes(h)||(l[h]=sql`excluded.${sql.identifier(h)}`));a.enabled&&(l[a.updatedAt]=Date.now());let c=r.map(h=>this.getColumn(h)),u=Object.keys(l).length>0?l:{[i]:sql`${this.getColumn(i)}`},D=this.getDb().insert(t).values(s),f=await(this.dialect==="mysql"?D.onDuplicateKeyUpdate({set:u}):D.onConflictDoUpdate({target:c,set:u})).returning();return {items:f.map((h,C)=>({data:h,created:false,index:C})),createdCount:0,updatedCount:f.length,totalCount:f.length}}},ne=class extends BulkPatchEndpoint{db;dialect="sqlite";getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}buildConditions(e){let n=this.getTable(),t=[];for(let i of e.filters){let a=W(n,i,this.dialect);a&&t.push(a);}let r=this.getSoftDeleteConfig();return r.enabled&&t.push(isNull(this.getColumn(r.field))),t}async countMatching(e){let n=this.buildConditions(e),t=await this.getDb().select({count:sql`count(*)`}).from(this.getTable()).where(g(...n));return S(t)}async applyPatch(e,n){let t=this.buildConditions(n),r=await this.getDb().update(this.getTable()).set(this.applyManagedUpdateFields(e)).where(g(...t)).returning();return {updated:r.length,records:r}}},re=class extends VersionHistoryEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async recordExists(e){let n=this.getTable(),t=await this.getDb().select({count:sql`count(*)`}).from(n).where(eq(this.getColumn("id"),e));return S(t)>0}},oe=class extends VersionReadEndpoint{},ie=class extends VersionCompareEndpoint{},se=class extends VersionRollbackEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async rollback(e,n,t){let r=this.getTable(),i=this.getVersioningConfig().field;return (await this.getDb().update(r).set({...n,[i]:t}).where(eq(this.getColumn("id"),e)).returning())[0]}},ae=class extends AggregateEndpoint{db;dialect="sqlite";getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async aggregate(e){let n=this.getTable(),t=[],r=this.getSoftDeleteConfig();if(r.enabled){let{query:s}=await this.getValidatedData();s?.withDeleted===true||s?.withDeleted==="true"||t.push(isNull(this.getColumn(r.field)));}if(e.filters)for(let[s,l]of Object.entries(e.filters))if(typeof l=="object"&&l!==null)for(let[d,c]of Object.entries(l)){if(!isFilterOperator(d)){t.push(sql`1 = 0`);continue}let u=W(n,{field:s,operator:d,value:c},this.dialect);u&&t.push(u);}else t.push(eq(this.getColumn(s),l));let i=t.length>0?g(...t):void 0,a=await this.getDb().select().from(n).where(i);return computeAggregations(a,e)}},K=class extends SearchEndpoint{db;dialect="sqlite";getDb(){return m(this)}useNativeSearch=false;vectorColumn;vectorConfig="english";getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async search(e,n){let t=this.getTable(),r=[],i=this.getSearchableFields(),a=e.fields||Object.keys(i);if(this.useNativeSearch&&this.vectorColumn){let w=this.getColumn(this.vectorColumn),M=e.mode==="phrase"?sql`phraseto_tsquery(${this.vectorConfig}, ${e.query})`:e.mode==="all"?sql`plainto_tsquery(${this.vectorConfig}, ${e.query})`:sql`to_tsquery(${this.vectorConfig}, ${e.query.split(/\s+/).join(" | ")})`;r.push(sql`${w} @@ ${M}`);}else {let w=(M,E)=>{try{let T=this.getColumn(M);return B(sql`CAST(${T} AS TEXT)`,E,this.dialect)}catch{return}};if(e.mode==="all"){let M=Et(e.query);if(M.length>0){let E=[];for(let T of M){let Y=a.map(Q=>w(Q,T)).filter(Q=>Q!==void 0);Y.length>0&&E.push(J(...Y));}E.length>0&&r.push(g(...E));}}else {let M=a.map(E=>w(E,e.query)).filter(E=>E!==void 0);M.length>0&&r.push(J(...M));}}let s=await V({db:this.getDb(),table:t,filters:n,dialect:this.dialect,softDeleteConfig:this.getSoftDeleteConfig(),defaultPerPage:this.defaultPerPage,extraConditions:r}),l=s.records,d=s.totalCount,c=e.mode==="all"?{...e,mode:"any"}:e,u=searchInMemory(l,c,i),D={relations:n.options.include||[]},f=u.map(w=>w.item),h=await v(this.getDb(),f,this._meta,D);return {items:u.map((w,M)=>({...w,item:h[M]})),totalCount:d}}},le=class extends ExportEndpoint{db;dialect="sqlite";getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async list(e){let n=await V({db:this.getDb(),table:this.getTable(),filters:e,dialect:this.dialect,searchFields:this.searchFields,softDeleteConfig:this.getSoftDeleteConfig(),defaultPerPage:this.defaultPerPage}),t={relations:e.options.include||[]},r=await v(this.getDb(),n.records,this._meta,t);return ee(r,n)}},de=class extends ImportEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async findExisting(e){return te(this.getDb(),this.getTable(),n=>this.getColumn(n),e,this.getUpsertKeys())}async create(e){let n=this.getTable(),t=this.applyManagedInsertFields(e,"drizzle");return (await this.getDb().insert(n).values(t).returning())[0]}async update(e,n){let t=this.getTable(),r=this._meta.model.primaryKeys[0],i=e[r];return (await this.getDb().update(t).set(this.applyManagedUpdateFields(n)).where(eq(this.getColumn(r),i)).returning())[0]}},ce=class extends CloneEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}generateId(){return crypto.randomUUID()}async findSource(e,n){let t=this.getTable(),r=this.getColumn(this.lookupField),i=this.getSoftDeleteConfig(),a=[eq(r,e)];if(n)for(let[l,d]of Object.entries(n))a.push(eq(this.getColumn(l),d));i.enabled&&a.push(isNull(this.getColumn(i.field)));let s=await this.getDb().select().from(t).where(g(...a)).limit(1);return s[0]?s[0]:null}async createClone(e){let n=this.getTable(),t=this.applyManagedInsertFields(e,"drizzle",()=>this.generateId());return (await this.getDb().insert(n).values(t).returning())[0]}};function yn(o,e,n){let t=n?.dialect??"sqlite";return {Create:class extends j{_meta=e;db=o},Read:class extends P{_meta=e;db=o},Update:class extends I{_meta=e;db=o},Delete:class extends _{_meta=e;db=o},List:class extends A{_meta=e;db=o;dialect=t},Restore:class extends q{_meta=e;db=o},Upsert:class extends N{_meta=e;db=o;dialect=t},Search:class extends K{_meta=e;db=o;dialect=t},BatchCreate:class extends U{_meta=e;db=o},BatchUpdate:class extends F{_meta=e;db=o},BatchDelete:class extends Z{_meta=e;db=o},BatchRestore:class extends L{_meta=e;db=o},BatchUpsert:class extends ${_meta=e;db=o;dialect=t}}}var ge=null,Te=false,pe=null;async function ze(){if(Te){if(pe)throw pe;return ge}Te=true;try{return ge=await import('drizzle-zod'),ge}catch{throw pe=new Error("drizzle-zod is not installed. Please install it: npm install drizzle-zod"),pe}}async function Rt(o,e){return (await ze()).createSelectSchema(o,e)}async function Tt(o,e){return (await ze()).createInsertSchema(o,e)}async function xt(o,e){let n=await ze();return n.createUpdateSchema?n.createUpdateSchema(o,e):n.createInsertSchema(o,e).partial()}async function kt(o,e){let n=await ze(),t=e?.coerceDates!==false,r=t?Bt(o):new Set,i=n.createSelectSchema(o,e?.selectRefine),a=n.createInsertSchema(o,e?.insertRefine),s;return n.createUpdateSchema?s=n.createUpdateSchema(o,e?.updateRefine):s=n.createInsertSchema(o,e?.updateRefine).partial(),t&&r.size>0&&(a=xe(a,r),s=xe(s,r)),{select:i,insert:a,update:s}}function Ot(){return ge!==null}var vt=z$1.preprocess(o=>{if(o instanceof Date)return o;if(typeof o=="string"){let e=new Date(o);if(!isNaN(e.getTime()))return e}return o},z$1.date()),St=z$1.preprocess(o=>{if(o==null)return null;if(o instanceof Date)return o;if(typeof o=="string"){let e=new Date(o);if(!isNaN(e.getTime()))return e}return o},z$1.date().nullable());function Bt(o){let e=new Set,n=o;for(let[t,r]of Object.entries(n)){if(t==="_"||t==="$inferInsert"||t==="$inferSelect")continue;let i=r;if(!i||typeof i!="object")continue;let a=String(i.dataType??"").toLowerCase(),s=String(i.columnType??"").toLowerCase(),l=i.config,d=String(l?.dataType??"").toLowerCase();(a.includes("timestamp")||a.includes("date")||a.includes("datetime")||s.includes("pgtimestamp")||s.includes("pgdate")||s.includes("mysqltimestamp")||s.includes("mysqldate")||s.includes("sqlitetimestamp")||d.includes("timestamp")||d.includes("date"))&&e.add(t);}return e}function xe(o,e){if(e.size===0)return o;let n=o.shape,t={};for(let[r,i]of Object.entries(n))if(e.has(r)){let a=i.isOptional?.()??false,s=i.isNullable?.()??false,l=vt;(s||a)&&(l=St),a&&(l=l.optional()),t[r]=l;}else t[r]=i;return z$1.object(t)}var Ln={CreateEndpoint:j,ListEndpoint:A,ReadEndpoint:P,UpdateEndpoint:I,DeleteEndpoint:_,RestoreEndpoint:q,BatchCreateEndpoint:U,BatchUpdateEndpoint:F,BatchDeleteEndpoint:Z,BatchRestoreEndpoint:L,BatchUpsertEndpoint:$,SearchEndpoint:K,AggregateEndpoint:ae,ExportEndpoint:le,ImportEndpoint:de,UpsertEndpoint:N,CloneEndpoint:ce,BulkPatchEndpoint:ne,VersionHistoryEndpoint:re,VersionReadEndpoint:oe,VersionCompareEndpoint:ie,VersionRollbackEndpoint:se};export{$e as DRIZZLE_DIALECTS,Ln as DrizzleAdapters,ae as DrizzleAggregateEndpoint,U as DrizzleBatchCreateEndpoint,Z as DrizzleBatchDeleteEndpoint,L as DrizzleBatchRestoreEndpoint,F as DrizzleBatchUpdateEndpoint,$ as DrizzleBatchUpsertEndpoint,ne as DrizzleBulkPatchEndpoint,ce as DrizzleCloneEndpoint,j as DrizzleCreateEndpoint,_ as DrizzleDeleteEndpoint,le as DrizzleExportEndpoint,de as DrizzleImportEndpoint,A as DrizzleListEndpoint,P as DrizzleReadEndpoint,q as DrizzleRestoreEndpoint,K as DrizzleSearchEndpoint,I as DrizzleUpdateEndpoint,N as DrizzleUpsertEndpoint,ie as DrizzleVersionCompareEndpoint,re as DrizzleVersionHistoryEndpoint,oe as DrizzleVersionReadEndpoint,se as DrizzleVersionRollbackEndpoint,v as batchLoadDrizzleRelations,W as buildWhereCondition,G as cast,yn as createDrizzleCrud,kt as createDrizzleSchemas,Tt as createInsertSchema,Rt as createSelectSchema,xt as createUpdateSchema,p as getColumn,z as getTable,Ot as isDrizzleZodAvailable,Ke as loadDrizzleRelation,he as loadDrizzleRelations,S as readCount,B as substringMatch};
|
|
4
|
+
3. Use factory: createDrizzleCrud(db, meta)`)}var j=class extends CreateEndpoint{db;useTransaction=false;getDb(){return m(this)}getTable(){return z(this._meta)}getRelatedTable(e){return e.table}async create(e,n){let t=n??this.getDb(),r=this.getTable(),i=this.applyManagedInsertFields(e,"drizzle");return (await t.insert(r).values(i).returning())[0]}async createNested(e,n,t,r,i){let s=i??this.getDb(),a=this.getRelatedTable(t);if(!a)return getLogger().warn(`Related table not found for ${n}. Add 'table' to the relation config.`),[];let l=Array.isArray(r)?r:[r],c=[];for(let u of l){if(typeof u!="object"||u===null)continue;let d={...u,id:crypto.randomUUID(),[t.foreignKey]:e},D=await s.insert(a).values(d).returning();D[0]&&c.push(D[0]);}return c}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}},P=class extends ReadEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async read(e,n,t){let r=this.getTable(),i=this.getColumn(this.lookupField),s=this.getSoftDeleteConfig(),a=[eq(i,e)];if(n)for(let[u,d]of Object.entries(n))a.push(eq(this.getColumn(u),d));s.enabled&&a.push(isNull(this.getColumn(s.field)));let l=await this.getDb().select().from(r).where(g(...a)).limit(1);return l[0]?await fe(this.getDb(),l[0],this._meta,t):null}},I=class extends UpdateEndpoint{db;useTransaction=false;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}getRelatedTable(e){return e.table}async findExisting(e,n,t){let r=t??this.getDb(),i=this.getTable(),s=this.getColumn(this.lookupField),a=this.getSoftDeleteConfig(),l=[eq(s,e)];if(n)for(let[u,d]of Object.entries(n))l.push(eq(this.getColumn(u),d));return a.enabled&&l.push(isNull(this.getColumn(a.field))),(await r.select().from(i).where(g(...l)).limit(1))[0]||null}async update(e,n,t,r){let i=r??this.getDb(),s=this.getTable(),a=this.getColumn(this.lookupField),l=this.getSoftDeleteConfig(),c=[eq(a,e)];if(t)for(let[d,D]of Object.entries(t))c.push(eq(this.getColumn(d),D));return l.enabled&&c.push(isNull(this.getColumn(l.field))),(await i.update(s).set(this.applyManagedUpdateFields(n)).where(g(...c)).returning())[0]||null}async processNestedWrites(e,n,t,r,i){let s=i??this.getDb(),a=this.getRelatedTable(t);if(!a)return getLogger().warn(`Related table not found for ${n}. Add 'table' to the relation config.`),{created:[],updated:[],deleted:[],connected:[],disconnected:[]};let l={created:[],updated:[],deleted:[],connected:[],disconnected:[]},c=p(a,t.foreignKey),u=p(a,"id");if(r.create){let d=Array.isArray(r.create)?r.create:[r.create];for(let D of d){if(typeof D!="object"||D===null)continue;let f={...D,id:crypto.randomUUID(),[t.foreignKey]:e},h=await s.insert(a).values(f).returning();h[0]&&l.created.push(h[0]);}}if(r.update)for(let d of r.update){if(!d.id||!(await s.select().from(a).where(g(eq(u,d.id),eq(c,e))).limit(1))[0])continue;let{id:f,...h}=d,C=await s.update(a).set(h).where(eq(u,f)).returning();C[0]&&l.updated.push(C[0]);}if(r.delete)for(let d of r.delete)(await s.delete(a).where(g(eq(u,d),eq(c,e))).returning())[0]&&l.deleted.push(d);if(r.connect)for(let d of r.connect)(await s.update(a).set({[t.foreignKey]:e}).where(eq(u,d)).returning())[0]&&l.connected.push(d);if(r.disconnect)for(let d of r.disconnect)(await s.update(a).set({[t.foreignKey]:null}).where(g(eq(u,d),eq(c,e))).returning())[0]&&l.disconnected.push(d);return l}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}},_=class extends DeleteEndpoint{db;useTransaction=false;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}getRelatedTable(e){return e.table}async findForDelete(e,n,t){let r=t??this.getDb(),i=this.getTable(),s=this.getColumn(this.lookupField),a=this.getSoftDeleteConfig(),l=[eq(s,e)];if(n)for(let[u,d]of Object.entries(n))l.push(eq(this.getColumn(u),d));return a.enabled&&l.push(isNull(this.getColumn(a.field))),(await r.select().from(i).where(g(...l)).limit(1))[0]||null}async delete(e,n,t){let r=t??this.getDb(),i=this.getTable(),s=this.getColumn(this.lookupField),a=this.getSoftDeleteConfig(),l=[eq(s,e)];if(n)for(let[c,u]of Object.entries(n))l.push(eq(this.getColumn(c),u));return a.enabled&&l.push(isNull(this.getColumn(a.field))),a.enabled?(await r.update(i).set({[a.field]:new Date}).where(g(...l)).returning())[0]||null:(await r.delete(i).where(g(...l)).returning())[0]||null}async countRelated(e,n,t,r){let i=r??this.getDb(),s=this.getRelatedTable(t);if(!s)return 0;let a=p(s,t.foreignKey),l=await i.select({count:sql`count(*)`}).from(s).where(eq(a,e));return S(l)}async deleteRelated(e,n,t,r){let i=r??this.getDb(),s=this.getRelatedTable(t);if(!s)return 0;let a=p(s,t.foreignKey);return (await i.delete(s).where(eq(a,e)).returning()).length}async nullifyRelated(e,n,t,r){let i=r??this.getDb(),s=this.getRelatedTable(t);if(!s)return 0;let a=p(s,t.foreignKey);return (await i.update(s).set({[t.foreignKey]:null}).where(eq(a,e)).returning()).length}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}},A=class extends ListEndpoint{db;dialect="sqlite";supportsCursorPagination=true;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async list(e){let n=await V({db:this.getDb(),table:this.getTable(),filters:e,dialect:this.dialect,searchFields:this.searchFields,softDeleteConfig:this.getSoftDeleteConfig(),defaultPerPage:this.defaultPerPage,cursorField:this.isCursorPaginationActive()?this.cursorField||"id":void 0}),t={relations:e.options.include||[],scope:this.getRelationScope(e.options.withDeleted)};if(n.cursor){let{items:i,result_info:s}=buildCursorPage({rows:n.records,limit:n.cursor.limit,totalCount:n.totalCount,cursorField:this.cursorField||"id",cursorApplied:n.cursor.applied});return {result:await v(this.getDb(),i,this._meta,t),result_info:s}}let r=await v(this.getDb(),n.records,this._meta,t);return ee(r,n)}},F=class extends RestoreEndpoint{db;useTransaction=false;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async restore(e,n,t){let r=t??this.getDb(),i=this.getTable(),s=this.getColumn(this.lookupField),a=this.getSoftDeleteConfig(),l=[eq(s,e)];if(n)for(let[u,d]of Object.entries(n))l.push(eq(this.getColumn(u),d));return l.push(isNotNull(this.getColumn(a.field))),(await r.update(i).set({[a.field]:null}).where(g(...l)).returning())[0]||null}async handle(){return this.useTransaction?this.getDb().transaction(async e=>{this._tx=e;try{return await super.handle()}finally{this._tx=void 0;}}):super.handle()}};var q=class extends BatchCreateEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}async batchCreate(e){let n=this.getTable(),t=e.map(i=>this.applyManagedInsertFields(i,"drizzle"));return await this.getDb().insert(n).values(t).returning()}},U=class extends BatchUpdateEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async batchUpdate(e){let n=this.getTable(),t=this.getColumn(this.lookupField),r=this.getSoftDeleteConfig(),i=[],s=[],a=this.getTenantScopeFilter();for(let l of e){let c=[eq(t,l.id)];r.enabled&&c.push(isNull(this.getColumn(r.field))),a&&c.push(eq(this.getColumn(a.field),a.value));let u=await this.getDb().update(n).set(this.applyManagedUpdateFields(l.data)).where(g(...c)).returning();u[0]?i.push(u[0]):s.push(l.id);}return {updated:i,notFound:s}}},Z=class extends BatchDeleteEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async batchDelete(e){let n=this.getTable(),t=this.getColumn(this.lookupField),r=this.getSoftDeleteConfig(),i=[inArray(t,e)];r.enabled&&i.push(isNull(this.getColumn(r.field)));let s=this.getTenantScopeFilter();s&&i.push(eq(this.getColumn(s.field),s.value));let a;r.enabled?a=await this.getDb().update(n).set({[r.field]:new Date}).where(g(...i)).returning():a=await this.getDb().delete(n).where(g(...i)).returning();let l=a,c=new Set(l.map(d=>String(d[this.lookupField]))),u=e.filter(d=>!c.has(d));return {deleted:l,notFound:u}}},L=class extends BatchRestoreEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async batchRestore(e){let n=this.getTable(),t=this.getColumn(this.lookupField),r=this.getSoftDeleteConfig(),i=[inArray(t,e),isNotNull(this.getColumn(r.field))],s=this.getTenantScopeFilter();s&&i.push(eq(this.getColumn(s.field),s.value));let l=await this.getDb().update(n).set({[r.field]:null}).where(g(...i)).returning(),c=new Set(l.map(d=>String(d[this.lookupField]))),u=e.filter(d=>!c.has(d));return {restored:l,notFound:u}}};function Rt(o){return o.split(/\s+/).filter(e=>e.length>0)}var N=class extends UpsertEndpoint{db;dialect="sqlite";getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async findExisting(e){return te(this.getDb(),this.getTable(),n=>this.getColumn(n),e,this.getUpsertKeys())}async create(e){let n=this.getTable(),t=this.applyManagedInsertFields(e,"drizzle");return (await this.getDb().insert(n).values(t).returning())[0]}async update(e,n){let t=this.getTable(),r=this._meta.model.primaryKeys[0],i=e[r];return (await this.getDb().update(t).set(this.applyManagedUpdateFields(n)).where(eq(this.getColumn(r),i)).returning())[0]}async nativeUpsert(e,n){let t=this.getTable(),r=this.getUpsertKeys(),i=this._meta.model.primaryKeys[0],s=this.getSoftDeleteConfig(),a=this.getTimestampsConfig(),l=this.applyManagedInsertFields(e,"drizzle"),c={};for(let[C,w]of Object.entries(e))!r.includes(C)&&C!==i&&(this.createOnlyFields?.includes(C)||(c[C]=w));a.enabled&&(c[a.updatedAt]=Date.now());let u=r.map(C=>this.getColumn(C)),d;s.enabled&&(d=isNull(this.getColumn(s.field)));let D=Object.keys(c).length>0?c:{[i]:sql`${this.getColumn(i)}`},f=this.getDb().insert(t).values(l);return this.dialect==="mysql"?{data:(await f.onDuplicateKeyUpdate({set:D}).returning())[0],created:false}:{data:(await f.onConflictDoUpdate({target:u,set:D,where:d}).returning())[0],created:false}}},$=class extends BatchUpsertEndpoint{db;dialect="sqlite";getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async findExisting(e){return te(this.getDb(),this.getTable(),n=>this.getColumn(n),e,this.getUpsertKeys())}async create(e){let n=this.getTable(),t=this.applyManagedInsertFields(e,"drizzle");return (await this.getDb().insert(n).values(t).returning())[0]}async update(e,n){let t=this.getTable(),r=this._meta.model.primaryKeys[0],i=e[r];return (await this.getDb().update(t).set(this.applyManagedUpdateFields(n)).where(eq(this.getColumn(r),i)).returning())[0]}async nativeBatchUpsert(e,n){if(e.length===0)return {items:[],createdCount:0,updatedCount:0,totalCount:0};let t=this.getTable(),r=this.getUpsertKeys(),i=this._meta.model.primaryKeys[0],s=this.getTimestampsConfig(),a=e.map(h=>this.applyManagedInsertFields(h,"drizzle")),l={},c=e[0];for(let h of Object.keys(c))!r.includes(h)&&h!==i&&(this.createOnlyFields?.includes(h)||(l[h]=sql`excluded.${sql.identifier(h)}`));s.enabled&&(l[s.updatedAt]=Date.now());let u=r.map(h=>this.getColumn(h)),d=Object.keys(l).length>0?l:{[i]:sql`${this.getColumn(i)}`},D=this.getDb().insert(t).values(a),f=await(this.dialect==="mysql"?D.onDuplicateKeyUpdate({set:d}):D.onConflictDoUpdate({target:u,set:d})).returning();return {items:f.map((h,C)=>({data:h,created:false,index:C})),createdCount:0,updatedCount:f.length,totalCount:f.length}}},re=class extends BulkPatchEndpoint{db;dialect="sqlite";getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}buildConditions(e){let n=this.getTable(),t=[];for(let i of e.filters){let s=W(n,i,this.dialect);s&&t.push(s);}let r=this.getSoftDeleteConfig();return r.enabled&&t.push(isNull(this.getColumn(r.field))),t}async countMatching(e){let n=this.buildConditions(e),t=await this.getDb().select({count:sql`count(*)`}).from(this.getTable()).where(g(...n));return S(t)}async applyPatch(e,n){let t=this.buildConditions(n),r=await this.getDb().update(this.getTable()).set(this.applyManagedUpdateFields(e)).where(g(...t)).returning();return {updated:r.length,records:r}}},oe=class extends VersionHistoryEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async recordExists(e){let n=this.getTable(),t=await this.getDb().select({count:sql`count(*)`}).from(n).where(eq(this.getColumn("id"),e));return S(t)>0}},ie=class extends VersionReadEndpoint{},se=class extends VersionCompareEndpoint{},ae=class extends VersionRollbackEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async rollback(e,n,t){let r=this.getTable(),i=this.getVersioningConfig().field;return (await this.getDb().update(r).set({...n,[i]:t}).where(eq(this.getColumn("id"),e)).returning())[0]}},le=class extends AggregateEndpoint{db;dialect="sqlite";getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async aggregate(e){let n=this.getTable(),t=[],r=this.getSoftDeleteConfig();if(r.enabled){let{query:a}=await this.getValidatedData();a?.withDeleted===true||a?.withDeleted==="true"||t.push(isNull(this.getColumn(r.field)));}if(e.filters)for(let[a,l]of Object.entries(e.filters))if(typeof l=="object"&&l!==null)for(let[c,u]of Object.entries(l)){if(!isFilterOperator(c)){t.push(sql`1 = 0`);continue}let d=W(n,{field:a,operator:c,value:u},this.dialect);d&&t.push(d);}else t.push(eq(this.getColumn(a),l));let i=t.length>0?g(...t):void 0,s=await this.getDb().select().from(n).where(i);return computeAggregations(s,e)}},K=class extends SearchEndpoint{db;dialect="sqlite";getDb(){return m(this)}useNativeSearch=false;vectorColumn;vectorConfig="english";getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async search(e,n){let t=this.getTable(),r=[],i=this.getSearchableFields(),s=e.fields||Object.keys(i);if(this.useNativeSearch&&this.vectorColumn){let w=this.getColumn(this.vectorColumn),M=e.mode==="phrase"?sql`phraseto_tsquery(${this.vectorConfig}, ${e.query})`:e.mode==="all"?sql`plainto_tsquery(${this.vectorConfig}, ${e.query})`:sql`to_tsquery(${this.vectorConfig}, ${e.query.split(/\s+/).join(" | ")})`;r.push(sql`${w} @@ ${M}`);}else {let w=(M,R)=>{try{let T=this.getColumn(M);return B(sql`CAST(${T} AS TEXT)`,R,this.dialect)}catch{return}};if(e.mode==="all"){let M=Rt(e.query);if(M.length>0){let R=[];for(let T of M){let Y=s.map(Q=>w(Q,T)).filter(Q=>Q!==void 0);Y.length>0&&R.push(J(...Y));}R.length>0&&r.push(g(...R));}}else {let M=s.map(R=>w(R,e.query)).filter(R=>R!==void 0);M.length>0&&r.push(J(...M));}}let a=await V({db:this.getDb(),table:t,filters:n,dialect:this.dialect,softDeleteConfig:this.getSoftDeleteConfig(),defaultPerPage:this.defaultPerPage,extraConditions:r}),l=a.records,c=a.totalCount,u=e.mode==="all"?{...e,mode:"any"}:e,d=searchInMemory(l,u,i),D={relations:n.options.include||[],scope:this.getRelationScope(n.options.withDeleted)},f=d.map(w=>w.item),h=await v(this.getDb(),f,this._meta,D);return {items:d.map((w,M)=>({...w,item:h[M]})),totalCount:c}}},de=class extends ExportEndpoint{db;dialect="sqlite";getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async list(e){let n=await V({db:this.getDb(),table:this.getTable(),filters:e,dialect:this.dialect,searchFields:this.searchFields,softDeleteConfig:this.getSoftDeleteConfig(),defaultPerPage:this.defaultPerPage}),t={relations:e.options.include||[],scope:this.getRelationScope(e.options.withDeleted)},r=await v(this.getDb(),n.records,this._meta,t);return ee(r,n)}},ce=class extends ImportEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}async findExisting(e){return te(this.getDb(),this.getTable(),n=>this.getColumn(n),e,this.getUpsertKeys())}async create(e){let n=this.getTable(),t=this.applyManagedInsertFields(e,"drizzle");return (await this.getDb().insert(n).values(t).returning())[0]}async update(e,n){let t=this.getTable(),r=this._meta.model.primaryKeys[0],i=e[r];return (await this.getDb().update(t).set(this.applyManagedUpdateFields(n)).where(eq(this.getColumn(r),i)).returning())[0]}},ue=class extends CloneEndpoint{db;getDb(){return m(this)}getTable(){return z(this._meta)}getColumn(e){return p(this.getTable(),e)}generateId(){return crypto.randomUUID()}async findSource(e,n){let t=this.getTable(),r=this.getColumn(this.lookupField),i=this.getSoftDeleteConfig(),s=[eq(r,e)];if(n)for(let[l,c]of Object.entries(n))s.push(eq(this.getColumn(l),c));i.enabled&&s.push(isNull(this.getColumn(i.field)));let a=await this.getDb().select().from(t).where(g(...s)).limit(1);return a[0]?a[0]:null}async createClone(e){let n=this.getTable(),t=this.applyManagedInsertFields(e,"drizzle",()=>this.generateId());return (await this.getDb().insert(n).values(t).returning())[0]}};function yn(o,e,n){let t=n?.dialect??"sqlite";return {Create:class extends j{_meta=e;db=o},Read:class extends P{_meta=e;db=o},Update:class extends I{_meta=e;db=o},Delete:class extends _{_meta=e;db=o},List:class extends A{_meta=e;db=o;dialect=t},Restore:class extends F{_meta=e;db=o},Upsert:class extends N{_meta=e;db=o;dialect=t},Search:class extends K{_meta=e;db=o;dialect=t},BatchCreate:class extends q{_meta=e;db=o},BatchUpdate:class extends U{_meta=e;db=o},BatchDelete:class extends Z{_meta=e;db=o},BatchRestore:class extends L{_meta=e;db=o},BatchUpsert:class extends ${_meta=e;db=o;dialect=t}}}var ze=null,xe=false,ge=null;async function me(){if(xe){if(ge)throw ge;return ze}xe=true;try{return ze=await import('drizzle-zod'),ze}catch{throw ge=new Error("drizzle-zod is not installed. Please install it: npm install drizzle-zod"),ge}}async function Et(o,e){return (await me()).createSelectSchema(o,e)}async function Tt(o,e){return (await me()).createInsertSchema(o,e)}async function xt(o,e){let n=await me();return n.createUpdateSchema?n.createUpdateSchema(o,e):n.createInsertSchema(o,e).partial()}async function kt(o,e){let n=await me(),t=e?.coerceDates!==false,r=t?Bt(o):new Set,i=n.createSelectSchema(o,e?.selectRefine),s=n.createInsertSchema(o,e?.insertRefine),a;return n.createUpdateSchema?a=n.createUpdateSchema(o,e?.updateRefine):a=n.createInsertSchema(o,e?.updateRefine).partial(),t&&r.size>0&&(s=ke(s,r),a=ke(a,r)),{select:i,insert:s,update:a}}function Ot(){return ze!==null}var vt=z$1.preprocess(o=>{if(o instanceof Date)return o;if(typeof o=="string"){let e=new Date(o);if(!isNaN(e.getTime()))return e}return o},z$1.date()),St=z$1.preprocess(o=>{if(o==null)return null;if(o instanceof Date)return o;if(typeof o=="string"){let e=new Date(o);if(!isNaN(e.getTime()))return e}return o},z$1.date().nullable());function Bt(o){let e=new Set,n=o;for(let[t,r]of Object.entries(n)){if(t==="_"||t==="$inferInsert"||t==="$inferSelect")continue;let i=r;if(!i||typeof i!="object")continue;let s=String(i.dataType??"").toLowerCase(),a=String(i.columnType??"").toLowerCase(),l=i.config,c=String(l?.dataType??"").toLowerCase();(s.includes("timestamp")||s.includes("date")||s.includes("datetime")||a.includes("pgtimestamp")||a.includes("pgdate")||a.includes("mysqltimestamp")||a.includes("mysqldate")||a.includes("sqlitetimestamp")||c.includes("timestamp")||c.includes("date"))&&e.add(t);}return e}function ke(o,e){if(e.size===0)return o;let n=o.shape,t={};for(let[r,i]of Object.entries(n))if(e.has(r)){let s=i.isOptional?.()??false,a=i.isNullable?.()??false,l=vt;(a||s)&&(l=St),s&&(l=l.optional()),t[r]=l;}else t[r]=i;return z$1.object(t)}var Ln={CreateEndpoint:j,ListEndpoint:A,ReadEndpoint:P,UpdateEndpoint:I,DeleteEndpoint:_,RestoreEndpoint:F,BatchCreateEndpoint:q,BatchUpdateEndpoint:U,BatchDeleteEndpoint:Z,BatchRestoreEndpoint:L,BatchUpsertEndpoint:$,SearchEndpoint:K,AggregateEndpoint:le,ExportEndpoint:de,ImportEndpoint:ce,UpsertEndpoint:N,CloneEndpoint:ue,BulkPatchEndpoint:re,VersionHistoryEndpoint:oe,VersionReadEndpoint:ie,VersionCompareEndpoint:se,VersionRollbackEndpoint:ae};export{Ke as DRIZZLE_DIALECTS,Ln as DrizzleAdapters,le as DrizzleAggregateEndpoint,q as DrizzleBatchCreateEndpoint,Z as DrizzleBatchDeleteEndpoint,L as DrizzleBatchRestoreEndpoint,U as DrizzleBatchUpdateEndpoint,$ as DrizzleBatchUpsertEndpoint,re as DrizzleBulkPatchEndpoint,ue as DrizzleCloneEndpoint,j as DrizzleCreateEndpoint,_ as DrizzleDeleteEndpoint,de as DrizzleExportEndpoint,ce as DrizzleImportEndpoint,A as DrizzleListEndpoint,P as DrizzleReadEndpoint,F as DrizzleRestoreEndpoint,K as DrizzleSearchEndpoint,I as DrizzleUpdateEndpoint,N as DrizzleUpsertEndpoint,se as DrizzleVersionCompareEndpoint,oe as DrizzleVersionHistoryEndpoint,ie as DrizzleVersionReadEndpoint,ae as DrizzleVersionRollbackEndpoint,v as batchLoadDrizzleRelations,W as buildWhereCondition,G as cast,yn as createDrizzleCrud,kt as createDrizzleSchemas,Tt as createInsertSchema,Et as createSelectSchema,xt as createUpdateSchema,p as getColumn,z as getTable,Ot as isDrizzleZodAvailable,Qe as loadDrizzleRelation,fe as loadDrizzleRelations,S as readCount,B as substringMatch};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hono-crud/drizzle",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Drizzle ORM CRUD adapter for hono-crud",
|
|
5
5
|
"author": "Kauan Guesser <contato@kauan.net>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"drizzle-zod": ">=0.8.0",
|
|
48
48
|
"hono": ">=4.11.7 <5",
|
|
49
49
|
"zod": ">=4.0.0",
|
|
50
|
-
"hono-crud": "^0.13.
|
|
50
|
+
"hono-crud": "^0.13.19"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"drizzle-orm": "^0.45.1",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"tsup": "^8.4.0",
|
|
57
57
|
"typescript": "^5.8.3",
|
|
58
58
|
"zod": "^4.3.5",
|
|
59
|
-
"hono-crud": "0.13.
|
|
59
|
+
"hono-crud": "0.13.19"
|
|
60
60
|
},
|
|
61
61
|
"peerDependenciesMeta": {
|
|
62
62
|
"drizzle-zod": {
|