@inixiative/json-rules 2.19.5 → 2.19.6

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/README.md CHANGED
@@ -101,6 +101,8 @@ Supported comparison operators for aggregate rules: `equals`, `notEquals`, `less
101
101
  - `after`
102
102
  - `onOrBefore`
103
103
  - `onOrAfter`
104
+ - `notBefore`
105
+ - `notAfter`
104
106
  - `within`
105
107
  - `notWithin`
106
108
  - `between`
@@ -221,13 +223,18 @@ absolute date. Magnitudes are always **positive** — direction lives in the key
221
223
  Units are dayjs words: `day`, `week`, `isoWeek`, `month`, `quarter`, `year`,
222
224
  `hour`, `minute`, `second`.
223
225
 
224
- **Point expressions** — pair with `before` / `after` / `onOrBefore` / `onOrAfter`,
226
+ **Point expressions** — pair with `before` / `after` / `onOrBefore` / `onOrAfter` /
227
+ `notBefore` / `notAfter`,
225
228
  or as `between` endpoints:
226
229
 
227
230
  ```ts
228
231
  // "more than 30 days ago"
229
232
  { field: 'completedAt', dateOperator: DateOperator.before, value: { ago: { days: 30 } } }
230
233
 
234
+ // "not since 30 days ago" — on/before the point OR never (notAfter is the null-carrying
235
+ // complement of after; onOrBefore is positive and skips NULL). Takes a literal date too.
236
+ { field: 'lastLoginAt', dateOperator: DateOperator.notAfter, value: { ago: { days: 30 } } }
237
+
231
238
  // "within the next 2 months"
232
239
  { field: 'dueAt', dateOperator: DateOperator.after, value: { ahead: { months: 2 } } }
233
240
 
@@ -536,7 +543,7 @@ Without `{ map, model }`, or on an entry that doesn't declare it, the bare
536
543
  Date rules follow the same split. The positive operators answer non-match on both
537
544
  rails — a bare boundary is not something a NULL column satisfies, so `check()`
538
545
  reports the rule's ordinary non-match (honoring `error`) and the compilers keep the
539
- bare `<` / `BETWEEN`. The negative-flavored ones (`notWithin`, `notBetween`, `dayNotIn`) follow
546
+ bare `<` / `BETWEEN`. The negative-flavored ones (`notBefore`, `notAfter`, `notWithin`, `notBetween`, `dayNotIn`) follow
540
547
  the negation ruling instead: a never-set date is not in the range, so a null column
541
548
  MATCHES, and the compilers carry the `IS NULL` arm. To match never-seen rows under a
542
549
  positive operator, ask for them:
@@ -545,6 +552,7 @@ positive operator, ask for them:
545
552
  | Rule | `check()` on `{ col: null }` | `toSql()` | `toPrisma()` |
546
553
  | --- | --- | --- | --- |
547
554
  | positive `dateOperator` (`before`, `between`, `dayIn`, …) | no match | `col < $1` (NULL never satisfies) | `{ col: { lt: … } }` |
555
+ | `notAfter X` / `notBefore X` | matches | `(col <= $1 OR col IS NULL)` / `(col >= $1 OR col IS NULL)` | `{ OR: [{ col: { lte } }, { col: { equals: null } }] }` (nullable column) |
548
556
  | `notWithin { ago: { days: 30 } }` | matches | `(col NOT BETWEEN $1 AND $2 OR col IS NULL)` | `{ OR: [{ col: { NOT: { gte, lte } } }, { col: { equals: null } }] }` (nullable column) |
549
557
  | `notBetween` | matches | `(col NOT BETWEEN $1 AND $2 OR col IS NULL)` | `{ OR: [{ col: { NOT: … } }, { col: { equals: null } }] }` (nullable column, same field-map licensing as above) |
550
558
  | `dayNotIn` | matches | `(EXTRACT(DOW FROM col) <> ALL($1) OR col IS NULL)` | — (no Prisma output) |