一个可定制的用于scim2.0过滤器的解析器/transpiler

scim2-filter-parser的Python项目详细描述


traviscodecov

说明

scim 2.0定义的查询如下:

'emails[type eq "work" and value co "@example.com"] or ims[type eq "xmpp" and value co "@foo.com"]'

这些可能很难使用,并转换成sql来运行数据库。

这就是scim 2.0过滤器解析器(sfp)可以提供帮助的地方。

SFP分为四个模块,每个模块处理 将scim调用转换为sql查询。

第一步是标记查询或词法分析,其中过滤器查询 被分解成许多代币组成。

sfp-lexer 'emails[type eq "work" and value co "@example.com"] or ims[type eq "xmpp" and value co "@foo.com"]'

Token(type='ATTRNAME', value='emails', lineno=1, index=0)
Token(type='LBRACKET', value='[', lineno=1, index=6)
Token(type='ATTRNAME', value='type', lineno=1, index=7)
Token(type='EQ', value='eq', lineno=1, index=12)
Token(type='COMP_VALUE', value='work', lineno=1, index=15)
Token(type='AND', value='and', lineno=1, index=22)
Token(type='ATTRNAME', value='value', lineno=1, index=26)
Token(type='CO', value='co', lineno=1, index=32)
Token(type='COMP_VALUE', value='@example.com', lineno=1, index=35)
Token(type='RBRACKET', value=']', lineno=1, index=49)
Token(type='OR', value='or', lineno=1, index=51)
Token(type='ATTRNAME', value='ims', lineno=1, index=54)
Token(type='LBRACKET', value='[', lineno=1, index=57)
Token(type='ATTRNAME', value='type', lineno=1, index=58)
Token(type='EQ', value='eq', lineno=1, index=63)
Token(type='COMP_VALUE', value='xmpp', lineno=1, index=66)
Token(type='AND', value='and', lineno=1, index=73)
Token(type='ATTRNAME', value='value', lineno=1, index=77)
Token(type='CO', value='co', lineno=1, index=83)
Token(type='COMP_VALUE', value='@foo.com', lineno=1, index=86)
Token(type='RBRACKET', value=']', lineno=1, index=96)

第二步是将这一系列标记转换为抽象语法树。

sfp-parser 'emails[type eq "work" and value co "@example.com"] or ims[type eq "xmpp" and value co "@foo.com"]'

Filter(expr=LogExpr, negated=False, namespace=None)
    LogExpr(op='or', expr1=Filter, expr2=Filter)
        Filter(expr=Filter, negated=False, namespace=None)
            Filter(expr=Filter, negated=False, namespace=AttrPath)
                Filter(expr=LogExpr, negated=False, namespace=None)
                    LogExpr(op='and', expr1=Filter, expr2=Filter)
                        Filter(expr=AttrExpr, negated=False, namespace=None)
                            AttrExpr(value='eq', attr_path=AttrPath, comp_value=CompValue)
                                AttrPath(attr_name='type', sub_attr=None, uri=None)
                                CompValue(value='work')
                        Filter(expr=AttrExpr, negated=False, namespace=None)
                            AttrExpr(value='co', attr_path=AttrPath, comp_value=CompValue)
                                AttrPath(attr_name='value', sub_attr=None, uri=None)
                                CompValue(value='@example.com')
                AttrPath(attr_name='emails', sub_attr=None, uri=None)
        Filter(expr=Filter, negated=False, namespace=None)
            Filter(expr=Filter, negated=False, namespace=AttrPath)
                Filter(expr=LogExpr, negated=False, namespace=None)
                    LogExpr(op='and', expr1=Filter, expr2=Filter)
                        Filter(expr=AttrExpr, negated=False, namespace=None)
                            AttrExpr(value='eq', attr_path=AttrPath, comp_value=CompValue)
                                AttrPath(attr_name='type', sub_attr=None, uri=None)
                                CompValue(value='xmpp')
                        Filter(expr=AttrExpr, negated=False, namespace=None)
                            AttrExpr(value='co', attr_path=AttrPath, comp_value=CompValue)
                                AttrPath(attr_name='value', sub_attr=None, uri=None)
                                CompValue(value='@foo.com')
                AttrPath(attr_name='ims', sub_attr=None, uri=None)

