Shm*_*ikA 5 python json abstract-syntax-tree python-3.x
我正在寻找一种方法来向其他开发人员和可选的客户公开我工作场所的过滤功能。
我想基于向我的其他开发人员以及后来向我们的客户公开的用户定义过滤器,对我的数据(python dicts)实现一种简单的查询语言。
在我的 dict / json 数据上公开 SQL 接口会很棒(我不想设置服务器)
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)
Run Code Online (Sandbox Code Playgroud)
这应该返回(在结果中):
[
{'first': 'john', 'last': 'doe', 'likes': ['cookies', 'http']},
{'first': 'jane', 'last': 'doe', 'likes': ['cookies', 'donuts']},
]
Run Code Online (Sandbox Code Playgroud)
注意:我不介意更改运算符名称,例如or -> OR contains -> inside或其他任何名称,只要它是人类可读的并且保持语言的相同表达能力
我查看了一些像PLY这样的 DSL 库,但在我看来它们太复杂了,并且涉及一些完成任务的魔法(不确定从哪里开始以及是否值得)
没有找到任何插件系统来为我的用户公开沙盒功能(即更安全的评估)
我查看了TinyDB和其他通过 json 实现某种 SQL 的工具,但找不到可以在没有大量自定义的情况下工作的东西。我还查看了pandasql,它总体上看起来不错,但没有维护的库:(
有一个 lucene 包解析器 - luqum基于PLY但它与我的语法树不同(他们有更多的方法)并且 lib 没有真正维护,(我确实考虑稍微操纵这个 lib 以获得我想要的)
使用 SQLiteDB 加载我的所有数据(无论是否在内存中),然后对其运行 SQL 查询。没有测试它,但这应该非常简单,因为将我的整个数据加载到 SQL 中只是为了运行我不想做的数据。
我愿意接受建议,甚至对如何改进上述解决方案以使其有效
在使用 PLY 进行基于文本的查询之前,我会从常规 Python 类构建核心语言,如下所示:
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)
Run Code Online (Sandbox Code Playgroud)
这输出:
{'first': 'john', 'last': 'doe', 'likes': ['cookies', 'http']}
{'first': 'jane', 'last': 'doe', 'likes': ['cookies', 'donuts']}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
997 次 |
| 最近记录: |