I'm looking for a way to expose filtering functionality at my workplace to other developers and optionally customers.
i want to implement a simple query language over my data (python dicts) based on user defined filters exposed to my other developers and later on to our customers.
Exposing SQL interface over my dict / json data would be great (I prefer not to setup server)
db = [
{'first': 'john', 'last': 'doe', 'likes': ['cookies', 'http']},
{'first': 'jane', 'last': 'doe', 'likes': ['cookies', 'donuts']},
{'first': 'danny', 'last': 'foo', 'likes': ['http', 'donuts']},
]
query = '(first == "john" or last == "doe") and likes contains "cookies"'
results = run_query(db, query)
this should return (in results):
[
{'first': 'john', 'last': 'doe', 'likes': ['cookies', 'http']},
{'first': 'jane', 'last': 'doe', 'likes': ['cookies', 'donuts']},
]
note: i do not mind changing the operator names, e.g. or -> OR
contains -> inside
or anything else as long as it is human readable and keeps the same expressiveness of the language
I looked at some DSL libraries like PLY but they seems to me too complex and involves some magic to get things done (not really sure where to start and if its worth it)
didnt find any plugin system to expose a sandboxed functionality for my users (i.e. safer eval)
I looked at TinyDB and others that implement some sort of SQL over json but couldn't find something that work without alot of customizations. I also looked at pandasql which seems good overall but unmaintained library :(
there is a lucene package parser - luqum based on PLY
but its different from my syntax tree (they have more methods) and the lib is not really maintained, (I do consider manipulating this lib a bit to get what i want)
use SQLiteDB to load all my data (in memory or not) and then run SQL queries over it. didnt test it but this should be pretty straightforward with the downside of loading my whole data into SQL just to run the data on which i prefer not to do.
I am open to suggestions or even on how to improve the above solution to make this work
Create a select querySelect Create > Query Wizard . Select Simple Query, and then OK. Select the table that contains the field, add the Available Fields you want to Selected Fields, and select Next. Choose whether you want to open the query in Datasheet view or modify the query in Design view, and then select Finish.
The fundamental difference is that SQL is a query language primarily used for accessing and extracting data, whereas Python is a general-purpose programming language that enables experimentation with the data.
SQL, which stands for structured query language, is a programming language in which the user queries relational databases. Data scientists use SQL in Python in a variety of instances, dictated by the use case at hand or by personal preference.
Before using PLY for text based queries, I would build-up the core language from regular Python classes like this:
class Match:
def __init__(self, **target):
[[self.key, self.value]] = target.items()
def __call__(self, obj):
return self.key in obj and self.value == obj[self.key]
class Contains:
def __init__(self, **target):
[[self.key, self.value]] = target.items()
def __call__(self, obj):
return self.key in obj and self.value in obj[self.key]
class Or:
def __init__(self, *predicates):
self.predicates = predicates
def __call__(self, record):
return any(predicate(record) for predicate in self.predicates)
class And:
def __init__(self, *predicates):
self.predicates = predicates
def __call__(self, record):
return all(predicate(record) for predicate in self.predicates)
def run_query(db, query):
return filter(query, db)
if __name__ == '__main__':
db = [
{'first': 'john', 'last': 'doe', 'likes': ['cookies', 'http']},
{'first': 'jane', 'last': 'doe', 'likes': ['cookies', 'donuts']},
{'first': 'danny', 'last': 'foo', 'likes': ['http', 'donuts']},
]
query = And(Or(Match(first='john'), Match(last='doe')), Contains(likes='cookies'))
for result in run_query(db, query):
print(result)
This outputs:
{'first': 'john', 'last': 'doe', 'likes': ['cookies', 'http']}
{'first': 'jane', 'last': 'doe', 'likes': ['cookies', 'donuts']}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With