Repository: dag-hammarskjold-library/dlx

Issue:
Wildcard search bugs
Regressions introduced in #377

Hints from issue comments:
@jbukhari: Addresses https://github.com/dag-hammarskjold-library/dlx-rest/issues/1528

Solution patch:
diff --git a/dlx/marc/query.py b/dlx/marc/query.py
index e03499cf..f5b8d4c2 100644
--- a/dlx/marc/query.py
+++ b/dlx/marc/query.py
@@ -15,7 +15,7 @@ class InvalidQueryString(Exception):
 class WildcardRegex(Regex):
     # for differentiating regex to run against text index vs actual value
     def __init__(self, string=None):
-        super().__init__(string)
+        super().__init__(string, 'i')
     
 class Query():
     @classmethod
@@ -88,6 +88,7 @@ def process_string(string):
                 else:
                     return Regex(string[1:-1])
             elif '*' in string:
+                # create regex pattern using wildcard character
                 if string == '*':
                     # special string for checking if field exists
                     return string
@@ -96,7 +97,7 @@ def process_string(string):
                 string = string.replace('*', placeholder)
                 string = re.escape(string)
                 string = string.replace(placeholder, '.*')
-                string = string if string[0:2] == '.*' else '^ ' + string # the "text" field in pseudo indexes starts with a space 
+                string = string if string[0:2] == '.*' else '^' + string
                 string = string if string[-2:] == '.*' else string + '$'
 
                 return WildcardRegex(string)
@@ -131,8 +132,9 @@ def parse(token, modifier=None):
                 # regex
                 if isinstance(value, Regex):
                     if isinstance(value, WildcardRegex):
-                        new_pattern = Tokenizer.scrub(re.sub(r'\^', ' ', value.pattern))  # pseudo index text field starts with a space
-                        matches = DB.handle[f'_index_{tag}'].find({'text': Regex(new_pattern)})
+                        #new_pattern = re.sub(r'^\^', '^ ', value.pattern)  # pseudo index text field starts with a space
+                        #matches = DB.handle[f'_index_{tag}'].find({'text': Regex(new_pattern)})
+                        matches = DB.handle[f'_index_{tag}'].find({'subfields': {'$elemMatch': {'code': code, 'value': value}}})
                     else:
                         #matches = DB.handle[f'_index_{tag}'].find({'subfields.value': value})
                         return Condition(tag, {code: value}, modifier=modifier, record_type=self.record_type)
@@ -250,8 +252,9 @@ def parse(token, modifier=None):
                 # regex
                 if isinstance(value, Regex):
                     if isinstance(value, WildcardRegex):
-                        new_pattern = Tokenizer.scrub(re.sub(r'\^', ' ', value.pattern)) # pseudo index text field starts with a space
-                        matches = DB.handle[f'_index_{tag}'].find({'text': Regex(new_pattern)})
+                        new_pattern = re.sub(r'\^', '^ ', value.pattern).lower() # pseudo index text field starts with a space
+                        #matches = DB.handle[f'_index_{tag}'].find({'text': Regex(new_pattern)})
+                        matches = DB.handle[f'_index_{tag}'].find({'subfields.value': value})
                     else:
                         #matches = DB.handle[f'_index_{tag}'].find({'subfields.value': value})
                         return TagOnly(tag, value, modifier=modifier, record_type=self.record_type)
@@ -423,7 +426,7 @@ def parse(token, modifier=None):
                     # regex
                     if isinstance(value, Regex):
                         if isinstance(value, WildcardRegex):
-                            new_pattern = Tokenizer.scrub(re.sub(r'\^', ' ', value.pattern)) # pseudo index text field starts with a space
+                            new_pattern = re.sub(r'\^', '^ ', value.pattern) # pseudo index text field starts with a space
                             q = {'text': Regex(new_pattern)}
                         else:
                             q = {'_id': value}


Test patch:
diff --git a/tests/test_marc.py b/tests/test_marc.py
index 2eda5447..ad20e409 100644
--- a/tests/test_marc.py
+++ b/tests/test_marc.py
@@ -355,6 +355,15 @@ def test_querystring(db):
     # string with wildcard
     query = Query.from_string(f"245__c:*itl*", record_type='bib')
     assert len(list(BibSet.from_query(query.compile()))) == 2
+
+    query = Query.from_string(f"245:titl*", record_type='bib')
+    assert len(list(BibSet.from_query(query.compile()))) == 2
+
+    query = Query.from_string(f"650:head*", record_type='bib')
+    assert len(list(BibSet.from_query(query.compile()))) == 2
+
+    query = Query.from_string(f"650__a:head*", record_type='bib')
+    assert len(list(BibSet.from_query(query.compile()))) == 2
     
     # logical fields
     bib = Bib().set('246', 'a', 'This title:').set('246', 'b', 'is a title').commit()