changeset 14011:f77911437539 13.0

mod_storage_internal: Return item-not-found for unknown before/after ids This is required per XEP-0313, otherwise clients cannot tell the difference between an empty successful query and a query where their sync point is no longer within the archive.
author Matthew Wild <mwild1@gmail.com>
date Fri, 12 Dec 2025 12:43:23 +0000
parents ed210f6b1d00
children 373d3edf58aa f0b2a05bcedc
files plugins/mod_storage_internal.lua spec/core_storagemanager_spec.lua
diffstat 2 files changed, 61 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/mod_storage_internal.lua	Fri Dec 12 11:31:04 2025 +0000
+++ b/plugins/mod_storage_internal.lua	Fri Dec 12 12:43:23 2025 +0000
@@ -173,6 +173,7 @@
 		return list[i]
 	end
 
+	local after_found;
 	if query then
 		if query.reverse then
 			i = #list + 1
@@ -231,12 +232,23 @@
 			iter = it.filter(function(item)
 				local found_after = found;
 				if item.key == query.after then
+					after_found = true;
 					found = true
 				end
 				return found_after;
 			end, iter);
 		end
 		if query.before then
+			local before_key, before_found = query.before;
+			for idx = 1, #list do
+				if list[idx].key == before_key then
+					before_found = true;
+					break;
+				end
+			end
+			if not before_found then
+				return nil, "item-not-found";
+			end
 			local found = false;
 			iter = it.filter(function(item)
 				if item.key == query.before then
@@ -250,8 +262,18 @@
 		end
 	end
 
+	local first_item = iter();
+	if first_item == nil and query and query.after and not after_found then
+		return nil, "item-not-found";
+	end
+
 	return function()
-		local item = iter();
+		local item;
+		if first_item then
+			item, first_item = first_item, nil;
+		else
+			item = iter();
+		end
 		if item == nil then
 			if list.close then
 				list:close();
--- a/spec/core_storagemanager_spec.lua	Fri Dec 12 11:31:04 2025 +0000
+++ b/spec/core_storagemanager_spec.lua	Fri Dec 12 12:43:23 2025 +0000
@@ -621,7 +621,44 @@
 						assert.equal(2, count);
 					end);
 
+					it("for non-existent after id returning error", function ()
+						do
+							local data, err = archive:find("user", {
+								["after"] = "non-existent-id";
+							});
+							assert.is_falsy(data);
+							assert.is_equal("item-not-found", err);
+						end
 
+						do
+							local data, err = archive:find("user", {
+								["after"] = "non-existent-id";
+								["reverse"] = true;
+							});
+							assert.is_falsy(data);
+							assert.is_equal("item-not-found", err);
+						end
+					end);
+
+					it("for non-existent before id returning error", function ()
+						do
+							local data, err = archive:find("user", {
+								["before"] = "non-existent-id";
+							});
+							assert.is_falsy(data);
+							assert.is_equal("item-not-found", err);
+						end
+
+						do
+							local data, err = archive:find("user", {
+								["before"] = "non-existent-id";
+								["reverse"] = true;
+							});
+							assert.is_falsy(data);
+							assert.is_equal("item-not-found", err);
+						end
+
+					end);
 
 				end);
 
@@ -791,3 +828,4 @@
 		end);
 	end
 end);
+