number
A number is a signed 32-bit integer: floats 400, 2**31 is "integer out of range", and 0 is not null, yet is_not and not_in match null rows while greater_than and less_than do not.
Data type number, probed on Version.frame_count and Version.sg_first_frame (stock, editable).
Also stock and editable on Version: sg_last_frame. The schema declares no range: properties holds only
default_value (null here) and summary_default.
Read A plain JSON integer under attributes, never a string and never wrapped. An unset field is
null, not 0 and not absent.
id=<n> sg_first_frame=1001(int) sg_last_frame=1100(int) frame_count=100(int)
Write PUT /entity/versions/<id> with Content-Type: application/json and a bare
{"frame_count": 42}; POST /entity/versions takes the same value shape. The API states its own accepted
set in the rejection: [String, Integer, NilClass].
| sent | result |
|---|---|
42 |
200, reads back 42 |
'42' |
200, reads back 42; coerced to int, no error |
-7 |
200, reads back -7 |
null |
200, reads back None |
3.7 / 3.2 / -3.7 |
400 API update() Version.frame_count expected [String, Integer, NilClass] data type(s) but got Float: 3.7; no truncation, no rounding |
True |
400 ... but got TrueClass: true |
'42abc' |
400 title Invalid data for 'number' data type; source {"frame_count": "Invalid data for 'number' data type. Value: 42abc"} |
'' |
400 source {"frame_count": "Invalid data for 'number' data type. Value: "} |
Range A signed 32-bit integer.
| sent | result |
|---|---|
2147483647 (2**31-1) |
200, reads back exactly |
2147483648 (2**31) |
400 |
4294967295 / 2**63-1 / 2**63 |
400 |
-2147483648 (-(2**31)) |
200, reads back exactly |
-2147483649 |
400 |
-(2**63) |
400 |
"2147483648" as a numeric string |
400; a string does not route around the ceiling |
The two verbs fail differently on 2147483648:
| verb | body |
|---|---|
PUT |
{"status": 400, "code": 104, "title": "Update failed for [Version.frame_count]: Invalid statement.", "source": null, "detail": null, "meta": null} |
POST |
{"status": 400, "code": 104, "title": "Create failed for [Version]: PG::NumericValueOutOfRange: ERROR: integer out of range\n", "source": null, "detail": null, "meta": {"crud_error_uuid": "<uuid>"}} |
Clear
| sent | result |
|---|---|
null |
200, reads back None |
0 |
200, reads back 0 |
'' |
400 Invalid data for 'number' data type. Value: |
| field never set on create | reads None |
null clears; 0 is a value. They are distinct on write, on read and under a filter.
Filter POST /entity/versions/_search, Content-Type: application/vnd+shotgun.api3_array+json.
A bogus relation 400s with the whole vocabulary (probe 017):
Valid relations: ["is", "is_not", "greater_than", "less_than", "between", "in", "not_in"]
contains, starts_with, ends_with and not_between are all absent, and each 400s with that same list.
There is no >= or <=. Bracket with between, or shift the bound by one.
Match counts are against 4 sandbox rows holding 1001, 0, null, null.
| operator | value | matches |
|---|---|---|
is |
1001 |
1 |
is |
0 |
1 |
is |
'1001' |
1 |
is |
None |
2; 0 is not matched |
is_not |
1001 |
3 |
is_not |
None |
2 |
greater_than |
0 |
1 |
greater_than |
-1 |
2 |
less_than |
1 |
1 |
less_than |
1001 |
1 |
in |
[1001, 0] |
2 |
in |
['1001'] |
1 |
in |
[999999] |
0 (negative control) |
not_in |
[1001] |
3 |
not_in |
[999999] |
4 |
between |
[0, 2000] |
2 |
between |
[2000, 3000] |
0 (negative control) |
between |
1001 |
400 API read() 'between' 'relation' expects a 2-element array: [1001] |
contains |
'100' |
400 API read() Version.sg_first_frame's 'number' data type doesn't support 'contains' 'relation' |
The contains 400 in full. source opens mid-sentence, without the title's
API read() Version.sg_first_frame's 'number' prefix, then gives the sent filter and the legal list:
source: {"Version.sg_first_frame": " data type doesn't support 'contains' 'relation'.
Value: {"path" => "sg_first_frame", "relation" => "contains", "values" => ["100"]}
Valid relations: ["is", "is_not", "greater_than", "less_than", "between",
"in", "not_in"]"}
Traps
- Signed 32-bit, not 64. A 64-bit id or seed reaches
2**64-1and must be stored in atextfield (probe 019saw the same ceiling on a created field). The create path names the cause,PG::NumericValueOutOfRange; the update path says onlyInvalid statement. - A float is rejected, not coerced.
int()anything computed (a mean, a ratio,n/2in Python 3) before writing it. A numeric string coerces, so"42"works and42.0does not. 0is a value,''is not a clear.nullis the only clear. Followingprobe 007: a row holding0isis_not None, so a number field full of zeroes scans as 100% filled, exactly like a checkbox full ofFalse. Rank a number field bygreater_than 0, or by_summarizegrouping (probe 020), never by fill rate.- Negation includes nulls; comparison excludes them.
is_not 1001andnot_in [999999]return the null rows too (3 and 4 of 4), whilegreater_than -1returns only the 2 rows that hold a value. Any "everything except X" filter over a sparse number field silently sweeps in every unset row.