diff mod_storage_xmlarchive/mod_storage_xmlarchive.lua @ 2398:7e922b968b44

mod_storage_xmlarchive: Find item indices for 'before' or 'after' queries and behave as if they were excluded if the items don't exist (thanks MattJ)
author Kim Alvefur <zash@zash.se>
date Fri, 25 Nov 2016 23:17:13 +0100
parents 7f9bf161f640
children 913bd81a4d3c
line wrap: on
line diff
--- a/mod_storage_xmlarchive/mod_storage_xmlarchive.lua	Fri Nov 25 23:11:07 2016 +0100
+++ b/mod_storage_xmlarchive/mod_storage_xmlarchive.lua	Fri Nov 25 23:17:13 2016 +0100
@@ -54,6 +54,25 @@
 	return id;
 end
 
+function archive:_get_idx(username, id, dates)
+	dates = dates or self:dates(username) or empty;
+	local date = id:sub(1, 10);
+	for d = 1, #dates do
+		if date == dates[d] then
+			module:log("debug", "Loading items from %s", dates[d]);
+			local items = dm.list_load(username .. "@" .. dates[d], module.host, self.store) or empty;
+			for i = 1, #items do
+				if items[i].id == id then
+					return d, i, items;
+				end
+			end
+			return; -- Assuming no duplicates
+		elseif date > dates[d] then
+			return; -- List is assumed to be sorted
+		end
+	end
+end
+
 function archive:find(username, query)
 	username = username or "@";
 	query = query or empty;
@@ -81,35 +100,59 @@
 	local start_day, step, last_day = 1, 1, #dates;
 	local count = 0;
 	local rev = query.reverse;
-	local in_range = not (query.after or query.before);
-	if query.after or query.start then
-		local d = query.after and query.after:sub(1, 10) or dt.date(query.start);
+	if query.start then
+		local d = dt.date(query.start);
 		for i = 1, #dates do
 			if dates[i] == d then
 				start_day = i; break;
 			end
 		end
 	end
-	if query.before or query["end"] then
-		local d = query.before and query.before:sub(1, 10) or dt.date(query["end"]);
+	if query["end"] then
+		local d = dt.date(query["end"]);
 		for i = #dates, 1, -1 do
 			if dates[i] == d then
 				last_day = i; break;
 			end
 		end
 	end
+	local items, xmlfile;
+	local first_item, last_item;
 	if rev then
 		start_day, step, last_day = last_day, -step, start_day;
+		if query.before then
+			local before_day, before_item, items_ = self:_get_idx(username, query.before, dates);
+			if before_day and before_day <= start_day then
+				if before_item then
+					first_item = before_item - 1;
+				else
+					first_item = #items_;
+				end
+				last_item = 1;
+				start_day = before_day;
+				items = items_;
+			end
+		end
+	elseif query.after then
+		local after_day, after_item, items_ = self:_get_idx(username, query.after, dates);
+		if after_day and after_day >= start_day then
+			if after_item then
+				first_item = after_item + 1;
+			else
+				first_item = 1;
+			end
+			last_item = #items_;
+			start_day = after_day;
+			items = items_;
+		end
 	end
-	local items, xmlfile;
-	local first_item, last_item;
 
 	return function ()
 		if limit and count >= limit then if xmlfile then xmlfile:close() end return; end
 		local filename;
 
 		for d = start_day, last_day, step do
-			if d ~= start_day or not items then
+			if not items then
 				module:log("debug", "Loading items from %s", dates[d]);
 				start_day = d;
 				items = dm.list_load(username .. "@" .. dates[d], module.host, self.store) or empty;
@@ -144,8 +187,7 @@
 						return;
 					end
 				end
-				if in_range
-				and (not q_with or i_with == q_with)
+				if  (not q_with or i_with == q_with)
 				and (not q_start or i_when >= q_start)
 				and (not q_end or i_when <= q_end) then
 					count = count + 1;
@@ -164,16 +206,8 @@
 						return item.id, stanza, i_when, i_with;
 					end
 				end
-				if (rev and item.id == query.after) or
-					(not rev and item.id == query.before) then
-					in_range = false;
-					limit = count;
-				end
-				if (rev and item.id == query.before) or
-					(not rev and item.id == query.after) then
-					in_range = true;
-				end
 			end
+			items = nil;
 			if xmlfile then
 				xmlfile:close();
 				xmlfile = nil;