如何将 hylang s-expression 序列化为 PostgreSQL json/json-b?

How to serialize hylang s-expression into PostgreSQL json/json-b?

我们正在尝试使用hylang作为一些金融业务流程的DSL。我们试图将业务规则用作 JSON,但使用 hy 语言切换到 DSL。现在我们需要像以前的 JSON-B 项一样将 s-expression 项持久化到 postgreSQL 中。有没有标准的方法可以做到这一点,或者我们必须改用文本字段?

上一个:

  "conditions": {
    "all": [
        {
            "name": "order_create_date",
            "value": 1620675000,
            "operator": "greater_than_or_equal_to"
        },
        {
            "name": "order_create_date",
            "value": 1624217400,
            "operator": "less_than_or_equal_to"
        }
  }

当前:

(defn check_condition [params] (
                            and (> params.order_create_date "2021/06/22") (< params.order_create_date "2021/07/22"))

)

确实没有标准的方法来做到这一点;在 Hy 或 Postgres 方面没有实现任何特别的东西。除非你真的有大量的这些,或者它们非常大,或者你想对它们进行某种奇特的搜索或索引,否则将它们存储为文本应该没问题。事实上,我更喜欢平面文件而不是数据库。

另一种选择是利用 Postgres 的 JSON 支持并设计您自己的在 Hy 模型树和 JSON 之间转换的小方法。例如,Hy 表达式可以表示为 JSON 数组。 Python 的 json 库可以帮助解决这个问题,例如JSONEncoderdefault 参数。

有2种解决方案:

  1. 使用像 'sexpdata' 这样的库来解析和反解析 S 表达式 to/from Python 列表,然后使用 JSON 加上一些自定义 enc/dec.

  2. 使用 pyparsing 将 S-Expression 解析为 Python 列表,然后使用 json.

    import pyparsing as pp
    import json
    
    LP = pp.Literal("(").suppress()
    RP = pp.Literal(")").suppress()
    String = pp.Word(pp.alphanums + '_,.#@<>=+=/*%[]')
    SingleQuoteString = pp.QuotedString(quoteChar="'", unquoteResults=False)
    DoubleQuoteString = pp.QuotedString(quoteChar='"', unquoteResults=False)
    QuotedString = SingleQuoteString | DoubleQuoteString
    Atom = String | QuotedString
    SExpr = pp.Forward()
    SExprList = pp.Group(pp.ZeroOrMore(SExpr | Atom))
    SExpr << (LP + SExprList + RP)
    
    
    def to_json(expr: str) -> str:
        return json.dumps(SExpr.parseString(expr).asList())
    
    
    def from_json(val: str) -> str:
        if isinstance(val, list):
            return f"({' '.join(from_json(e) for e in val)})"
        else:
            return str(val)