Skip to content

Commit 36e3fdc

Browse files
committed
Split in-memory with fs tables
1 parent e0bc87a commit 36e3fdc

5 files changed

Lines changed: 45 additions & 19 deletions

File tree

json_sql/apply.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from typing import List, Dict, Optional
2-
from .tables import TablesSnapshot
2+
from .tables import ITablesSnapshot
33
from .ast import (
44
Expression,
55
StringExpression,
@@ -203,7 +203,7 @@ def apply_select_fields(fields: List[SelectField], data: List[dict], ctx: dict):
203203

204204

205205
def apply_from(
206-
from_part: Optional[From], tables: TablesSnapshot, ctx: dict
206+
from_part: Optional[From], tables: ITablesSnapshot, ctx: dict
207207
) -> List[dict]:
208208
if from_part is None:
209209
return [{}]
@@ -225,7 +225,7 @@ def apply_from(
225225
return data
226226

227227

228-
def apply_select(select: Select, tables: TablesSnapshot, ctx: dict):
228+
def apply_select(select: Select, tables: ITablesSnapshot, ctx: dict):
229229
data = apply_from(select.from_part, tables, ctx)
230230
if select.where_part:
231231
data = apply_where(select.where_part, data, ctx)
@@ -240,7 +240,7 @@ def apply_select(select: Select, tables: TablesSnapshot, ctx: dict):
240240
return data
241241

242242

243-
def apply_command(command: Command, tables: TablesSnapshot, ctx: dict):
243+
def apply_command(command: Command, tables: ITablesSnapshot, ctx: dict):
244244
if isinstance(command, Select):
245245
return apply_select(command, tables, ctx)
246246
else:

json_sql/cli.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
from typing import List
22
from pathlib import Path
3-
from json_sql.tables import TablesSnapshot, Table
3+
from json_sql.tables import FileSystemTables, Table
44
from json import loads
55
from eval import eval_sql
66

77

8-
def query(code: str, json_paths: List[Path], ctx: dict) -> List[dict]:
9-
tables = TablesSnapshot(
10-
tables=[
11-
Table(name=path.stem, columns=[], data=loads(path.read_text()))
12-
for path in json_paths
13-
]
14-
)
15-
return eval_sql(code=code, tables=tables, ctx=ctx)
8+
def query(code: str, workdir: Path, ctx: dict):
9+
tables = FileSystemTables(workdir=workdir)
10+
result = eval_sql(code=code, tables=tables, ctx=ctx)
11+
return result
1612

1713

1814
def help(): ...

json_sql/eval.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from .lexer import scan
22
from .parser import parse
33
from .apply import apply_command
4-
from .tables import TablesSnapshot
4+
from .tables import ITablesSnapshot
55

66

7-
def eval_sql(code: str, tables: TablesSnapshot, ctx: dict):
7+
def eval_sql(code: str, tables: ITablesSnapshot, ctx: dict):
88
tokens = scan(code)
99
ast = parse(tokens)
1010
result = apply_command(command=ast, tables=tables, ctx=ctx)

json_sql/eval_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from unittest import TestCase
22
from .eval import eval_sql
3-
from .tables import TablesSnapshot, Table, Column
3+
from .tables import InMemoryTables
44

55

66
class TestEvalSQL(TestCase):
77
def test_eval_sql(self):
88
code = "select 1+1"
9-
tables = TablesSnapshot(
9+
tables = InMemoryTables(
1010
tables=[],
1111
)
1212
ctx = {}
@@ -15,7 +15,7 @@ def test_eval_sql(self):
1515

1616
def test_eval_select_alias(self):
1717
code = "select 1+1 as a"
18-
tables = TablesSnapshot(
18+
tables = InMemoryTables(
1919
tables=[],
2020
)
2121
ctx = {}

json_sql/tables.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
from typing import List, Optional
22
from pydantic import BaseModel
3+
from pathlib import Path
4+
from abc import ABC, abstractmethod
5+
import json
36

47

58
class ForeignKey(BaseModel):
@@ -20,11 +23,38 @@ class Table(BaseModel):
2023
data: List[dict] = []
2124

2225

23-
class TablesSnapshot(BaseModel):
26+
class ITablesSnapshot(ABC):
27+
@abstractmethod
28+
def get_table(self, name: str) -> Optional[Table]:
29+
raise NotImplementedError("get_table method must be implemented")
30+
31+
32+
class InMemoryTables(BaseModel, ITablesSnapshot):
2433
tables: List[Table]
2534

2635
def get_table(self, name: str) -> Optional[Table]:
2736
for table in self.tables:
2837
if table.name == name:
2938
return table
3039
return None
40+
41+
42+
class FileSystemTables(ITablesSnapshot):
43+
workdir: Path
44+
45+
def __init__(self, workdir: Path):
46+
self.workdir = workdir
47+
48+
def get_table(self, name: str):
49+
table_path = self.workdir / f"{name}.json"
50+
if not table_path.exists():
51+
raise FileNotFoundError(f"File {table_path} does not exist")
52+
rows = json.loads(table_path.read_text())
53+
columns = set()
54+
for row in rows:
55+
assert isinstance(row, dict), f"Row {row} is not a dictionary"
56+
for key, value in row.items():
57+
if key not in columns:
58+
col = Column(name=key, type=type(value).__name__)
59+
columns.add(col)
60+
return Table(name=name, columns=list(columns), data=rows)

0 commit comments

Comments
 (0)