aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKim Alvefur <zash@zash.se>2021-03-18 12:57:25 +0100
committerKim Alvefur <zash@zash.se>2021-03-18 12:57:25 +0100
commitc62c5b307ec907b78f309dbbe90b6569fe91a3f8 (patch)
tree4f94c2f7fd30fc6e47171a5db99bdef6b780e56c
parentfb7df0067cf4a84b1fe7f9145b9aafb0ebae75fa (diff)
downloadprosody-c62c5b307ec907b78f309dbbe90b6569fe91a3f8.tar.gz
prosody-c62c5b307ec907b78f309dbbe90b6569fe91a3f8.zip
util.datamapper: Add initial support for parsing arrays
-rw-r--r--spec/util_datamapper_spec.lua25
-rw-r--r--teal-src/util/datamapper.tl56
-rw-r--r--util/datamapper.lua56
3 files changed, 118 insertions, 19 deletions
diff --git a/spec/util_datamapper_spec.lua b/spec/util_datamapper_spec.lua
index 7f5b71de..aacaf995 100644
--- a/spec/util_datamapper_spec.lua
+++ b/spec/util_datamapper_spec.lua
@@ -46,6 +46,11 @@ describe("util.datampper", function()
type = "string";
xml = {name = "origin-id"; namespace = "urn:xmpp:sid:0"; x_single_attribute = "id"};
};
+ reactions = {
+ type = "array";
+ xml = {namespace = "urn:xmpp:reactions:0"; wrapped = true};
+ items = {type = "string"; xml = {name = "reaction"}};
+ };
};
};
@@ -57,6 +62,10 @@ describe("util.datampper", function()
<active xmlns='http://jabber.org/protocol/chatstates'/>
<fallback xmlns='urn:xmpp:fallback:0'/>
<origin-id xmlns='urn:xmpp:sid:0' id='qgkmMdPB'/>
+ <reactions id='744f6e18-a57a-11e9-a656-4889e7820c76' xmlns='urn:xmpp:reactions:0'>
+ <reaction>👋</reaction>
+ <reaction>🐢</reaction>
+ </reactions>
</message>
]];
@@ -71,6 +80,10 @@ describe("util.datampper", function()
state = "active";
fallback = true;
origin_id = "qgkmMdPB";
+ reactions = {
+ "👋",
+ "🐢",
+ };
};
end);
@@ -85,11 +98,21 @@ describe("util.datampper", function()
local u = map.unparse(s, d);
assert.equal("message", u.name);
assert.same(x.attr, u.attr);
- assert.equal(#x.tags-1, #u.tags)
assert.equal(x:get_child_text("body"), u:get_child_text("body"));
assert.equal(x:get_child_text("delay", "urn:xmpp:delay"), u:get_child_text("delay", "urn:xmpp:delay"));
assert.same(x:get_child("delay", "urn:xmpp:delay").attr, u:get_child("delay", "urn:xmpp:delay").attr);
assert.same(x:get_child("origin-id", "urn:xmpp:sid:0").attr, u:get_child("origin-id", "urn:xmpp:sid:0").attr);
+ for _, tag in ipairs(x.tags) do
+ if tag.name ~= "UNRELATED" and tag.name ~= "reactions" then
+ assert.truthy(u:get_child(tag.name, tag.attr.xmlns) or u:get_child(tag.name), tag:top_tag())
+ end
+ end
+ assert.equal(#x.tags-2, #u.tags)
+
+ pending("arrays", function ()
+ assert.truthy(u:get_child("reactions", "urn:xmpp:reactions:0"))
+ end);
+
end);
end);
end)
diff --git a/teal-src/util/datamapper.tl b/teal-src/util/datamapper.tl
index 055ddabd..76370ed9 100644
--- a/teal-src/util/datamapper.tl
+++ b/teal-src/util/datamapper.tl
@@ -49,6 +49,7 @@ local enum value_goes
"in_attribute"
"in_single_attribute"
"in_children"
+ "in_wrapper"
end
local function unpack_propschema( propschema : js.schema_t | js.schema_t.type_e, propname : string, current_ns : string )
@@ -67,6 +68,10 @@ local function unpack_propschema( propschema : js.schema_t | js.schema_t.type_e,
proptype = propschema
end
+ if proptype == "object" or proptype == "array" then
+ value_where = "in_children"
+ end
+
if propschema is js.schema_t then
local xml = propschema.xml
if xml then
@@ -79,8 +84,9 @@ local function unpack_propschema( propschema : js.schema_t | js.schema_t.type_e,
if xml.prefix then
prefix = xml.prefix
end
-
- if xml.attribute then
+ if proptype == "array" and xml.wrapped then
+ value_where = "in_wrapper"
+ elseif xml.attribute then
value_where = "in_attribute"
elseif xml.text then
value_where = "in_text"
@@ -98,15 +104,13 @@ local function unpack_propschema( propschema : js.schema_t | js.schema_t.type_e,
end
end
- if proptype == "object" or proptype == "array" then
- value_where = "in_children"
- end
-
return proptype, value_where, name, namespace, prefix, single_attribute, enums
end
+local parse_object : function (schema : js.schema_t, s : st.stanza_t) : { string : any }
+local parse_array : function (schema : js.schema_t, s : st.stanza_t) : { any }
-local function parse_object (schema : js.schema_t, s : st.stanza_t) : table
+function parse_object (schema : js.schema_t, s : st.stanza_t) : { string : any }
local out : { string : any } = {}
if schema.properties then
for prop, propschema in pairs(schema.properties) do
@@ -153,10 +157,22 @@ local function parse_object (schema : js.schema_t, s : st.stanza_t) : table
if c then
out[prop] = parse_object(propschema, c);
end
- -- else TODO
+ elseif proptype == "array" then
+ out[prop] = parse_array(propschema, s);
+ else
+ error "unreachable"
end
+ elseif value_where == "in_wrapper" and propschema is js.schema_t and proptype == "array" then
+ local wrapper = s:get_child(name, namespace);
+ if wrapper then
+ out[prop] = parse_array(propschema, wrapper);
+ else
+ error "unreachable"
+ end
+ else
+ error "unreachable"
end
- if value_where ~= "in_children" then
+ if value_where ~= "in_children" and value_where ~= "in_wrapper" then
out[prop] = totype(proptype, value)
end
end
@@ -165,9 +181,31 @@ local function parse_object (schema : js.schema_t, s : st.stanza_t) : table
return out
end
+function parse_array (schema : js.schema_t, s : st.stanza_t) : { any }
+ local proptype, value_where, child_name, namespace = unpack_propschema(schema.items, nil, s.attr.xmlns)
+ local out : { any } = {}
+ for c in s:childtags(child_name, namespace) do
+ local value : string;
+ if value_where == "in_text_tag" then
+ value = c:get_text();
+ else
+ error "NYI"
+ end
+
+ if value ~= nil then
+ table.insert(out, value);
+ end
+ end
+ return out;
+end
+
local function parse (schema : js.schema_t, s : st.stanza_t) : table
if schema.type == "object" then
return parse_object(schema, s)
+ elseif schema.type == "array" then
+ return parse_array(schema, s)
+ else
+ error "top-level scalars unsupported"
end
end
diff --git a/util/datamapper.lua b/util/datamapper.lua
index da46d072..a208dd7e 100644
--- a/util/datamapper.lua
+++ b/util/datamapper.lua
@@ -38,6 +38,10 @@ local function unpack_propschema(propschema, propname, current_ns)
proptype = propschema
end
+ if proptype == "object" or proptype == "array" then
+ value_where = "in_children"
+ end
+
if type(propschema) == "table" then
local xml = propschema.xml
if xml then
@@ -50,8 +54,9 @@ local function unpack_propschema(propschema, propname, current_ns)
if xml.prefix then
prefix = xml.prefix
end
-
- if xml.attribute then
+ if proptype == "array" and xml.wrapped then
+ value_where = "in_wrapper"
+ elseif xml.attribute then
value_where = "in_attribute"
elseif xml.text then
value_where = "in_text"
@@ -69,14 +74,13 @@ local function unpack_propschema(propschema, propname, current_ns)
end
end
- if proptype == "object" or proptype == "array" then
- value_where = "in_children"
- end
-
return proptype, value_where, name, namespace, prefix, single_attribute, enums
end
-local function parse_object(schema, s)
+local parse_object
+local parse_array
+
+function parse_object(schema, s)
local out = {}
if schema.properties then
for prop, propschema in pairs(schema.properties) do
@@ -123,10 +127,22 @@ local function parse_object(schema, s)
if c then
out[prop] = parse_object(propschema, c);
end
-
+ elseif proptype == "array" then
+ out[prop] = parse_array(propschema, s);
+ else
+ error("unreachable")
+ end
+ elseif value_where == "in_wrapper" and type(propschema) == "table" and proptype == "array" then
+ local wrapper = s:get_child(name, namespace);
+ if wrapper then
+ out[prop] = parse_array(propschema, wrapper);
+ else
+ error("unreachable")
end
+ else
+ error("unreachable")
end
- if value_where ~= "in_children" then
+ if value_where ~= "in_children" and value_where ~= "in_wrapper" then
out[prop] = totype(proptype, value)
end
end
@@ -135,9 +151,31 @@ local function parse_object(schema, s)
return out
end
+function parse_array(schema, s)
+ local proptype, value_where, child_name, namespace = unpack_propschema(schema.items, nil, s.attr.xmlns)
+ local out = {}
+ for c in s:childtags(child_name, namespace) do
+ local value;
+ if value_where == "in_text_tag" then
+ value = c:get_text();
+ else
+ error("NYI")
+ end
+
+ if value ~= nil then
+ table.insert(out, value);
+ end
+ end
+ return out
+end
+
local function parse(schema, s)
if schema.type == "object" then
return parse_object(schema, s)
+ elseif schema.type == "array" then
+ return parse_array(schema, s)
+ else
+ error("top-level scalars unsupported")
end
end