Skip to content

Commit

Permalink
Merge pull request #40 from c3g/develop
Browse files Browse the repository at this point in the history
Version 0.9.0
  • Loading branch information
davidlougheed authored May 14, 2020
2 parents 5d8e851 + 8562e4d commit affdb66
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 29 deletions.
2 changes: 1 addition & 1 deletion chord_lib/package.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = chord_lib
version = 0.8.0
version = 0.9.0
authors = David Lougheed
author_emails = [email protected]
33 changes: 21 additions & 12 deletions chord_lib/search/postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

SQLComposableWithParams = Tuple[sql.Composable, tuple]

QUERY_ROOT = q.Literal("$root")
SQL_ROOT = sql.Identifier("_root")


# TODO: Python 3.7: Data Class
class OptionalComposablePair:
Expand Down Expand Up @@ -93,6 +96,11 @@ def json_schema_to_postgres_schema(name: str, schema: dict) -> Tuple[Optional[sq
)


def _get_search_and_database_properties(schema: dict) -> Tuple[dict, dict]:
search_properties = schema.get("search", {})
return search_properties, search_properties.get("database", {})


def collect_resolve_join_tables(
resolve: Tuple[q.Literal, ...],
schema: dict,
Expand All @@ -114,13 +122,12 @@ def collect_resolve_join_tables(
if len(resolve) == 0:
return ()

search_properties = schema.get("search", {})
search_database_properties = search_properties.get("database", {})
search_properties, search_database_properties = _get_search_and_database_properties(schema)

# TODO: might be able to inject .value under some circumstances here
schema_field = resolve[0].value
db_field = search_database_properties.get("field", schema_field if schema_field != "$root" else None)
current_relation = search_database_properties.get("relation", None)
db_field = search_database_properties.get("field", schema_field if schema_field != QUERY_ROOT.value else None)
current_relation = search_database_properties.get("relation")

new_resolve_path = re.sub(r"[$\[\]]+", "", "{}_{}".format(resolve_path if resolve_path is not None else "",
schema_field))
Expand All @@ -133,7 +140,7 @@ def collect_resolve_join_tables(

# TODO: Additional conditions to check if it's actually JSON
# TODO: HStore support?
structure_type = search_database_properties.get("type", None)
structure_type = search_database_properties.get("type")
if structure_type in ("json", "jsonb"):
if schema["type"] == "array": # JSON(B) array or object
relation_template = "{}_array_elements({})"
Expand Down Expand Up @@ -215,7 +222,7 @@ def collect_join_tables(ast: q.AST, terms: tuple, schema: dict) -> Tuple[JoinAnd

if ast.fn == q.FUNCTION_RESOLVE:
terms = list(terms)
collected_joins = collect_resolve_join_tables((q.Literal("$root"), *ast.args), schema)
collected_joins = collect_resolve_join_tables((QUERY_ROOT, *ast.args), schema)

for j in collected_joins:
existing_aliases = set(t.current_alias_str for t in terms if t is not None)
Expand All @@ -234,9 +241,11 @@ def collect_join_tables(ast: q.AST, terms: tuple, schema: dict) -> Tuple[JoinAnd

def join_fragment(ast: q.AST, schema: dict) -> sql.Composable:
terms = collect_join_tables(ast, (), schema)
if len(terms) == 0:
if not terms: # Query was probably just a literal
# TODO: Don't hard-code _root?
return sql.SQL("(SELECT NULL) AS {}").format(sql.Identifier("_root"))
search_database_properties = _get_search_and_database_properties(schema)[1]
relation = search_database_properties.get("relation")
return sql.SQL("{} AS {}").format(sql.Identifier(relation) if relation else sql.SQL("(SELECT NULL)"), SQL_ROOT)

return sql.SQL(", ").join((
sql.SQL(" LEFT JOIN ").join((
Expand Down Expand Up @@ -269,7 +278,7 @@ def search_query_to_psycopg2_sql(query, schema: dict, internal: bool = False) ->
ast = q.convert_query_to_ast_and_preprocess(query)
sql_obj, params = search_ast_to_psycopg2_expr(ast, (), schema, internal)
# noinspection SqlDialectInspection,SqlNoDataSourceInspection
return sql.SQL("SELECT \"_root\".* FROM {} WHERE {}").format(join_fragment(ast, schema), sql_obj), params
return sql.SQL("SELECT {}.* FROM {} WHERE {}").format(SQL_ROOT, join_fragment(ast, schema), sql_obj), params


def uncurried_binary_op(op: str, args: List[q.AST], params: tuple, schema: dict, internal: bool = False) \
Expand Down Expand Up @@ -300,16 +309,16 @@ def _wildcard(args: List[q.AST], params: tuple, _schema: dict, _internal: bool =


def get_relation(resolve: List[q.Literal], schema: dict):
aliases = collect_resolve_join_tables((q.Literal("$root"), *resolve), schema)[-1].aliases
aliases = collect_resolve_join_tables((QUERY_ROOT, *resolve), schema)[-1].aliases
return aliases.current if aliases.current is not None else aliases.parent


def get_field(resolve: List[q.Literal], schema: dict) -> Optional[str]:
return collect_resolve_join_tables((q.Literal("$root"), *resolve), schema)[-1].field_alias
return collect_resolve_join_tables((QUERY_ROOT, *resolve), schema)[-1].field_alias


def get_search_properties(resolve: List[q.Literal], schema: dict) -> dict:
return collect_resolve_join_tables((q.Literal("$root"), *resolve), schema)[-1].search_properties
return collect_resolve_join_tables((QUERY_ROOT, *resolve), schema)[-1].search_properties


def _resolve(args: List[q.AST], params: tuple, schema: dict, _internal: bool = False) -> SQLComposableWithParams:
Expand Down
22 changes: 11 additions & 11 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
appdirs==1.4.3
appdirs==1.4.4
attrs==19.3.0
certifi==2020.4.5.1
chardet==3.0.4
Expand All @@ -7,10 +7,10 @@ codecov==2.0.22
coverage==5.1
distlib==0.3.0
Django==2.2.12
djangorestframework==3.10.3
djangorestframework==3.11.0
entrypoints==0.3
filelock==3.0.12
flake8==3.7.9
flake8==3.8.1
Flask==1.1.2
idna==2.9
importlib-metadata==1.6.0
Expand All @@ -24,23 +24,23 @@ packaging==20.3
pluggy==0.13.1
psycopg2-binary==2.8.5
py==1.8.1
pycodestyle==2.5.0
pyflakes==2.1.1
pycodestyle==2.6.0
pyflakes==2.2.0
pyparsing==2.4.7
pyrsistent==0.16.0
pytest==5.4.1
pytest==5.4.2
pytest-cov==2.8.1
pytest-django==3.9.0
python-dateutil==2.8.1
pytz==2019.3
redis==3.4.1
pytz==2020.1
redis==3.5.1
requests==2.23.0
six==1.14.0
sqlparse==0.3.1
toml==0.10.0
tox==3.14.6
toml==0.10.1
tox==3.15.0
urllib3==1.25.9
virtualenv==20.0.18
virtualenv==20.0.20
wcwidth==0.1.9
Werkzeug==1.0.1
zipp==3.1.0
10 changes: 5 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
python_requires=">=3.6",
install_requires=[
"jsonschema>=3.2.0,<4",
"psycopg2-binary>=2.8.4,<3.0",
"redis>=3.4.1,<4.0",
"Werkzeug>=1.0,<2.0",
"psycopg2-binary>=2.8.5,<3.0",
"redis>=3.5.1,<4.0",
"Werkzeug>=1.0.1,<2.0",
],
extras_require={
"flask": ["Flask>=1.1,<2.0"],
"django": ["Django>=2.2,<3.0", "djangorestframework>=3.11,<3.12"]
"flask": ["Flask>=1.1.2,<2.0"],
"django": ["Django>=2.2.12,<3.0", "djangorestframework>=3.11,<3.12"]
},

author=config["package"]["authors"],
Expand Down

0 comments on commit affdb66

Please sign in to comment.