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