From a854a0dc0aa79a31695db833184c5ca3698632a9 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 24 Apr 2024 12:27:26 +0100 Subject: [PATCH] feat: Implement 'Like' predicate in entity storage This acts like the SQL 'LIKE' keyword, allowing partial string matches. --- packages/backend/src/om/entitystorage/SQLES.js | 18 +++++++++++++++++- packages/backend/src/om/query/query.js | 10 ++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/om/entitystorage/SQLES.js b/packages/backend/src/om/entitystorage/SQLES.js index 61b6eecb..ede60eb6 100644 --- a/packages/backend/src/om/entitystorage/SQLES.js +++ b/packages/backend/src/om/entitystorage/SQLES.js @@ -22,7 +22,7 @@ const { BaseES } = require("./BaseES"); const APIError = require("../../api/APIError"); const { Entity } = require("./Entity"); const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait"); -const { And, Or, Eq, Predicate, Null, PredicateUtil } = require("../query/query"); +const { And, Or, Eq, Like, Null, Predicate, PredicateUtil } = require("../query/query"); const { DB_WRITE } = require("../../services/database/consts"); class RawCondition extends AdvancedBase { @@ -355,6 +355,22 @@ class SQLES extends BaseES { return new RawCondition({ sql, values }); } + + if ( om_query instanceof Like ) { + const key = om_query.key; + let value = om_query.value; + const prop = this.om.properties[key]; + + value = await prop.sql_reference(value); + + const options = prop.descriptor.sql ?? {}; + const col_name = options.column_name ?? prop.name; + + const sql = `${col_name} LIKE ?`; + const values = [value]; + + return new RawCondition({ sql, values }); + } } } } diff --git a/packages/backend/src/om/query/query.js b/packages/backend/src/om/query/query.js index 8817afde..4533076b 100644 --- a/packages/backend/src/om/query/query.js +++ b/packages/backend/src/om/query/query.js @@ -50,6 +50,15 @@ class Eq extends Predicate { } } +class Like extends Predicate { + async check (entity) { + // Convert SQL LIKE pattern to RegExp + // TODO: Support escaping the pattern characters + const regex = new RegExp(this.value.replaceAll('%', '.*').replaceAll('_', '.'), 'i'); + return regex.test(await entity.get(this.key)); + } +} + Predicate.prototype.and = function (other) { return new And({ children: [this, other] }); } @@ -105,4 +114,5 @@ module.exports = { And, Or, Eq, + Like, };