plugins/mod_storage_memory.lua
changeset 9538 c1befd1c886d
parent 9537 b301f7edf346
child 9613 1dfcea523200
--- a/plugins/mod_storage_memory.lua	Sun Oct 21 18:00:46 2018 +0200
+++ b/plugins/mod_storage_memory.lua	Sun Oct 21 19:06:41 2018 +0200
@@ -1,4 +1,5 @@
 local serialize = require "util.serialization".serialize;
+local array = require "util.array";
 local envload = require "util.envload".envload;
 local st = require "util.stanza";
 local is_stanza = st.is_stanza or function (s) return getmetatable(s) == st.stanza_mt end
@@ -113,25 +114,70 @@
 		self.store[username or NULL] = nil;
 		return true;
 	end
-	local old = self.store[username or NULL];
-	if not old then return true; end
-	local qstart = query.start or -math.huge;
-	local qend = query["end"] or math.huge;
-	local qwith = query.with;
-	local new = {};
-	self.store[username or NULL] = new;
-	local t;
-	for i = 1, #old do
-		i = old[i];
-		t = i.when;
-		if not(qstart >= t and qend <= t and (not qwith or i.with == qwith)) then
-			self:append(username, i.key, i.value(), t, i.with);
+	local items = self.store[username or NULL];
+	if not items then
+		-- Store is empty
+		return 0;
+	end
+	items = array(items);
+	local count_before = #items;
+	if query then
+		if query.key then
+			items:filter(function (item)
+				return item.key ~= query.key;
+			end);
+		end
+		if query.with then
+			items:filter(function (item)
+				return item.with ~= query.with;
+			end);
+		end
+		if query.start then
+			items:filter(function (item)
+				return item.when < query.start;
+			end);
+		end
+		if query["end"] then
+			items:filter(function (item)
+				return item.when > query["end"];
+			end);
+		end
+		if query.truncate and #items > query.truncate then
+			if query.reverse then
+				-- Before: { 1, 2, 3, 4, 5, }
+				-- After: { 1, 2, 3 }
+				for i = #items, query.truncate + 1, -1 do
+					items[i] = nil;
+				end
+			else
+				-- Before: { 1, 2, 3, 4, 5, }
+				-- After: { 3, 4, 5 }
+				local offset = #items - query.truncate;
+				for i = 1, #items do
+					items[i] = items[i+offset];
+				end
+			end
 		end
 	end
-	if #new == 0 then
-		self.store[username or NULL] = nil;
+	local count = count_before - #items;
+	if count == 0 then
+		return 0; -- No changes, skip write
 	end
-	return true;
+	setmetatable(items, nil);
+
+	do -- re-index by key
+		for k in pairs(items) do
+			if type(k) == "string" then
+				items[k] = nil;
+			end
+		end
+
+		for i = 1, #items do
+			items[ items[i].key ] = i;
+		end
+	end
+
+	return count;
 end
 
 archive_store.purge = _purge_store;