Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3ecfa87

Browse filesBrowse files
Allow tables to only be accessible through nested query (#10)
1 parent 592d841 commit 3ecfa87
Copy full SHA for 3ecfa87

File tree

Expand file treeCollapse file tree

7 files changed

+65
-7
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

7 files changed

+65
-7
lines changed
Open diff view settings
Collapse file

‎README.md‎

Copy file name to clipboardExpand all lines: README.md
+4Lines changed: 4 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ res = await async_engine.execute_query(query=query, db_session=db)
119119
| ----- | ----- | ----- | ----- |
120120
| graphql_name | str | None | Customise the graphql type name (defaults to sql tablename) |
121121
| description | str | None | Customise the graphql type descripton |
122+
| query | bool | True | Whether to allow direct querying of table |
122123
| include_fields | list[str] | None | Allow only specific fields to be exposed |
123124
| exclude_fields | list[str] | [] | Block specific fields from being exposed |
124125
| relationships | list[str] | [] | Relationships to be exposed (target table must be registered aswell) |
@@ -129,8 +130,11 @@ res = await async_engine.execute_query(query=query, db_session=db)
129130
| default_limit | int | None | Default number of records that can be returned in 1 query |
130131
| max_limit | int | None | Maximum number of records that can be returned in 1 query |
131132

133+
132134
**NOTE:** if you do not specify include_fields or exclude_fields it will default expose all fields.
133135

136+
**NOTE:** if you specify query=False, then all filtering & ordering & pagination is disabled. This is for the case where a table should only be available via a relationship
137+
134138
**Filtering Options:**
135139

136140
| Type | Supported Filters |
Collapse file

‎src/alchemyql/engine.py‎

Copy file name to clipboardExpand all lines: src/alchemyql/engine.py
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def register(
4040
sqlalchemy_cls,
4141
graphql_name: str | None = None,
4242
description: str | None = None,
43+
query: bool = True,
4344
include_fields: list[str] | None = None,
4445
exclude_fields: list[str] | None = None,
4546
relationships: list[str] | None = None,
@@ -56,6 +57,7 @@ def register(
5657
Options:
5758
- graphql_name - Name to give GraphQL type (defaults to tablename)
5859
- description - Description to give GraphQL type
60+
- query - whether to support direct querying of table
5961
- include_fields - list of column names to expose
6062
- exclude_fields - list of column names not to expose
6163
- relationships - list of relationship names to expose (target table must also be registered before schema is built)
@@ -71,6 +73,7 @@ def register(
7173
sqlalchemy_cls,
7274
graphql_name,
7375
description,
76+
query,
7477
include_fields,
7578
exclude_fields,
7679
relationships,
Collapse file

‎src/alchemyql/models.py‎

Copy file name to clipboardExpand all lines: src/alchemyql/models.py
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,7 @@ class Table:
3333
default_limit : int | None
3434
max_limit : int | None
3535

36+
# Querying Details
37+
query : bool
38+
3639
# fmt: on
Collapse file

‎src/alchemyql/register.py‎

Copy file name to clipboardExpand all lines: src/alchemyql/register.py
+14-4Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def register_transform(
127127
sqlalchemy_cls,
128128
graphql_name: str | None,
129129
description: str | None,
130+
query: bool,
130131
include_fields: list[str] | None,
131132
exclude_fields: list[str] | None,
132133
relationships: list[str] | None,
@@ -143,12 +144,20 @@ def register_transform(
143144
inspected = inspect(sqlalchemy_cls)
144145

145146
fields = build_fields(inspected, include_fields, exclude_fields)
146-
147-
validate_filter_fields(inspected, filter_fields or [])
148-
validate_order_fields(inspected, order_fields or [], default_order)
149-
validate_paginated_fields(pagination, default_limit, max_limit)
150147
validate_relationships(inspected, relationships)
151148

149+
if query:
150+
validate_filter_fields(inspected, filter_fields or [])
151+
validate_order_fields(inspected, order_fields or [], default_order)
152+
validate_paginated_fields(pagination, default_limit, max_limit)
153+
else:
154+
filter_fields = []
155+
order_fields = []
156+
default_order = None
157+
pagination = False
158+
default_limit = None
159+
max_limit = None
160+
152161
# Perform initial transformation
153162
table = Table(
154163
sqlalchemy_cls=sqlalchemy_cls,
@@ -163,6 +172,7 @@ def register_transform(
163172
pagination=pagination,
164173
default_limit=default_limit,
165174
max_limit=max_limit,
175+
query=query,
166176
)
167177

168178
return table
Collapse file

‎src/alchemyql/schema.py‎

Copy file name to clipboardExpand all lines: src/alchemyql/schema.py
+4-3Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,10 @@ def build_gql_schema(tables: list[Table], is_async: bool) -> GraphQLSchema:
159159
)
160160

161161
# Final query field
162-
query_fields[table.graphql_name + "s"] = GraphQLField(
163-
GraphQLList(base_object), args=args, resolve=resolver
164-
)
162+
if table.query:
163+
query_fields[table.graphql_name + "s"] = GraphQLField(
164+
GraphQLList(base_object), args=args, resolve=resolver
165+
)
165166

166167
# Step 4 — Build root query
167168
query = GraphQLObjectType(name="Query", fields=lambda q=query_fields: q)
Collapse file
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
type Query {
2+
sample_table_1s: [sample_table_1]
3+
}
4+
5+
"""SAMPLE_TABLE_1"""
6+
type sample_table_1 {
7+
int_field: Int!
8+
string_field: String!
9+
t2_rel: sample_table_2
10+
}
11+
12+
"""SAMPLE_TABLE_2"""
13+
type sample_table_2 {
14+
int_field: Int!
15+
string_field: String!
16+
}
Collapse file

‎tests/build_schema/test_build_schema.py‎

Copy file name to clipboardExpand all lines: tests/build_schema/test_build_schema.py
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,27 @@ def test_build_schema_d_combination(cls: type[AlchemyQL]):
233233
assert engine.get_schema() == expected
234234

235235

236+
@pytest.mark.parametrize("cls", [AlchemyQLSync, AlchemyQLAsync])
237+
def test_build_schema_d_non_queryable_table(cls: type[AlchemyQL]):
238+
engine = cls()
239+
240+
engine.register(
241+
D_Table_1,
242+
include_fields=["int_field", "string_field"],
243+
relationships=["t2_rel"],
244+
)
245+
engine.register(
246+
D_Table_2,
247+
query=False,
248+
include_fields=["int_field", "string_field"],
249+
)
250+
engine.build_schema()
251+
252+
expected = read_data_file("D_test_case_non_queryable_table.txt")
253+
254+
assert engine.get_schema() == expected
255+
256+
236257
@pytest.mark.parametrize("cls", [AlchemyQLSync, AlchemyQLAsync])
237258
def test_build_with_invalid_relationships(cls: type[AlchemyQL]):
238259
engine = cls()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.