第三步是将ast转换成我们选择的语言。 上面的查询被转换成下面的sql。

sfp-transpiler 'emails[type eq "work" and value co "@example.com"] or ims[type eq "xmpp" and value co "@foo.com"]'

((emails.type = {0}) AND (emails.value LIKE {1})) OR ((ims.type = {2}) AND (ims.value LIKE {3}))
{0: 'work', 1: '%@example.com%', 2: 'xmpp', 3: '%@foo.com%'}

第四步是获取sql where子句的一个片段并完成 SQL查询的其余部分。

sfp-query 'emails[type eq "work" and value co "@example.com"] or ims[type eq "xmpp" and value co "@foo.com"]'

>>> DO NOT USE THIS OUTPUT DIRECTLY
>>> SQL INJECTION ATTACK RISK
>>> SQL PREVIEW:
    SELECT DISTINCT users.*
    FROM users
    LEFT JOIN emails ON emails.user_id = users.id
    LEFT JOIN schemas ON schemas.user_id = users.id
    WHERE ((emails.type = work) AND (emails.value LIKE %@example.com%)) OR ((ims.type = xmpp) AND (ims.value LIKE %@foo.com%));

请注意,sfp不使用预注入的参数构建sql查询。 这将造成SQL注入攻击漏洞。而是一个Query 对象已创建,可以强制显示自己,如上图所示 通过printing查询对象。

使用

尽管提供了命令行垫片,但该库旨在使用 以编程方式。库的用户应该实例化 scim2_filter_parser.query.Query类,具有属性映射和可选的 使查询中的所有必需字段都可访问所需的任何联接。

例如,如果用户信息存储在users表和电子邮件中 信息存储在不同的表emails中,然后是属性映射 连接可以这样定义:

attr_map = {
    ('userName', None, None): 'users.username',
    ('name', 'familyName', None): 'users.family_name',
    ('meta', 'lastModified', None): 'users.update_ts',
    ('emails', None, None): 'emails.address',
    ('emails', 'value', None): 'emails.address',
}

joins = (
    'LEFT JOIN emails ON emails.user_id = users.id',
)

q = Query(filter, 'users', attr_map, joins)

q.sql # Will be equal to 'SELECT * FROM users ...
q.params # Will be equal to the paramters specific to the filter query.

属性映射(attr_map)是scim attribute,subattribute, 以及表字段的架构uri。您需要将此自定义为 特定数据库架构。

Query.sql方法返回可以用作第一个 使用您喜爱的数据库引擎调用cursor.execute()时的参数。 如果您使用的数据库需要替换字符,而不是%s, 然后您可以将Query类子类化,并重写placeholder类 级别变量。有关此子类的示例,请参见查询模块和单元测试 和sqlite一起。

Query.params方法返回一个可以用作 调用cursor.execute()时的第二个参数。

spped

SFP相当快。查看speed_test.py脚本了解长和短脚本的详细信息 已测试筛选查询。SFP在不到54微秒的时间内将一个简短的筛选查询转译为SQL。 对于更长的查询,sfp只花了273微秒。

scim2筛选器分析器git:(master)python-m timeit-s“import speed_test”“speed_test.short()” 10000圈,最好是3:53.8 usec/圈 scim2筛选器分析器git:(master)python-m timeit-s“import speed_test”“speed_test.long()” 1000个循环,最好3:273 usec/循环

-

该项目仍处于生命的初级阶段,应相应地加以利用。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
spring引导服务器忽略java上载请求   java多个驼峰路由会导致大量线程吗?   java 安卓单签入回收器gridLayout管理器   Java中指向类的不同实例的对象数组   java的启动/停止和打开/关闭等分组功能是否违反了单一责任原则?   java hibernate组件映射与自定义值类型   java如何使用不同的JDK在Jenkins作业中使用JDK8   java从匹配器获取字符串的特定部分   java通过在Spark数据框内的数组列中映射来创建新列   servlet的java Tomcat配置   java多个活动不在一个应用程序安卓 studio中   javajsf:view beforePhase在我离开页面时多次触发   javascript如何使用“java脚本”进行加密,使用和“java”进行解密   java My App不是从URL ASPX读取简单的JSON   java在RESTish web服务中应用DDD原则