ReviewOS

also looking at this

stacks/bun-query-builder

fix(browser): stop serialising an exclusion as an inclusion

#1108
Merged glennmichael123 wants to merge fix/1096-browser-not-in into main
2 files +115 -1
packages/bun-query-builder/src/browser.tsmodified+16-1
Changes to packages/bun-query-builder/src/browser.ts
@@ -525,11 +525,15 @@ export class BrowserQueryBuilder<T = any> {
525525 private buildQueryParams(): URLSearchParams {
526526 const params = new URLSearchParams()
527527
528 // As in BrowserModelQueryBuilder: `boolean` is not read, so an `orWhere`
529 // serialises as an AND. Left alone deliberately — see #1096.
528530 // Add where clauses as query params
529531 for (const where of this.state.wheres) {
530532 if (where.operator === '=') {
531533 params.append(where.column, String(where.value))
532534 }
535 // `in` only — `not in` falls through to the filter branch, so an
536 // exclusion stays distinguishable from an inclusion (#1096).
533537 else if (where.operator === 'in' && Array.isArray(where.value)) {
534538 params.append(`${where.column}[]`, where.value.join(','))
535539 }
@@ -970,11 +974,22 @@ else {
970974 private buildQueryParams(): URLSearchParams {
971975 const params = new URLSearchParams()
972976
977 // `where.boolean` is not read here, so an `orWhere` serialises exactly like
978 // a `where` and the server reads it as AND. Representing OR needs a wire
979 // format that this file has no precedent for, so it is left alone rather
980 // than invented — see #1096. BrowserQueryBuilder.buildQueryParams has the
981 // same gap.
973982 for (const where of this._wheres) {
974983 if (where.operator === '=') {
975984 params.append(where.column, String(where.value))
976985 }
977else if ((where.operator === 'in' || where.operator === 'not in') && Array.isArray(where.value)) {
986 // `in` only. Including `not in` here made an exclusion serialise
987 // byte-identically to an inclusion — `whereNotIn('role', ['banned'])`
988 // and `whereIn('role', ['banned'])` both sent `role[]=banned`, so the
989 // server returned precisely the rows the caller meant to exclude.
990 // Falling through to the filter branch below is what the sibling
991 // BrowserQueryBuilder already does. See #1096.
992 else if (where.operator === 'in' && Array.isArray(where.value)) {
978993 params.append(`${where.column}[]`, where.value.join(','))
979994 }
980995else if (where.operator === 'is' && where.value === null) {