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'
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.