Software /
code /
prosody
Comparison
util/datamapper.lua @ 12580:a9dbf657c894 0.12
util.datamapper: Improve handling of schemas with non-obvious "type"
The JSON Schema specification says that schemas are objects or booleans,
and that the 'type' property is optional and can be an array.
This module previously allowed bare type names as schemas and did not
really handle booleans.
It now handles missing 'type' properties and boolean 'true' as a schema.
Objects and arrays are guessed based on the presence of 'properties' or
'items' field.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Fri, 08 Jul 2022 17:32:48 +0200 |
parent | 12133:11060c8919b6 |
child | 12782:8815d3090928 |
comparison
equal
deleted
inserted
replaced
12579:ca6a43fe0231 | 12580:a9dbf657c894 |
---|---|
1 -- This file is generated from teal-src/util/datamapper.lua | |
2 | |
1 local st = require("util.stanza"); | 3 local st = require("util.stanza"); |
2 local pointer = require("util.jsonpointer"); | 4 local pointer = require("util.jsonpointer"); |
3 | 5 |
4 local schema_t = {} | 6 local schema_t = {} |
5 | 7 |
27 end | 29 end |
28 | 30 |
29 local value_goes = {} | 31 local value_goes = {} |
30 | 32 |
31 local function resolve_schema(schema, root) | 33 local function resolve_schema(schema, root) |
32 if type(schema) == "table" and schema["$ref"] and schema["$ref"]:sub(1, 1) == "#" then | 34 if type(schema) == "table" then |
33 local referenced = pointer.resolve(root, schema["$ref"]:sub(2)); | 35 if schema["$ref"] and schema["$ref"]:sub(1, 1) == "#" then |
34 if referenced ~= nil then | 36 return pointer.resolve(root, schema["$ref"]:sub(2)) |
35 return referenced | |
36 end | 37 end |
37 end | 38 end |
38 return schema | 39 return schema |
40 end | |
41 | |
42 local function guess_schema_type(schema) | |
43 local schema_types = schema.type | |
44 if type(schema_types) == "string" then | |
45 return schema_types | |
46 elseif schema_types ~= nil then | |
47 error("schema has unsupported 'type' property") | |
48 elseif schema.properties then | |
49 return "object" | |
50 elseif schema.items then | |
51 return "array" | |
52 end | |
53 return "string" | |
39 end | 54 end |
40 | 55 |
41 local function unpack_propschema(propschema, propname, current_ns) | 56 local function unpack_propschema(propschema, propname, current_ns) |
42 | 57 |
43 local proptype = "string" | 58 local proptype = "string" |
47 local prefix | 62 local prefix |
48 local single_attribute | 63 local single_attribute |
49 local enums | 64 local enums |
50 | 65 |
51 if type(propschema) == "table" then | 66 if type(propschema) == "table" then |
52 proptype = propschema.type | 67 proptype = guess_schema_type(propschema); |
53 elseif type(propschema) == "string" then | 68 elseif type(propschema) == "string" then |
54 proptype = propschema | 69 error("schema as string is not supported: " .. propschema .. " {" .. current_ns .. "}" .. propname) |
55 end | 70 end |
56 | 71 |
57 if proptype == "object" or proptype == "array" then | 72 if proptype == "object" or proptype == "array" then |
58 value_where = "in_children" | 73 value_where = "in_children" |
59 end | 74 end |
207 end | 222 end |
208 return out | 223 return out |
209 end | 224 end |
210 | 225 |
211 local function parse(schema, s) | 226 local function parse(schema, s) |
212 if schema.type == "object" then | 227 local s_type = guess_schema_type(schema) |
228 if s_type == "object" then | |
213 return parse_object(schema, s, schema) | 229 return parse_object(schema, s, schema) |
214 elseif schema.type == "array" then | 230 elseif s_type == "array" then |
215 return parse_array(schema, s, schema) | 231 return parse_array(schema, s, schema) |
216 else | 232 else |
217 error("top-level scalars unsupported") | 233 error("top-level scalars unsupported") |
218 end | 234 end |
219 end | 235 end |
304 | 320 |
305 end | 321 end |
306 | 322 |
307 local out = ctx or st.stanza(current_name, {xmlns = current_ns}) | 323 local out = ctx or st.stanza(current_name, {xmlns = current_ns}) |
308 | 324 |
309 if schema.type == "object" then | 325 local s_type = guess_schema_type(schema) |
326 if s_type == "object" then | |
310 | 327 |
311 for prop, propschema in pairs(schema.properties) do | 328 for prop, propschema in pairs(schema.properties) do |
312 propschema = resolve_schema(propschema, root) | 329 propschema = resolve_schema(propschema, root) |
313 local v = t[prop] | 330 local v = t[prop] |
314 | 331 |
317 unparse_property(out, v, proptype, propschema, value_where, name, namespace, current_ns, prefix, single_attribute, root) | 334 unparse_property(out, v, proptype, propschema, value_where, name, namespace, current_ns, prefix, single_attribute, root) |
318 end | 335 end |
319 end | 336 end |
320 return out | 337 return out |
321 | 338 |
322 elseif schema.type == "array" then | 339 elseif s_type == "array" then |
323 local itemschema = resolve_schema(schema.items, root) | 340 local itemschema = resolve_schema(schema.items, root) |
324 local proptype, value_where, name, namespace, prefix, single_attribute = unpack_propschema(itemschema, current_name, current_ns) | 341 local proptype, value_where, name, namespace, prefix, single_attribute = unpack_propschema(itemschema, current_name, current_ns) |
325 for _, item in ipairs(t) do | 342 for _, item in ipairs(t) do |
326 unparse_property(out, item, proptype, itemschema, value_where, name, namespace, current_ns, prefix, single_attribute, root) | 343 unparse_property(out, item, proptype, itemschema, value_where, name, namespace, current_ns, prefix, single_attribute, root) |
327 end | 344 end |