Search code examples
jsonpostgresqllisphy

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


We are trying to use hylang as DSL for some financial business flow. We were trying to use business rules as JSON, but switched to DSL using hy language. Now we need to persist s-expression items into postgreSQL as like previous JSON-B items. Is there a standard way to do this or we have to use text fields instead?

Previous:

  "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"
        }
  }

Current:

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

)


Solution

  • There are 2 solutions:

    1. Using libraries like 'sexpdata' for parsing and unparsing S-Expresisons to/from Python list, and then using JSON plus some custom enc/dec.

    2. Using pyparsing for parsing S-Expression into Python list and then using 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)