Edit on GitHub

sqlglot.serde

  1from __future__ import annotations
  2
  3import typing as t
  4
  5from sqlglot import expressions as exp
  6
  7
  8INDEX = "i"
  9ARG_KEY = "k"
 10IS_ARRAY = "a"
 11CLASS = "c"
 12TYPE = "t"
 13COMMENTS = "o"
 14META = "m"
 15VALUE = "v"
 16DATA_TYPE = "DataType.Type"
 17
 18
 19def dump(expression: exp.Expr) -> list[dict[str, t.Any]]:
 20    """
 21    Dump an Expr into a JSON serializable List.
 22    """
 23    i = 0
 24    payloads = []
 25    stack: list[tuple[t.Any, int | None, str | None, bool]] = [(expression, None, None, False)]
 26
 27    while stack:
 28        node, index, arg_key, is_array = stack.pop()
 29
 30        payload: dict[str, t.Any] = {}
 31
 32        if index is not None:
 33            payload[INDEX] = index
 34        if arg_key is not None:
 35            payload[ARG_KEY] = arg_key
 36        if is_array:
 37            payload[IS_ARRAY] = is_array
 38
 39        payloads.append(payload)
 40
 41        if hasattr(node, "parent"):
 42            klass = node.__class__.__qualname__
 43
 44            if node.__class__.__module__ != exp.__name__:
 45                klass = f"{node.__module__}.{klass}"
 46
 47            payload[CLASS] = klass
 48
 49            if node.type:
 50                payload[TYPE] = dump(node.type)
 51            if node.comments:
 52                payload[COMMENTS] = node.comments
 53            if node._meta is not None:
 54                payload[META] = node._meta
 55            if node.args:
 56                for k, vs in reversed(node.args.items()):
 57                    if type(vs) is list:
 58                        for v in reversed(vs):
 59                            stack.append((v, i, k, True))
 60                    elif vs is not None:
 61                        stack.append((vs, i, k, False))
 62        elif type(node) is exp.DType:
 63            payload[CLASS] = DATA_TYPE
 64            payload[VALUE] = node.value
 65        else:
 66            payload[VALUE] = node
 67
 68        i += 1
 69
 70    return payloads
 71
 72
 73def load(
 74    payloads: list[dict[str, t.Any]] | None,
 75) -> exp.Expr | exp.DType | None:
 76    """
 77    Load a list of dicts generated by dump into an Expr.
 78    """
 79
 80    if not payloads:
 81        return None
 82
 83    payload, *tail = payloads
 84    root = _load(payload)
 85    nodes: list[object] = [root]
 86    for payload in tail:
 87        if CLASS in payload:
 88            node: object = _load(payload)
 89        else:
 90            node = payload[VALUE]
 91
 92        nodes.append(node)
 93        parent = nodes[payload[INDEX]]
 94        arg_key = payload[ARG_KEY]
 95
 96        if payload.get(IS_ARRAY):
 97            parent.append(arg_key, node)
 98        else:
 99            parent.set(arg_key, node)
100
101    return root
102
103
104def _load(payload: dict[str, t.Any]) -> exp.Expr | exp.DType:
105    class_name = payload[CLASS]
106
107    if class_name == DATA_TYPE:
108        return exp.DType(payload[VALUE])
109
110    if "." in class_name:
111        module_path, class_name = class_name.rsplit(".", maxsplit=1)
112        module = __import__(module_path, fromlist=[class_name])
113    else:
114        module = exp
115
116    expression = getattr(module, class_name)()
117    expression._type = load(payload.get(TYPE))
118    expression.comments = payload.get(COMMENTS)
119    expression._meta = payload.get(META)
120    return expression
INDEX = 'i'
ARG_KEY = 'k'
IS_ARRAY = 'a'
CLASS = 'c'
TYPE = 't'
COMMENTS = 'o'
META = 'm'
VALUE = 'v'
DATA_TYPE = 'DataType.Type'
def dump(expression: sqlglot.expressions.core.Expr) -> list[dict[str, typing.Any]]:
20def dump(expression: exp.Expr) -> list[dict[str, t.Any]]:
21    """
22    Dump an Expr into a JSON serializable List.
23    """
24    i = 0
25    payloads = []
26    stack: list[tuple[t.Any, int | None, str | None, bool]] = [(expression, None, None, False)]
27
28    while stack:
29        node, index, arg_key, is_array = stack.pop()
30
31        payload: dict[str, t.Any] = {}
32
33        if index is not None:
34            payload[INDEX] = index
35        if arg_key is not None:
36            payload[ARG_KEY] = arg_key
37        if is_array:
38            payload[IS_ARRAY] = is_array
39
40        payloads.append(payload)
41
42        if hasattr(node, "parent"):
43            klass = node.__class__.__qualname__
44
45            if node.__class__.__module__ != exp.__name__:
46                klass = f"{node.__module__}.{klass}"
47
48            payload[CLASS] = klass
49
50            if node.type:
51                payload[TYPE] = dump(node.type)
52            if node.comments:
53                payload[COMMENTS] = node.comments
54            if node._meta is not None:
55                payload[META] = node._meta
56            if node.args:
57                for k, vs in reversed(node.args.items()):
58                    if type(vs) is list:
59                        for v in reversed(vs):
60                            stack.append((v, i, k, True))
61                    elif vs is not None:
62                        stack.append((vs, i, k, False))
63        elif type(node) is exp.DType:
64            payload[CLASS] = DATA_TYPE
65            payload[VALUE] = node.value
66        else:
67            payload[VALUE] = node
68
69        i += 1
70
71    return payloads

Dump an Expr into a JSON serializable List.

def load( payloads: list[dict[str, typing.Any]] | None) -> sqlglot.expressions.core.Expr | sqlglot.expressions.datatypes.DType | None:
 74def load(
 75    payloads: list[dict[str, t.Any]] | None,
 76) -> exp.Expr | exp.DType | None:
 77    """
 78    Load a list of dicts generated by dump into an Expr.
 79    """
 80
 81    if not payloads:
 82        return None
 83
 84    payload, *tail = payloads
 85    root = _load(payload)
 86    nodes: list[object] = [root]
 87    for payload in tail:
 88        if CLASS in payload:
 89            node: object = _load(payload)
 90        else:
 91            node = payload[VALUE]
 92
 93        nodes.append(node)
 94        parent = nodes[payload[INDEX]]
 95        arg_key = payload[ARG_KEY]
 96
 97        if payload.get(IS_ARRAY):
 98            parent.append(arg_key, node)
 99        else:
100            parent.set(arg_key, node)
101
102    return root

Load a list of dicts generated by dump into an Expr.