Repository navigation
schema-calc v0.2.0
Coefficients and inequalities. A contract can now multiply a field by a whole number and compare two sides with <=, >=, < or >, so an ordinary validator can check discount <= subtotal, or that each share is a third of the total rounded down to the cent. The shipped examples compile to byte-identical schemas; a 0.1.1 contract changes only if part of its schema held more than 2,000 subschemas without a reference. Try it in any browser; nothing is sent to a server.
What's new
- Whole-number coefficients, written
3 * priceorprice * 3, from 1 to 1,000. Products of fields and decimal coefficients are refused with a clear message. The schema grows with the coefficient:total = k * price + shippingwith four integer and two fractional digits is 21 kB atk= 1, 80 kB at 10, 401 kB at 100 and 751 kB at 1,000. - Inequalities.
>=and>negate both sides, and a strict comparison adds one minor unit, so every inequality becomessum <= 0. Where an equation rejects a column that leaves a remainder, an inequality carries the remainder rounded up instead (proof). Addingdiscount <= subtotalto the invoice takes it from 41,364 to 46,422 B; a bound such asshipping < 100is about 1 kB. - A fourth example, the even split.
3 * share <= totalandtotal < 3 * share + 0.03accept exactly the share rounded down to the cent: 33.33 of 100.00, but neither 33.32 nor 33.34. It is 26,728 B, or 12,278 B in the tally encoding, and has its own tab in the playground. - At most 2,000 subschemas between references. With a coefficient of 1,000, Ajv's call stack overflowed while validating some records; Ajv and schemasafe compile each such region into one function. Larger regions now move into
$defs, as the 32-level nesting limit already did.compile(spec, { maxSubschemas })sets another limit. No existing example changes. - The tally encoding refuses coefficients above 16, with a message pointing to the flat encoding. Its schema grows roughly with the cube of the coefficient:
total = 16 * price + shippingis 87 kB, and a coefficient of 100 would take megabytes.
Check it without Schema Calc
Python 3 and jsonschema only, in an empty directory:
python3 -m pip install jsonschema==4.25.1
base=https://github.com/fMindstormer/schema-calc/releases/download/v0.2.0
for f in validate.py invoice.schema.json invoice.valid.json invoice.invalid.json; do curl -fLO "$base/$f"; done
python3 validate.py invoice.schema.json invoice.valid.json invoice.invalid.jsonACCEPT invoice.valid.json
REJECT invoice.invalid.json
Validator compatibility
The test corpus grew to 32,000 flat and 31,521 tally records, adding coefficients from 2 to 1,000, exhaustive one-digit comparisons, signed inequalities one unit either side of the boundary, and the even split. All of them pass Ajv and Python jsonschema, and twelve validators in five languages ran them (table). None gave a wrong answer. Nine load every schema. @cfworker/json-schema needs --defs. @exodus/schemasafe times out loading the two largest test schemas, compiled from coefficients of 100 and 1,000 (333 kB and 911 kB); timed separately, it takes 159 s and 11 minutes. jsonschema-rs runs out of memory on the larger flat schemas, as before.
For library users
parseConstraint parses every relation. parseEquation still accepts only equations, because code written against 0.1 reads its result as one.
Files
invoice.schema.json is the compiled invoice contract, unchanged since 0.1.1; invoice.valid.json and invoice.invalid.json are the correct record and the one a cent off. validate.py is the standalone validator: it needs only jsonschema and never imports the compiler. schema-calc-0.2.0.zip is the source, with a MANIFEST.sha256 inside; schema-calc-0.2.0.zip.sha256 is its checksum and SHA256SUMS covers every file.
Scope
Sums and differences of nonnegative decimal strings and their whole-number multiples, related by =, <=, >=, < or >: up to 8 fields, 8 constraints and 12 digits. No products of fields, division, !=, or nested objects and arrays yet. A research prototype; it is not published to npm.