Further gql improvements & added test data #181
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from starlette.responses import JSONResponse
|
||||
|
||||
from api.src.queries.cities import CityGraphType, CityFilter, CitySort
|
||||
from api.src.queries.hello import UserGraphType
|
||||
from api.src.queries.hello import UserGraphType, AuthUserFilter, AuthUserSort, AuthUserGraphType
|
||||
from api.src.queries.user import UserFilter, UserSort
|
||||
from cpl.api.api_module import ApiModule
|
||||
from cpl.application.application_builder import ApplicationBuilder
|
||||
@@ -14,9 +14,12 @@ from cpl.core.utils.cache import Cache
|
||||
from cpl.database.mysql.mysql_module import MySQLModule
|
||||
from cpl.graphql.application.graphql_app import GraphQLApp
|
||||
from cpl.graphql.graphql_module import GraphQLModule
|
||||
from model.post_dao import PostDao
|
||||
from model.post_query import PostFilter, PostSort, PostGraphType
|
||||
from queries.hello import HelloQuery
|
||||
from scoped_service import ScopedService
|
||||
from service import PingService
|
||||
from test_data_seeder import TestDataSeeder
|
||||
|
||||
|
||||
def main():
|
||||
@@ -27,29 +30,38 @@ def main():
|
||||
Configuration.add_json_file(f"appsettings.{Environment.get_host_name()}.json", optional=True)
|
||||
|
||||
# builder.services.add_logging()
|
||||
builder.services.add_structured_logging()
|
||||
builder.services.add_transient(PingService)
|
||||
builder.services.add_module(MySQLModule)
|
||||
builder.services.add_module(ApiModule)
|
||||
builder.services.add_module(GraphQLModule)
|
||||
(
|
||||
builder.services.add_structured_logging()
|
||||
.add_transient(PingService)
|
||||
.add_module(MySQLModule)
|
||||
.add_module(ApiModule)
|
||||
.add_module(GraphQLModule)
|
||||
.add_scoped(ScopedService)
|
||||
.add_cache(AuthUser)
|
||||
.add_cache(Role)
|
||||
.add_transient(CityGraphType)
|
||||
.add_transient(CityFilter)
|
||||
.add_transient(CitySort)
|
||||
.add_transient(UserGraphType)
|
||||
.add_transient(UserFilter)
|
||||
.add_transient(UserSort)
|
||||
.add_transient(AuthUserGraphType)
|
||||
.add_transient(AuthUserFilter)
|
||||
.add_transient(AuthUserSort)
|
||||
.add_transient(HelloQuery)
|
||||
# posts
|
||||
.add_transient(PostDao)
|
||||
.add_transient(PostGraphType)
|
||||
.add_transient(PostFilter)
|
||||
.add_transient(PostSort)
|
||||
|
||||
builder.services.add_scoped(ScopedService)
|
||||
|
||||
builder.services.add_cache(AuthUser)
|
||||
builder.services.add_cache(Role)
|
||||
|
||||
builder.services.add_transient(CityGraphType)
|
||||
builder.services.add_transient(CityFilter)
|
||||
builder.services.add_transient(CitySort)
|
||||
|
||||
builder.services.add_transient(UserGraphType)
|
||||
builder.services.add_transient(UserFilter)
|
||||
builder.services.add_transient(UserSort)
|
||||
|
||||
builder.services.add_transient(HelloQuery)
|
||||
# test data
|
||||
.add_singleton(TestDataSeeder)
|
||||
)
|
||||
|
||||
app = builder.build()
|
||||
app.with_logging()
|
||||
app.with_migrations("./scripts")
|
||||
|
||||
app.with_authentication()
|
||||
app.with_authorization()
|
||||
@@ -66,6 +78,7 @@ def main():
|
||||
schema = app.with_graphql()
|
||||
schema.query.string_field("ping", resolver=lambda: "pong")
|
||||
schema.query.with_query("hello", HelloQuery)
|
||||
schema.query.dao_collection_field(PostGraphType, PostDao, "posts", PostFilter, PostSort)
|
||||
|
||||
app.with_playground()
|
||||
app.with_graphiql()
|
||||
|
||||
0
example/api/src/model/__init__.py
Normal file
0
example/api/src/model/__init__.py
Normal file
30
example/api/src/model/post.py
Normal file
30
example/api/src/model/post.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from datetime import datetime
|
||||
from typing import Self
|
||||
|
||||
from cpl.core.typing import SerialId
|
||||
from cpl.database.abc import DbModelABC
|
||||
|
||||
|
||||
class Post(DbModelABC[Self]):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: int,
|
||||
title: str,
|
||||
content: str,
|
||||
deleted: bool = False,
|
||||
editor_id: SerialId | None = None,
|
||||
created: datetime | None = None,
|
||||
updated: datetime | None = None,
|
||||
):
|
||||
DbModelABC.__init__(self, id, deleted, editor_id, created, updated)
|
||||
self._title = title
|
||||
self._content = content
|
||||
|
||||
@property
|
||||
def title(self) -> str:
|
||||
return self._title
|
||||
|
||||
@property
|
||||
def content(self) -> str:
|
||||
return self._content
|
||||
11
example/api/src/model/post_dao.py
Normal file
11
example/api/src/model/post_dao.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from cpl.database.abc import DbModelDaoABC
|
||||
from model.post import Post
|
||||
|
||||
|
||||
class PostDao(DbModelDaoABC):
|
||||
|
||||
def __init__(self):
|
||||
DbModelDaoABC.__init__(self, Post, "posts")
|
||||
|
||||
self.attribute(Post.title, str)
|
||||
self.attribute(Post.content, str)
|
||||
38
example/api/src/model/post_query.py
Normal file
38
example/api/src/model/post_query.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from cpl.graphql.schema.filter.filter import Filter
|
||||
from cpl.graphql.schema.graph_type import GraphType
|
||||
from cpl.graphql.schema.sort.sort import Sort
|
||||
from cpl.graphql.schema.sort.sort_order import SortOrder
|
||||
from model.post import Post
|
||||
|
||||
class PostFilter(Filter[Post]):
|
||||
def __init__(self):
|
||||
Filter.__init__(self)
|
||||
self.field("id", int)
|
||||
self.field("title", str)
|
||||
self.field("content", str)
|
||||
|
||||
class PostSort(Sort[Post]):
|
||||
def __init__(self):
|
||||
Sort.__init__(self)
|
||||
self.field("id", SortOrder)
|
||||
self.field("title", SortOrder)
|
||||
self.field("content", SortOrder)
|
||||
|
||||
|
||||
class PostGraphType(GraphType[Post]):
|
||||
|
||||
def __init__(self):
|
||||
GraphType.__init__(self)
|
||||
|
||||
self.int_field(
|
||||
"id",
|
||||
resolver=lambda root: root.id,
|
||||
)
|
||||
self.string_field(
|
||||
"title",
|
||||
resolver=lambda root: root.title,
|
||||
)
|
||||
self.string_field(
|
||||
"content",
|
||||
resolver=lambda root: root.content,
|
||||
)
|
||||
@@ -1,11 +1,43 @@
|
||||
from api.src.queries.cities import CityFilter, CitySort, CityGraphType, City
|
||||
from api.src.queries.user import User, UserFilter, UserSort, UserGraphType
|
||||
from cpl.api.middleware.request import get_request
|
||||
from cpl.auth.schema import AuthUserDao, AuthUser
|
||||
from cpl.graphql.schema.filter.filter import Filter
|
||||
from cpl.graphql.schema.graph_type import GraphType
|
||||
from cpl.graphql.schema.query import Query
|
||||
from cpl.graphql.schema.sort.sort import Sort
|
||||
from cpl.graphql.schema.sort.sort_order import SortOrder
|
||||
|
||||
users = [User(i, f"User {i}") for i in range(1, 101)]
|
||||
cities = [City(i, f"City {i}") for i in range(1, 101)]
|
||||
|
||||
class AuthUserFilter(Filter[AuthUser]):
|
||||
def __init__(self):
|
||||
Filter.__init__(self)
|
||||
self.field("id", int)
|
||||
self.field("username", str)
|
||||
|
||||
|
||||
class AuthUserSort(Sort[AuthUser]):
|
||||
def __init__(self):
|
||||
Sort.__init__(self)
|
||||
self.field("id", SortOrder)
|
||||
self.field("username", SortOrder)
|
||||
|
||||
class AuthUserGraphType(GraphType[AuthUser]):
|
||||
|
||||
def __init__(self):
|
||||
GraphType.__init__(self)
|
||||
|
||||
self.int_field(
|
||||
"id",
|
||||
resolver=lambda root: root.id,
|
||||
)
|
||||
self.string_field(
|
||||
"username",
|
||||
resolver=lambda root: root.username,
|
||||
)
|
||||
|
||||
class HelloQuery(Query):
|
||||
def __init__(self):
|
||||
Query.__init__(self)
|
||||
@@ -28,3 +60,10 @@ class HelloQuery(Query):
|
||||
CitySort,
|
||||
resolver=lambda: cities,
|
||||
)
|
||||
self.dao_collection_field(
|
||||
AuthUserGraphType,
|
||||
AuthUserDao,
|
||||
"authUsers",
|
||||
AuthUserFilter,
|
||||
AuthUserSort,
|
||||
)
|
||||
|
||||
10
example/api/src/scripts/0-posts.sql
Normal file
10
example/api/src/scripts/0-posts.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE IF NOT EXISTS `posts` (
|
||||
`id` INT(30) NOT NULL AUTO_INCREMENT,
|
||||
`title` VARCHAR(64) NOT NULL,
|
||||
`content` VARCHAR(512) NOT NULL,
|
||||
deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
editorId INT NULL,
|
||||
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY(`id`)
|
||||
);
|
||||
31
example/api/src/test_data_seeder.py
Normal file
31
example/api/src/test_data_seeder.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from faker import Faker
|
||||
|
||||
from cpl.database.abc import DataSeederABC
|
||||
from cpl.query import Enumerable
|
||||
from model.post import Post
|
||||
from model.post_dao import PostDao
|
||||
|
||||
|
||||
fake = Faker()
|
||||
|
||||
|
||||
class TestDataSeeder(DataSeederABC):
|
||||
|
||||
def __init__(self, posts: PostDao):
|
||||
DataSeederABC.__init__(self)
|
||||
|
||||
self._posts = posts
|
||||
|
||||
async def seed(self):
|
||||
if await self._posts.count() == 0:
|
||||
await self._seed_posts()
|
||||
|
||||
async def _seed_posts(self):
|
||||
posts = Enumerable.range(0, 100).select(
|
||||
lambda x: Post(
|
||||
id=0,
|
||||
title=fake.sentence(nb_words=6),
|
||||
content=fake.paragraph(nb_sentences=6),
|
||||
)
|
||||
).to_list()
|
||||
await self._posts.create_many(posts, skip_editor=True)
|
||||
@@ -5,16 +5,16 @@ from cpl.core.typing import SerialId
|
||||
from cpl.database.abc.db_model_abc import DbModelABC
|
||||
|
||||
|
||||
class City(DbModelABC):
|
||||
class City(DbModelABC[Self]):
|
||||
def __init__(
|
||||
self,
|
||||
id: int,
|
||||
name: str,
|
||||
zip: str,
|
||||
deleted: bool = False,
|
||||
editor_id: Optional[SerialId] = None,
|
||||
created: Optional[datetime] = None,
|
||||
updated: Optional[datetime] = None,
|
||||
editor_id: SerialId | None = None,
|
||||
created: datetime | None= None,
|
||||
updated: datetime | None= None,
|
||||
):
|
||||
DbModelABC.__init__(self, id, deleted, editor_id, created, updated)
|
||||
self._name = name
|
||||
|
||||
@@ -5,7 +5,7 @@ from cpl.core.typing import SerialId
|
||||
from cpl.database.abc.db_model_abc import DbModelABC
|
||||
|
||||
|
||||
class User(DbModelABC):
|
||||
class User(DbModelABC[Self]):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -13,9 +13,9 @@ class User(DbModelABC):
|
||||
name: str,
|
||||
city_id: int = 0,
|
||||
deleted: bool = False,
|
||||
editor_id: Optional[SerialId] = None,
|
||||
created: Optional[datetime] = None,
|
||||
updated: Optional[datetime] = None,
|
||||
editor_id: SerialId | None = None,
|
||||
created: datetime | None= None,
|
||||
updated: datetime | None= None,
|
||||
):
|
||||
DbModelABC.__init__(self, id, deleted, editor_id, created, updated)
|
||||
self._name = name
|
||||
|
||||
Reference in New Issue
Block a user