about summary refs log tree commit diff stats
path: root/html/text-world/js/where.js
diff options
context:
space:
mode:
Diffstat (limited to 'html/text-world/js/where.js')
-rw-r--r--html/text-world/js/where.js82
1 files changed, 82 insertions, 0 deletions
diff --git a/html/text-world/js/where.js b/html/text-world/js/where.js
new file mode 100644
index 0000000..60e3797
--- /dev/null
+++ b/html/text-world/js/where.js
@@ -0,0 +1,82 @@
+/**
+ * A mostly functional query filter similar to SQL's WHERE
+ * @param {Array} collection - Array of objects to filter
+ * @param {Object} properties - Object containing properties to match against
+ * @returns {Array} - Filtered array of objects
+ */
+const where = (collection, properties) => {
+
+    if (!collection || !properties) {
+        return [];
+    }
+
+    const propertyPaths = Object.entries(properties).map(([key, value]) => ({
+        path: key,
+        parts: key.split('.'),
+        value
+    }));
+
+    const getNestedValue = (() => {
+        const cache = new WeakMap();
+        
+        return (obj, parts) => {
+            if (!obj) return undefined;
+            
+            let cached = cache.get(obj);
+            if (!cached) {
+                cached = new Map();
+                cache.set(obj, cached);
+            }
+            
+            const pathKey = parts.join('.');
+            if (cached.has(pathKey)) {
+                return cached.get(pathKey);
+            }
+
+            const value = parts.reduce((current, key) => 
+                current && current[key] !== undefined ? current[key] : undefined, 
+                obj
+            );
+            
+            cached.set(pathKey, value);
+            return value;
+        };
+    })();
+
+    const isEqual = (value1, value2) => {
+
+        if (value2 === undefined) return true;
+        if (value1 === value2) return true;
+        if (value1 === null || value2 === null) return false;
+
+        if (Array.isArray(value1) && Array.isArray(value2)) {
+            return value1.length === value2.length &&
+                   value1.every((val, idx) => isEqual(val, value2[idx]));
+        }
+
+        if (typeof value2 === 'object') {
+            return Object.entries(value2).every(([key, val]) => 
+                value1 && isEqual(value1[key], val)
+            );
+        }
+
+        return false;
+    };
+
+    const matchesProperties = item => 
+        propertyPaths.every(({ parts, value }) => 
+            isEqual(getNestedValue(item, parts), value)
+        );
+
+    if (!Array.isArray(collection) || typeof properties !== 'object') {
+        return [];
+    }
+
+    return collection.filter(matchesProperties);
+};
+
+
+
+if (typeof module !== 'undefined' && module.exports) {
+    module.exports = where;
+}