diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/OldRecordHelper.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/OldRecordHelper.java
new file mode 100644
index 00000000..10f68c2c
--- /dev/null
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/customizers/OldRecordHelper.java
@@ -0,0 +1,88 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2025. Kingsrook, LLC
+ * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
+ * contact@kingsrook.com
+ * https://github.com/Kingsrook/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.kingsrook.qqq.backend.core.actions.customizers;
+
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import com.kingsrook.qqq.backend.core.context.QContext;
+import com.kingsrook.qqq.backend.core.model.data.QRecord;
+import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
+import com.kingsrook.qqq.backend.core.utils.collections.TypeTolerantKeyMap;
+
+
+/*******************************************************************************
+ ** utility class to help table customizers working with the oldRecordList.
+ ** Usage is just 2 lines:
+ ** outside of loop-over-records:
+ ** - OldRecordHelper oldRecordHelper = new OldRecordHelper(updateInput.getTableName(), oldRecordList);
+ ** then inside the record loop:
+ ** - Optional oldRecord = oldRecordHelper.getOldRecord(record);
+ *******************************************************************************/
+public class OldRecordHelper
+{
+ private String primaryKeyField;
+ private QFieldType primaryKeyType;
+
+ private Optional> oldRecordList;
+ private Map oldRecordMap;
+
+
+
+ /*******************************************************************************
+ ** Constructor
+ **
+ *******************************************************************************/
+ public OldRecordHelper(String tableName, Optional> oldRecordList)
+ {
+ this.primaryKeyField = QContext.getQInstance().getTable(tableName).getPrimaryKeyField();
+ this.primaryKeyType = QContext.getQInstance().getTable(tableName).getField(primaryKeyField).getType();
+
+ this.oldRecordList = oldRecordList;
+ }
+
+
+
+ /***************************************************************************
+ **
+ ***************************************************************************/
+ public Optional getOldRecord(QRecord record)
+ {
+ if(oldRecordMap == null)
+ {
+ if(oldRecordList.isPresent())
+ {
+ oldRecordMap = new TypeTolerantKeyMap<>(primaryKeyType);
+ oldRecordList.get().forEach(r -> oldRecordMap.put(r.getValue(primaryKeyField), r));
+ }
+ else
+ {
+ oldRecordMap = Collections.emptyMap();
+ }
+ }
+
+ return (Optional.ofNullable(oldRecordMap.get(record.getValue(primaryKeyField))));
+ }
+}
diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/OldRecordHelperTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/OldRecordHelperTest.java
new file mode 100644
index 00000000..69e0731f
--- /dev/null
+++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/actions/customizers/OldRecordHelperTest.java
@@ -0,0 +1,70 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2025. Kingsrook, LLC
+ * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
+ * contact@kingsrook.com
+ * https://github.com/Kingsrook/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.kingsrook.qqq.backend.core.actions.customizers;
+
+
+import java.util.List;
+import java.util.Optional;
+import com.kingsrook.qqq.backend.core.BaseTest;
+import com.kingsrook.qqq.backend.core.model.data.QRecord;
+import com.kingsrook.qqq.backend.core.utils.TestUtils;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+
+/*******************************************************************************
+ ** Unit test for OldRecordHelper
+ *******************************************************************************/
+class OldRecordHelperTest extends BaseTest
+{
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Test
+ void test()
+ {
+ OldRecordHelper oldRecordHelper = new OldRecordHelper(TestUtils.TABLE_NAME_PERSON_MEMORY, Optional.of(List.of(
+ new QRecord().withValue("id", 1)
+ )));
+
+ assertTrue(oldRecordHelper.getOldRecord(new QRecord().withValue("id", 1)).isPresent());
+ assertTrue(oldRecordHelper.getOldRecord(new QRecord().withValue("id", "1")).isPresent());
+ assertFalse(oldRecordHelper.getOldRecord(new QRecord().withValue("id", 2)).isPresent());
+ }
+
+
+
+ /*******************************************************************************
+ **
+ *******************************************************************************/
+ @Test
+ void testEmptyOldRecords()
+ {
+ OldRecordHelper oldRecordHelper = new OldRecordHelper(TestUtils.TABLE_NAME_PERSON_MEMORY, Optional.empty());
+ assertFalse(oldRecordHelper.getOldRecord(new QRecord().withValue("id", 1)).isPresent());
+ assertFalse(oldRecordHelper.getOldRecord(new QRecord().withValue("id", "1")).isPresent());
+ assertFalse(oldRecordHelper.getOldRecord(new QRecord().withValue("id", 2)).isPresent());
+ }
+
+}
\ No newline at end of file