Prototype Specification
In Fivetran HVR, a "prototype" is a pattern used to specify a complex object, such as the JSON body of a REST request or REST response. Prototype checking implemented inside HVR and prototypes are used to describe and document HVR REST-calls. This is because their range of types is tailored for HVR and (compared to alternatives) they have a concise and powerful grammar.
Syntax
A prototype can contain the following:
Syntax | Description |
---|---|
TYPE? | Matches element if it occurs zero or one times. |
TYPE* | Matches element if it occurs zero, one or more times. |
TYPE+ | Matches element if it occurs one or more times. |
(TYPES) | Matches an array (list). |
{KEY:TYPE[STUFF] } | Matches a JSON object such as {"a":1,"b":2} or an array of name/value arrays such as [["a",1],["b",2]] . |
{KEY?:TYPE[STUFF] } | Matches a JSON object except KEY is optional. |
{ name<str>*:TYPE} | Matches a JSON object with key (name) can occur zero, one or multiple times. For example prototype { table<str> *: <int> } matches JSON { "tab":33, "tbl2":0, "x":99 } . |
{ name<str>+:TYPE} | Similar to *: except the key must occur one or more times, it is not optional. |
TYPE1|TYPE2 | Matches if either TYPE1 or TYPE2 matches. |
<str> | Matches any string. |
<str aa bb> | Matches strings aa and bb . |
'aa' | Matches string aa . Same as <str aa> . |
<ident> | Identifiers are strings which start with alphabetic or underscore, followed by alphanumeric or underscore. |
<other> | Matches any name not yet used in {} object. |
<int> | A 32-bit integer (between -2,147,483,648 and 2,147,483,647). |
<bool> | Matches integers 0, 1 as well as JSON's true and false. |
<int64_ascii> | Matches an ASCII string containing a 64-bit integer. |
<float64_ascii> | Matches an ASCII string containing a float number. |
<date_int> | An "epoch integer" representing the number of seconds since midnight 1970, UTC. It also matches ISO 8601 format's UTC style, such as "2018-02-05T12:20:00Z". |
<date_str_z> | Matches a date/time in ISO 8601 format's UTC style, such as "2018-02-05T12:20:00Z". It also matches "epoch integers" representing the number of seconds since midnight 1970, UTC. |
<date_str_usecs_z> | Matches a date/time in ISO 8601 format’s UTC style including microseconds, such as "2018-02-05T12:20:00.123Z". It also matches "microsecond epoch integers" representing the number of microseconds since midnight 1970, UTC. |
<scal> | Matches anything except an array (list) or JSON object. |
<list> | Matches any array (list) or JSON object. |
<nullMAGIC> | Matches JSON's null. Value MAGIC (either &0, (), NUM or STR) controls how the values coerced to a list. |
<any> | Matches any element. |
[-x] | Matches a single-letter POSIX-style command-line option, such as ["-x"] . |
[-xTYPE] | Matches a POSIX-style command-line option with an argument such as ["-x", 22] . |
[OPTIONS]--TYPES | The double-hyphen signifies the end of POSIX-style command-line option matching. |
Prototype Coercion
Prototypes support coercion, so if a REST call has request prototype **(\<int\>\*)**
is called with JSON [1, "2", 3]
then it will coerce the request to list of integers, rather than give an mismatch. Likewise, REST endpoints with types \<date_int\>
and \<date_str_z\>
can both be supplied either 59
or "1970-01-01T00:00:59Z"
Examples
Example 1: Prototype
**(\<int\>\*)**
matches JSON[2, 3, 4]
\<int\>
matches any integer,\*
means that integer must occur zero or more times.()
means the whole thing must be in an array. So arrays are()
in prototypes, not[]
.
Example 2: Prototype
((tabid\<int\>+) {'fname':\<str\> 'readonly' ?:\<bool\>})
matches JSON[[2, 3], {"fname":"/tmp/xx", "readonly":false}]
Type
\<int\>
is preceded by a nametabid
. See this as a comment, to assist readability.{}
in the prototypes matches the JSON object. Note that no comma are used.The prototype has literal strings like
'fname'
but these are single-quoted, whereas JSON uses double-quotes.This prototype does not match JSON
[[], {"fname":"xx", "readonly":false}]
because(\<int\>+)
means the array needs one of more objects. It would match prototype contained**(\<int\>\*)**
instead.The prototype has
?:
so key"readonly"
is optional and therefore matches[[2, 3], {"fname":"/tmp/xx"}]
but not[[2, 3], {"readonly":false}]
The prototype matches
[[2, 3], {"readonly":false, "fname":"/tmp/xx"}]
because the order of attributes in a JSON object is not significant.This prototype does not match
[[2, 3], {"fname":"xx", "readwrite": true}]
because attribute"readwrite"
is not a named in the prototype. Matching of extra attributes is allowed if\<other\>
is added, for example prototype{'fname':\<str\> 'readonly'?:\<bool\> \<other\>?:\<any\>}
.