From 04653793c850f62a367d36d766b5c8946cbb8726 Mon Sep 17 00:00:00 2001 From: sean Date: Wed, 26 Apr 2023 16:32:42 -0400 Subject: [PATCH 1/4] Update pre-commit config. --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 53ef6b1..71052de 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,8 +3,8 @@ repos: rev: v1.2.0 hooks: - id: mypy - exclude: '.*tests/.*|.*docs/.*' - args: ["--show-error-codes"] + exclude: '.*tests/.*|.*docs/.*|.*examples/.*' + args: ["--show-error-codes", "--config=pyproject.toml"] additional_dependencies: [types-orjson] - repo: https://github.com/ambv/black rev: 23.3.0 From b16fb121f9cb867e889ea9f540a6091960add81d Mon Sep 17 00:00:00 2001 From: sean Date: Wed, 26 Apr 2023 16:33:05 -0400 Subject: [PATCH 2/4] Update README.md --- README.md | 54 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index c5d74ab..546b41c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,14 @@ # YeSQL +[![image](https://img.shields.io/pypi/v/yesql.svg)](https://pypi.org/project/yesql/) +[![image](https://img.shields.io/pypi/l/yesql.svg)](https://pypi.org/project/yesql/) +[![image](https://img.shields.io/pypi/pyversions/yesql.svg)](https://pypi.org/project/yesql/) +[![image](https://img.shields.io/github/languages/code-size/seandstewart/yesql.svg?style=flat)](https://github.com/seandstewart/yesql) +[![Test & Lint](https://github.com/seandstewart/yesql/workflows/Test/badge.svg)](https://github.com/seandstewart/yesql/actions) +[![Coverage](https://codecov.io/gh/seandstewart/yesql/branch/main/graph/badge.svg)](https://codecov.io/gh/seandstewart/yesql) +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) + + Say YES to SQL with YeSQL. YeSQL eliminates boilerplate without the baggage of an expensive or clunky ORM. Simply write your SQL and point YeSQL to the directory, and it does all the rest. @@ -16,35 +25,34 @@ pip install -U yesql ### Basic Usage ```python +from __future__ import annotations + import dataclasses import datetime import pathlib -from typing import Optional, Set -import typic import yesql QUERIES = pathlib.Path(__file__).resolve().parent / "queries" -@typic.slotted(dict=False, weakref=True) -@dataclasses.dataclass +@dataclasses.dataclass(slots=True, kw_only=True) class Post: - id: Optional[int] = None - slug: Optional[str] = None - title: Optional[str] = None - subtitle: Optional[str] = None - tagline: Optional[str] = None - body: Optional[str] = None - tags: Set[str] = dataclasses.field(default_factory=set) - publication_date: Optional[datetime.date] = None - created_at: Optional[datetime.datetime] = None - updated_at: Optional[datetime.datetime] = None + id: int | None = None + slug: str | None = None + title: str | None = None + subtitle: str | None = None + tagline: str | None = None + body: str | None = None + tags: set[str] = dataclasses.field(default_factory=set) + publication_date: datetime.date | None = None + created_at: datetime.datetime | None = None + updated_at: datetime.datetime | None = None -class AsyncPosts(yesql.AsyncQueryRepository[Post]): +class PostsRepository(yesql.SyncQueryRepository[Post]): """An asyncio-native service for querying blog posts.""" class metadata(yesql.QueryMetadata): @@ -53,8 +61,23 @@ class AsyncPosts(yesql.AsyncQueryRepository[Post]): __exclude_fields__ = frozenset(("slug",)) + +posts = PostsRepository() +posts.initialize() +new_post = Post( + title="My Great Blog Post", + subtitle="It's super great. Trust me...", + tagline="You'll be glad you read it.", + tags={"tips", "tricks", "cool stuff"}, +) +saved_post = posts.create(instance=new_post) ``` +#### Type-stub Generation (Experimental) + +YeSQL ships with simple CLI for generating type-stubs. This allows for more exact +static type-analysis and enables auto-complete for your IDE. + ## No ORMs? 1. *ORMs are bad for you.* @@ -104,7 +127,6 @@ YeSQL takes a SQL-first approach to data management: - [x] Query Library Bootstrapping - [x] Dynamic Query Library -- [ ] CLI for stamping new libraries or services - [ ] Full Documentation Coverage - [ ] Full Test Coverage - [ ] Dialect Support From 768eecc387da60d72ff7c46bcfa41967d6d586ad Mon Sep 17 00:00:00 2001 From: sean Date: Wed, 26 Apr 2023 16:35:57 -0400 Subject: [PATCH 3/4] Flesh out stubgen CLI and add initial pre-commit hook configuration. --- .pre-commit-hooks.yaml | 9 + docs/index.md | 10 +- examples/pg/db/client.pyi | 2246 +++++++++++++++++++++++++++++++++++++ poetry.lock | 19 +- pyproject.toml | 6 +- yesql/bin/main.py | 38 + yesql/bin/stubgen.py | 17 +- yesql/py.typed | 0 yesql/stubgen.py | 13 +- 9 files changed, 2330 insertions(+), 28 deletions(-) create mode 100644 .pre-commit-hooks.yaml create mode 100644 examples/pg/db/client.pyi create mode 100644 yesql/bin/main.py create mode 100644 yesql/py.typed diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 0000000..bc55029 --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,9 @@ +- id: yesql-stubgen + name: yesql Stubgen + entry: yesql stubgen + language: python + types: + - python + pass_filenames: true + additional_dependencies: + - black diff --git a/docs/index.md b/docs/index.md index c5d74ab..ac7b438 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ -# YeSQL +# yesql -Say YES to SQL with YeSQL. YeSQL eliminates boilerplate without the baggage of an -expensive or clunky ORM. Simply write your SQL and point YeSQL to the directory, and it +Say YES to SQL with yesql. yesql eliminates boilerplate without the baggage of an +expensive or clunky ORM. Simply write your SQL and point yesql to the directory, and it does all the rest. ## Quickstart @@ -80,9 +80,9 @@ class AsyncPosts(yesql.AsyncQueryRepository[Post]): reasonable means of mitigation. -## Why YeSQL? +## Why yesql? -YeSQL takes a SQL-first approach to data management: +yesql takes a SQL-first approach to data management: 1. *Focus on your SQL and your database.* - Reduce developer overhead by having one less middleman between you and your data. diff --git a/examples/pg/db/client.pyi b/examples/pg/db/client.pyi new file mode 100644 index 0000000..7eace17 --- /dev/null +++ b/examples/pg/db/client.pyi @@ -0,0 +1,2246 @@ +import typing +import pathlib +from typing import Iterable, cast + +import yesql + +from .model import Post + +QUERIES = pathlib.Path(__file__).resolve().parent / "queries" + +class AsyncPosts(yesql.AsyncQueryRepository[Post]): + """An asyncio-native service for querying blog posts.""" + + model = Post + + class metadata(yesql.QueryMetadata): + __querylib__ = QUERIES + __tablename__ = "posts" + __exclude_fields__ = frozenset(("slug",)) + async def bulk_create_returning( + self, + posts: Iterable[Post], + *, + connection: yesql.types.ConnectionT = None, + coerce: bool = True, + ): + """An example of overriding the default implementation for a specific use-case. + + In this case, the query is implemented to take an array of posts as a single + input. This allows a bulk operation to occur with a single, atomic query, + rather than as a series of executions. + + This query isn't compatible with the default implementation of a mutation, + but as you can see, it's quite straight-forward to customize your query methods + if necessary. + """ + query = cast(yesql.parse.QueryDatum, self.queries.mutate.bulk_create_returning) + return await self.executor.many( + query, + posts=[self.get_kvs(p) for p in posts], + connection=connection, + transaction=True, + coerce=coerce, + deserializer=self.serdes.bulk_deserializer, + ) + @typing.overload + def get( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Get a blog post by id.""" + @typing.overload + def get( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Get a blog post by id.""" + @typing.overload + def get( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Get a blog post by id.""" + @typing.overload + def get( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Get a blog post by id.""" + @typing.overload + def get( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Get a blog post by id.""" + @typing.overload + def get( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Get a blog post by id.""" + @typing.overload + def get_by_slug( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Get a blog post by slug.""" + @typing.overload + def get_by_slug( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Get a blog post by slug.""" + @typing.overload + def get_by_slug( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Get a blog post by slug.""" + @typing.overload + def get_by_slug( + self, + /, + *, + slug, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Get a blog post by slug.""" + @typing.overload + def get_by_slug( + self, + /, + *, + slug, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Get a blog post by slug.""" + @typing.overload + def get_by_slug( + self, + /, + *, + slug, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Get a blog post by slug.""" + @typing.overload + def get_by_tags( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags( + self, + /, + *, + tags, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags( + self, + /, + *, + tags, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags( + self, + /, + *, + tags, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags_cursor( + self, + /, + *, + tags, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags_cursor( + self, + /, + *, + tags, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get blog posts matching the given tags.""" + @typing.overload + def get_by_tags_cursor( + self, + /, + *, + tags, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get blog posts matching the given tags.""" + @typing.overload + def all( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Get all blog posts.""" + @typing.overload + def all( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Get all blog posts.""" + @typing.overload + def all( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Get all blog posts.""" + @typing.overload + def all( + self, + /, + *, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Get all blog posts.""" + @typing.overload + def all( + self, + /, + *, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Get all blog posts.""" + @typing.overload + def all( + self, + /, + *, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Get all blog posts.""" + @typing.overload + def all_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts.""" + @typing.overload + def all_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts.""" + @typing.overload + def all_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts.""" + @typing.overload + def all_cursor( + self, + /, + *, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts.""" + @typing.overload + def all_cursor( + self, + /, + *, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts.""" + @typing.overload + def all_cursor( + self, + /, + *, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts.""" + @typing.overload + def published( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published( + self, + /, + *, + date, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published( + self, + /, + *, + date, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published( + self, + /, + *, + date, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published_cursor( + self, + /, + *, + date, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published_cursor( + self, + /, + *, + date, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def published_cursor( + self, + /, + *, + date, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Get all blog posts which have been published up to this date.""" + @typing.overload + def search( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search( + self, + /, + *, + words, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search( + self, + /, + *, + words, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search( + self, + /, + *, + words, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search_cursor( + self, + /, + *, + words, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search_cursor( + self, + /, + *, + words, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search_cursor( + self, + /, + *, + words, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts using full-text a generalized word search.""" + @typing.overload + def search_phrase( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase( + self, + /, + *, + phrase, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase( + self, + /, + *, + phrase, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase( + self, + /, + *, + phrase, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase_cursor( + self, + /, + *, + phrase, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase_cursor( + self, + /, + *, + phrase, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def search_phrase_cursor( + self, + /, + *, + phrase, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Search all blog posts for a particular phrase.""" + @typing.overload + def create( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Create a new blog post :)""" + @typing.overload + def create( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Create a new blog post :)""" + @typing.overload + def create( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Create a new blog post :)""" + @typing.overload + def create( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Create a new blog post :)""" + @typing.overload + def create( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Create a new blog post :)""" + @typing.overload + def create( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Create a new blog post :)""" + @typing.overload + def bulk_create( + self, + /, + *, + instances: "typing.Sequence[Post]" = (), + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + returns: "bool" = False, + deserializer: "yesql.types.DeserializerT | None" = None, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Create a new blog post :)""" + @typing.overload + def bulk_create( + self, + /, + *, + instances: "typing.Sequence[Post]" = (), + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + returns: "bool" = False, + deserializer: "yesql.types.DeserializerT | None" = None, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Create a new blog post :)""" + @typing.overload + def bulk_create( + self, + /, + *, + instances: "typing.Sequence[Post]" = (), + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + returns: "bool" = False, + deserializer: "yesql.types.DeserializerT | None" = None, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Create a new blog post :)""" + @typing.overload + def bulk_create( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + returns: "bool" = False, + deserializer: "yesql.types.DeserializerT | None" = None, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Create a new blog post :)""" + @typing.overload + def bulk_create( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + returns: "bool" = False, + deserializer: "yesql.types.DeserializerT | None" = None, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Create a new blog post :)""" + @typing.overload + def bulk_create( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + returns: "bool" = False, + deserializer: "yesql.types.DeserializerT | None" = None, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_cursor( + self, + /, + *, + instances: "typing.Sequence[Post]" = (), + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_cursor( + self, + /, + *, + instances: "typing.Sequence[Post]" = (), + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_cursor( + self, + /, + *, + instances: "typing.Sequence[Post]" = (), + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_cursor( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_cursor( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_cursor( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + params: "typing.Iterable[typing.Sequence | typing.Mapping[str, typing.Any]]" = (), + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning( + self, + /, + *, + posts, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[list[Post]]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning( + self, + /, + *, + posts, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[list[Post]]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning( + self, + /, + *, + posts, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning_cursor( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning_cursor( + self, + /, + *, + posts, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning_cursor( + self, + /, + *, + posts, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def bulk_create_returning_cursor( + self, + /, + *, + posts, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.AsyncContextManager[yesql.types.CursorT]": + """Create a new blog post :)""" + @typing.overload + def update( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Update a post with all new data.""" + @typing.overload + def update( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Update a post with all new data.""" + @typing.overload + def update( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Update a post with all new data.""" + @typing.overload + def update( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Update a post with all new data.""" + @typing.overload + def update( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Update a post with all new data.""" + @typing.overload + def update( + self, + /, + *, + title, + subtitle, + tagline, + tags, + body, + publication_date, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Update a post with all new data.""" + @typing.overload + def delete( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Delete a post.""" + @typing.overload + def delete( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Delete a post.""" + @typing.overload + def delete( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Delete a post.""" + @typing.overload + def delete( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Delete a post.""" + @typing.overload + def delete( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Delete a post.""" + @typing.overload + def delete( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Delete a post.""" + @typing.overload + def publish( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Set the publication date for a blog post.""" + @typing.overload + def publish( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Set the publication date for a blog post.""" + @typing.overload + def publish( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Set the publication date for a blog post.""" + @typing.overload + def publish( + self, + /, + *, + publication_date, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """Set the publication date for a blog post.""" + @typing.overload + def publish( + self, + /, + *, + publication_date, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """Set the publication date for a blog post.""" + @typing.overload + def publish( + self, + /, + *, + publication_date, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Set the publication date for a blog post.""" + @typing.overload + def retract( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """ "Retract" a blog post by clearing out the publication_date.""" + @typing.overload + def retract( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """ "Retract" a blog post by clearing out the publication_date.""" + @typing.overload + def retract( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """ "Retract" a blog post by clearing out the publication_date.""" + @typing.overload + def retract( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + ) -> "typing.Awaitable[Post]": + """ "Retract" a blog post by clearing out the publication_date.""" + @typing.overload + def retract( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[Post]": + """ "Retract" a blog post by clearing out the publication_date.""" + @typing.overload + def retract( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT" = None, + deserializer: "yesql.types.DeserializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """ "Retract" a blog post by clearing out the publication_date.""" + @typing.overload + def add_tags( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.Awaitable[typing.Any]": + """Add new tags for a blog post.""" + @typing.overload + def add_tags( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[typing.Any]": + """Add new tags for a blog post.""" + @typing.overload + def add_tags( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Add new tags for a blog post.""" + @typing.overload + def add_tags( + self, + /, + *, + tags, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.Awaitable[typing.Any]": + """Add new tags for a blog post.""" + @typing.overload + def add_tags( + self, + /, + *, + tags, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[typing.Any]": + """Add new tags for a blog post.""" + @typing.overload + def add_tags( + self, + /, + *, + tags, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Add new tags for a blog post.""" + @typing.overload + def remove_tag( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.Awaitable[typing.Any]": + """Remove tags for this blog post""" + @typing.overload + def remove_tag( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[typing.Any]": + """Remove tags for this blog post""" + @typing.overload + def remove_tag( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Remove tags for this blog post""" + @typing.overload + def remove_tag( + self, + /, + *, + tags, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.Awaitable[typing.Any]": + """Remove tags for this blog post""" + @typing.overload + def remove_tag( + self, + /, + *, + tags, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[typing.Any]": + """Remove tags for this blog post""" + @typing.overload + def remove_tag( + self, + /, + *, + tags, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[typing.Any]": + """Remove tags for this blog post""" + @typing.overload + def clear_tags( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def clear_tags( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def clear_tags( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def clear_tags( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def clear_tags( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def clear_tags( + self, + /, + *, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def set_body( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def set_body( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def set_body( + self, + /, + *, + instance: "Post | None" = None, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def set_body( + self, + /, + *, + body, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def set_body( + self, + /, + *, + body, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[True]", + ) -> "typing.Awaitable[int]": + """ """ + @typing.overload + def set_body( + self, + /, + *, + body, + id, + connection: "yesql.types.ConnectionT" = None, + timeout: "float" = 10, + transaction: "bool" = True, + rollback: "bool" = False, + serializer: "yesql.types.SerializerT | None" = None, + coerce: "typing.Literal[False]", + ) -> "typing.Awaitable[int]": + """ """ + +SyncPosts = yesql.servicemaker( + model=Post, + querylib=QUERIES, + tablename="posts", + isaio=False, + exclude_fields=frozenset(("slug",)), +) diff --git a/poetry.lock b/poetry.lock index 63649e2..0368e65 100644 --- a/poetry.lock +++ b/poetry.lock @@ -84,7 +84,7 @@ tzdata = ["tzdata"] name = "black" version = "23.3.0" description = "The uncompromising code formatter." -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -263,7 +263,7 @@ files = [ name = "click" version = "8.1.3" description = "Composable command line interface toolkit" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -278,7 +278,7 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "dev" +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -771,7 +771,7 @@ reports = ["lxml"] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -865,7 +865,7 @@ files = [ name = "packaging" version = "23.1" description = "Core utilities for Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -892,7 +892,7 @@ six = "*" name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -939,7 +939,7 @@ pytzdata = ">=2020.1" name = "platformdirs" version = "3.4.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1409,7 +1409,7 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1569,9 +1569,10 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [extras] asyncpg = ["asyncpg", "orjson"] +cli = ["black"] psycopg = ["orjson", "psycopg"] [metadata] lock-version = "2.0" python-versions = ">=3.8.1,<4.0" -content-hash = "631a871ee1bf0a579639b89cab5f73f4546f7abfa25524b25bd7028d1694134d" +content-hash = "b52b742300c60ed397909a7cd95d8a2f96fd78c76ef16ba8de32e277572af6cc" diff --git a/pyproject.toml b/pyproject.toml index 78b98cc..00328ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "yesql" version = "1.0.0b0" -description = "YeSQL is a SQL-first data manipulation library that will replace your ORM." +description = "yesql is a SQL-first data access library that will replace your ORM." authors = ["Sean Stewart "] license = "MIT" keywords = ["typing", "data", "annotations", "validation", "json-schema"] @@ -25,7 +25,7 @@ classifiers = [ [tool.poetry.scripts] -"yesql-type-stubs" = "yesql.bin.stubgen:main" +"yesql" = "yesql.bin.main:run" [tool.poetry.dependencies] python = ">=3.8.1,<4.0" @@ -35,6 +35,7 @@ orjson = "^3" sqlparse = "^0.4" asyncpg = {version = "^0.27", optional = true} psycopg = {extras = ["binary", "pool"], version = "^3.1", optional = true} +black = {version = "^23", optional = true} [tool.poetry.group.docs.dependencies] mkdocs ="^1.2.2" @@ -61,6 +62,7 @@ bumpver = "^2022.1120" [tool.poetry.extras] asyncpg = ["asyncpg", "orjson"] psycopg = ["psycopg", "orjson"] +cli = ["black"] [tool.mypy] mypy_path = "$MYPY_CONFIG_FILE_DIR/yesql" diff --git a/yesql/bin/main.py b/yesql/bin/main.py new file mode 100644 index 0000000..5edfee0 --- /dev/null +++ b/yesql/bin/main.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import sys +import types + +from yesql.bin import stubgen + + +def get_parser(): + parser = argparse.ArgumentParser() + subparsers = parser.add_subparsers() + for name, module in SUB_COMMANDS.items(): + # https://docs.python.org/3/library/argparse.html#sub-commands + sub_parser = subparsers.add_parser(name) + sub_parser.set_defaults(run=module.run) + module.configure_parser(sub_parser) + return parser + + +SUB_COMMANDS: dict[str, types.ModuleType] = { + "stubgen": stubgen, +} + + +def run(): + parser = get_parser() + args = parser.parse_args() + if "run" not in vars(args): + parser.print_help(sys.stderr) + parser.exit(2) + + return args.run(args) + + +if __name__ == "__main__": + run() diff --git a/yesql/bin/stubgen.py b/yesql/bin/stubgen.py index 6ace8de..df4b274 100644 --- a/yesql/bin/stubgen.py +++ b/yesql/bin/stubgen.py @@ -10,9 +10,7 @@ from yesql import stubgen -def main(): - parse = parser() - args = parse.parse_args() +def run(args: argparse.Namespace): sources = args.source or ["."] stubbed = stub_package(*sources) if stubbed: @@ -23,11 +21,12 @@ def main(): sys.exit(1) -def parser(): - parse = argparse.ArgumentParser() +def configure_parser( + parser: argparse.ArgumentParser | None = None, +) -> argparse.ArgumentParser: + parse = parser or argparse.ArgumentParser() parse.add_argument( - "--source", - "-S", + "source", action="append", default=[], type=str, @@ -153,7 +152,3 @@ def dynamic_import(module_name: str, py_path: pathlib.Path) -> ModuleType: module = importlib.util.module_from_spec(module_spec) module_spec.loader.exec_module(module) # type: ignore[attr-defined] return module - - -if __name__ == "__main__": - main() diff --git a/yesql/py.typed b/yesql/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/yesql/stubgen.py b/yesql/stubgen.py index 5f902dc..449cb50 100644 --- a/yesql/stubgen.py +++ b/yesql/stubgen.py @@ -9,6 +9,7 @@ from types import ModuleType from typing import TypedDict +import black from yesql.core.parse import QueryDatum from yesql.repository import BaseQueryRepository from yesql.statement import Statement @@ -65,7 +66,9 @@ def get_stub_module(module: ModuleType) -> str | None: module_def_stub = "import typing\n" + module_def for src, replacement in replacements: module_def_stub = module_def_stub.replace(src, replacement) - return module_def_stub + + module_def_stub_blackened = blacken(module_def_stub) + return module_def_stub_blackened def get_stub_methods(repo: type[BaseQueryRepository]) -> list[str]: @@ -177,6 +180,14 @@ def get_query_params( return query_params +def blacken(code: str) -> str: + pyver = sys.version_info.minor + black_pyver = black.TargetVersion(pyver) + black_mode = black.Mode(is_pyi=True, target_versions={black_pyver}) + blackened = black.format_str(code, mode=black_mode) + return blackened + + class StubSignatures(TypedDict): method_sig: inspect.Signature method_sig_coerce: inspect.Signature From 71d5410889e857ac124e38eba254df007e597569 Mon Sep 17 00:00:00 2001 From: sean Date: Wed, 26 Apr 2023 17:00:24 -0400 Subject: [PATCH 4/4] Update README.md --- README.md | 72 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 546b41c..ee234ac 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# YeSQL +# yesql [![image](https://img.shields.io/pypi/v/yesql.svg)](https://pypi.org/project/yesql/) [![image](https://img.shields.io/pypi/l/yesql.svg)](https://pypi.org/project/yesql/) @@ -9,17 +9,36 @@ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) -Say YES to SQL with YeSQL. YeSQL eliminates boilerplate without the baggage of an -expensive or clunky ORM. Simply write your SQL and point YeSQL to the directory, and it -does all the rest. +Say _yes_ to _SQL_ with **yesql**. -## Quickstart +yesql eliminates boilerplate without the baggage of an expensive or clunky ORM. +Simply write your SQL, point yesql to the directory, and it does all the rest. +## Quickstart ### Installation ```shell -pip install -U yesql +pip install -U --pre yesql +``` +or +```shell +poetry add --allow-prereleases yesql +``` + +yesql currently supports the following database drivers: + +- [asyncpg][1] +- [psycopg][2] + +You can select your driver as an extra when installing yesql _(recommended)_: + +```shell +pip install -U --pre "yesql[psycopg]" +``` +or +```shell +poetry add --allow-prereleases yesql -E asyncpg ``` ### Basic Usage @@ -75,9 +94,31 @@ saved_post = posts.create(instance=new_post) #### Type-stub Generation (Experimental) -YeSQL ships with simple CLI for generating type-stubs. This allows for more exact +yesql ships with simple CLI for generating type-stubs. This allows for more exact static type-analysis and enables auto-complete for your IDE. +Usage: + +```shell +yesql stubgen +``` + +You can optionally supply any number of paths to directories or python modules. The +command will default to the current working directory on the filesystem. + +If you don't have [black][3] installed in your development environment, you should add +the `cli` extra as a development dependency. + +## Features + +- [x] Support for synchronous IO +- [x] Support for asynchronous IO (asyncio) +- [x] Support for PostgreSQL +- [x] Plays well with MyPy +- [x] Plays well with IDEs +- [x] Encourages best-practices for data-access (Separation of Concerns, Repository + Pattern) + ## No ORMs? 1. *ORMs are bad for you.* @@ -85,9 +126,9 @@ static type-analysis and enables auto-complete for your IDE. is to abstract out the details of working with a database. 2. *ORMs are slow.* - ORMs depend upon an extremely high level of abstraction in order to work consistently - across database clients. They also attempt to bridge the gap of data validation and - state management. By attempting to hide the details of managing state from the end + ORMs depend upon a high level of abstraction in order to work across database + clients. They also attempt to bridge the gap of data validation and state + management. By attempting to hide the details of managing state from the end user, they suffer from large computational costs and predict 3. *ORMs are wasteful.* @@ -103,9 +144,9 @@ static type-analysis and enables auto-complete for your IDE. reasonable means of mitigation. -## Why YeSQL? +## Why yesql? -YeSQL takes a SQL-first approach to data management: +yesql takes a SQL-first approach to data management: 1. *Focus on your SQL and your database.* - Reduce developer overhead by having one less middleman between you and your data. @@ -131,7 +172,7 @@ YeSQL takes a SQL-first approach to data management: - [ ] Full Test Coverage - [ ] Dialect Support - [x] Async PostgreSQL (via asyncpg & psycopg3) - - [ ] Async SQLite (via aiosqlite) + - [ ] Async SQLite - [ ] Async MySQL - [x] Sync PostgreSQL - [ ] Sync SQLite @@ -140,3 +181,8 @@ YeSQL takes a SQL-first approach to data management: ## License [MIT](https://sean-dstewart.mit-license.org/) + + +[1]: https://magicstack.github.io/asyncpg/current/ +[2]: https://www.psycopg.org/psycopg3/docs/ +[3]: https://black.readthedocs.io/en/stable/ \ No newline at end of file