Software / code / prosody
Comparison
teal-src/util/datamapper.tl @ 11461:766b0eddd12c
util.datamapper: Deal with type name changes in util.jsonschema
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Fri, 19 Mar 2021 00:26:04 +0100 |
| parent | 11459:86904555bffc |
| child | 11462:d1982b7eb00d |
comparison
equal
deleted
inserted
replaced
| 11460:a8b4e04bc044 | 11461:766b0eddd12c |
|---|---|
| 19 -- TODO cleanup / refactor | 19 -- TODO cleanup / refactor |
| 20 -- TODO s/number/integer/ once we have appropriate math.type() compat | 20 -- TODO s/number/integer/ once we have appropriate math.type() compat |
| 21 -- | 21 -- |
| 22 | 22 |
| 23 local st = require "util.stanza"; | 23 local st = require "util.stanza"; |
| 24 local js = require "util.jsonschema" | 24 local json = require"util.json" |
| 25 | |
| 26 local json_type_name = json.json_type_name; | |
| 27 local json_schema_object = require "util.jsonschema" | |
| 28 local type schema_t = boolean | json_type_name | json_schema_object | |
| 25 | 29 |
| 26 local function toboolean ( s : string ) : boolean | 30 local function toboolean ( s : string ) : boolean |
| 27 if s == "true" or s == "1" then | 31 if s == "true" or s == "1" then |
| 28 return true | 32 return true |
| 29 elseif s == "false" or s == "0" then | 33 elseif s == "false" or s == "0" then |
| 31 elseif s then | 35 elseif s then |
| 32 return true | 36 return true |
| 33 end | 37 end |
| 34 end | 38 end |
| 35 | 39 |
| 36 local function totype(t : js.schema_t.type_e, s : string) : any | 40 local function totype(t : json_type_name, s : string) : any |
| 37 if t == "string" then | 41 if t == "string" then |
| 38 return s; | 42 return s; |
| 39 elseif t == "boolean" then | 43 elseif t == "boolean" then |
| 40 return toboolean(s) | 44 return toboolean(s) |
| 41 elseif t == "number" or t == "integer" then | 45 elseif t == "number" or t == "integer" then |
| 51 "in_single_attribute" | 55 "in_single_attribute" |
| 52 "in_children" | 56 "in_children" |
| 53 "in_wrapper" | 57 "in_wrapper" |
| 54 end | 58 end |
| 55 | 59 |
| 56 local function unpack_propschema( propschema : js.schema_t | js.schema_t.type_e, propname : string, current_ns : string ) | 60 local function unpack_propschema( propschema : schema_t, propname : string, current_ns : string ) |
| 57 : js.schema_t.type_e, value_goes, string, string, string, string, { any } | 61 : json_type_name, value_goes, string, string, string, string, { any } |
| 58 local proptype : js.schema_t.type_e = "string" | 62 local proptype : json_type_name = "string" |
| 59 local value_where : value_goes = "in_text_tag" | 63 local value_where : value_goes = "in_text_tag" |
| 60 local name = propname | 64 local name = propname |
| 61 local namespace = current_ns | 65 local namespace = current_ns |
| 62 local prefix : string | 66 local prefix : string |
| 63 local single_attribute : string | 67 local single_attribute : string |
| 64 local enums : { any } | 68 local enums : { any } |
| 65 | 69 |
| 66 if propschema is js.schema_t then | 70 if propschema is json_schema_object then |
| 67 proptype = propschema.type | 71 proptype = propschema.type |
| 68 elseif propschema is js.schema_t.type_e then | 72 elseif propschema is json_type_name then |
| 69 proptype = propschema | 73 proptype = propschema |
| 70 end | 74 end |
| 71 | 75 |
| 72 if proptype == "object" or proptype == "array" then | 76 if proptype == "object" or proptype == "array" then |
| 73 value_where = "in_children" | 77 value_where = "in_children" |
| 74 end | 78 end |
| 75 | 79 |
| 76 if propschema is js.schema_t then | 80 if propschema is json_schema_object then |
| 77 local xml = propschema.xml | 81 local xml = propschema.xml |
| 78 if xml then | 82 if xml then |
| 79 if xml.name then | 83 if xml.name then |
| 80 name = xml.name | 84 name = xml.name |
| 81 end | 85 end |
| 106 end | 110 end |
| 107 | 111 |
| 108 return proptype, value_where, name, namespace, prefix, single_attribute, enums | 112 return proptype, value_where, name, namespace, prefix, single_attribute, enums |
| 109 end | 113 end |
| 110 | 114 |
| 111 local parse_object : function (schema : js.schema_t, s : st.stanza_t) : { string : any } | 115 local parse_object : function (schema : schema_t, s : st.stanza_t) : { string : any } |
| 112 local parse_array : function (schema : js.schema_t, s : st.stanza_t) : { any } | 116 local parse_array : function (schema : schema_t, s : st.stanza_t) : { any } |
| 113 | 117 |
| 114 function parse_object (schema : js.schema_t, s : st.stanza_t) : { string : any } | 118 function parse_object (schema : schema_t, s : st.stanza_t) : { string : any } |
| 115 local out : { string : any } = {} | 119 local out : { string : any } = {} |
| 116 if schema.properties then | 120 if schema is json_schema_object and schema.properties then |
| 117 for prop, propschema in pairs(schema.properties) do | 121 for prop, propschema in pairs(schema.properties) do |
| 118 | 122 |
| 119 local proptype, value_where, name, namespace, prefix, single_attribute, enums = unpack_propschema(propschema, prop, s.attr.xmlns) | 123 local proptype, value_where, name, namespace, prefix, single_attribute, enums = unpack_propschema(propschema, prop, s.attr.xmlns) |
| 120 | 124 |
| 121 local value : string | 125 local value : string |
| 150 elseif value_where == "in_single_attribute" then | 154 elseif value_where == "in_single_attribute" then |
| 151 local c = s:get_child(name, namespace) | 155 local c = s:get_child(name, namespace) |
| 152 value = c and c.attr[single_attribute] | 156 value = c and c.attr[single_attribute] |
| 153 elseif value_where == "in_text_tag" then | 157 elseif value_where == "in_text_tag" then |
| 154 value = s:get_child_text(name, namespace) | 158 value = s:get_child_text(name, namespace) |
| 155 elseif value_where == "in_children" and propschema is js.schema_t then | 159 elseif value_where == "in_children" and propschema is json_schema_object then |
| 156 if proptype == "object" then | 160 if proptype == "object" then |
| 157 local c = s:get_child(name, namespace) | 161 local c = s:get_child(name, namespace) |
| 158 if c then | 162 if c then |
| 159 out[prop] = parse_object(propschema, c); | 163 out[prop] = parse_object(propschema, c); |
| 160 end | 164 end |
| 161 elseif proptype == "array" then | 165 elseif proptype == "array" then |
| 162 out[prop] = parse_array(propschema, s); | 166 out[prop] = parse_array(propschema, s); |
| 163 else | 167 else |
| 164 error "unreachable" | 168 error "unreachable" |
| 165 end | 169 end |
| 166 elseif value_where == "in_wrapper" and propschema is js.schema_t and proptype == "array" then | 170 elseif value_where == "in_wrapper" and propschema is json_schema_object and proptype == "array" then |
| 167 local wrapper = s:get_child(name, namespace); | 171 local wrapper = s:get_child(name, namespace); |
| 168 if wrapper then | 172 if wrapper then |
| 169 out[prop] = parse_array(propschema, wrapper); | 173 out[prop] = parse_array(propschema, wrapper); |
| 170 else | 174 else |
| 171 error "unreachable" | 175 error "unreachable" |
| 172 end | 176 end |
| 173 else | 177 else |
| 174 error "unreachable" | 178 error "unreachable" |
| 175 end | 179 end |
| 176 if value_where ~= "in_children" and value_where ~= "in_wrapper" then | 180 if value_where ~= "in_children" and value_where ~= "in_wrapper" then |
| 177 out[prop] = totype(proptype, value) | 181 out[prop] = totype(proptype, value) |
| 180 end | 184 end |
| 181 | 185 |
| 182 return out | 186 return out |
| 183 end | 187 end |
| 184 | 188 |
| 185 function parse_array (schema : js.schema_t, s : st.stanza_t) : { any } | 189 function parse_array (schema : json_schema_object, s : st.stanza_t) : { any } |
| 186 local proptype, value_where, child_name, namespace = unpack_propschema(schema.items, nil, s.attr.xmlns) | 190 local proptype, value_where, child_name, namespace = unpack_propschema(schema.items, nil, s.attr.xmlns) |
| 187 local out : { any } = {} | 191 local out : { any } = {} |
| 188 for c in s:childtags(child_name, namespace) do | 192 for c in s:childtags(child_name, namespace) do |
| 189 local value : string; | 193 local value : string; |
| 190 if value_where == "in_text_tag" then | 194 if value_where == "in_text_tag" then |
| 200 end | 204 end |
| 201 end | 205 end |
| 202 return out; | 206 return out; |
| 203 end | 207 end |
| 204 | 208 |
| 205 local function parse (schema : js.schema_t, s : st.stanza_t) : table | 209 local function parse (schema : json_schema_object, s : st.stanza_t) : table |
| 206 if schema.type == "object" then | 210 if schema.type == "object" then |
| 207 return parse_object(schema, s) | 211 return parse_object(schema, s) |
| 208 elseif schema.type == "array" then | 212 elseif schema.type == "array" then |
| 209 return parse_array(schema, s) | 213 return parse_array(schema, s) |
| 210 else | 214 else |
| 211 error "top-level scalars unsupported" | 215 error "top-level scalars unsupported" |
| 212 end | 216 end |
| 213 end | 217 end |
| 214 | 218 |
| 215 local function unparse ( schema : js.schema_t, t : table, current_name : string, current_ns : string ) : st.stanza_t | 219 local function unparse ( schema : json_schema_object, t : table, current_name : string, current_ns : string ) : st.stanza_t |
| 216 | 220 |
| 217 if schema.xml then | 221 if schema.xml then |
| 218 if schema.xml.name then | 222 if schema.xml.name then |
| 219 current_name = schema.xml.name | 223 current_name = schema.xml.name |
| 220 end | 224 end |
| 221 if schema.xml.namespace then | 225 if schema.xml.namespace then |
| 222 current_ns = schema.xml.namespace | 226 current_ns = schema.xml.namespace |
| 223 end | 227 end |
| 224 -- TODO prefix? | 228 -- TODO prefix? |
| 225 end | 229 end |
| 226 | 230 |
| 227 local out = st.stanza(current_name, { xmlns = current_ns }) | 231 local out = st.stanza(current_name, { xmlns = current_ns }) |
| 228 | 232 |
| 229 if schema.type == "object" then | 233 if schema.type == "object" then |
| 230 | 234 |
| 231 for prop, propschema in pairs(schema.properties) do | 235 for prop, propschema in pairs(schema.properties) do |
| 232 local v = t[prop] | 236 local v = t[prop] |
| 291 out:text_tag(name, string.format("%g", v), propattr) | 295 out:text_tag(name, string.format("%g", v), propattr) |
| 292 elseif proptype == "integer" and v is number then -- TODO is integer | 296 elseif proptype == "integer" and v is number then -- TODO is integer |
| 293 out:text_tag(name, string.format("%d", v), propattr) | 297 out:text_tag(name, string.format("%d", v), propattr) |
| 294 elseif proptype == "boolean" and v is boolean then | 298 elseif proptype == "boolean" and v is boolean then |
| 295 out:text_tag(name, v and "1" or "0", propattr) | 299 out:text_tag(name, v and "1" or "0", propattr) |
| 296 elseif proptype == "object" and propschema is js.schema_t and v is table then | 300 elseif proptype == "object" and propschema is json_schema_object and v is table then |
| 297 local c = unparse(propschema, v, name, namespace); | 301 local c = unparse(propschema, v, name, namespace); |
| 298 if c then | 302 if c then |
| 299 out:add_direct_child(c); | 303 out:add_direct_child(c); |
| 300 end | 304 end |
| 301 elseif proptype == "array" and propschema is js.schema_t and v is table then | 305 elseif proptype == "array" and propschema is json_schema_object and v is table then |
| 302 local c = unparse(propschema, v, name, namespace); | 306 local c = unparse(propschema, v, name, namespace); |
| 303 if c then | 307 if c then |
| 304 if value_where == "in_wrapper" then | 308 if value_where == "in_wrapper" then |
| 305 local w = st.stanza(propschema.xml.name or name, { xmlns = propschema.xml.namespace or namespace }) | 309 local w = st.stanza(propschema.xml.name or name, { xmlns = propschema.xml.namespace or namespace }) |
| 306 w:add_direct_child(c); | 310 w:add_direct_child(c); |