Skip to content

Python: Eliminate runtime package and use sqlalchemy #939

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions examples/python/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ pytest~=6.2.2
pytest-asyncio~=0.14.0
psycopg2-binary~=2.8.6
asyncpg~=0.21.0
pydantic~=1.7.3
sqlc-python-runtime~=1.0.0
sqlalchemy==1.4.0
13 changes: 9 additions & 4 deletions examples/python/sqlc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"gen": {
"python": {
"out": "src/authors",
"package": "authors"
"package": "authors",
"emit_sync_querier": true,
"emit_async_querier": true
}
}
},
Expand All @@ -19,7 +21,8 @@
"gen": {
"python": {
"out": "src/booktest",
"package": "booktest"
"package": "booktest",
"emit_async_querier": true
}
}
},
Expand All @@ -30,7 +33,8 @@
"gen": {
"python": {
"out": "src/jets",
"package": "jets"
"package": "jets",
"emit_async_querier": true
}
}
},
Expand All @@ -41,7 +45,8 @@
"gen": {
"python": {
"out": "src/ondeck",
"package": "ondeck"
"package": "ondeck",
"emit_async_querier": true
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions examples/python/src/authors/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Code generated by sqlc. DO NOT EDIT.
from typing import Optional

import pydantic
import dataclasses


# Enums

# Models
class Author(pydantic.BaseModel):

@dataclasses.dataclass()
class Author:
id: int
name: str
bio: Optional[str]
Expand Down
147 changes: 83 additions & 64 deletions examples/python/src/authors/query.py
Original file line number Diff line number Diff line change
@@ -1,92 +1,111 @@

# Code generated by sqlc. DO NOT EDIT.
from typing import AsyncIterator, Awaitable, Iterator, Optional, overload
from typing import AsyncIterator, Iterator, Optional

import sqlc_runtime as sqlc
import sqlalchemy
import sqlalchemy.ext.asyncio

from authors import models


CREATE_AUTHOR = """-- name: create_author :one
CREATE_AUTHOR = """-- name: create_author \\:one
INSERT INTO authors (
name, bio
) VALUES (
$1, $2
:p1, :p2
)
RETURNING id, name, bio
"""


DELETE_AUTHOR = """-- name: delete_author :exec
DELETE_AUTHOR = """-- name: delete_author \\:exec
DELETE FROM authors
WHERE id = $1
WHERE id = :p1
"""


GET_AUTHOR = """-- name: get_author :one
GET_AUTHOR = """-- name: get_author \\:one
SELECT id, name, bio FROM authors
WHERE id = $1 LIMIT 1
WHERE id = :p1 LIMIT 1
"""


LIST_AUTHORS = """-- name: list_authors :many
LIST_AUTHORS = """-- name: list_authors \\:many
SELECT id, name, bio FROM authors
ORDER BY name
"""


@overload
def create_author(conn: sqlc.Connection, name: str, bio: Optional[str]) -> Optional[models.Author]:
pass


@overload
def create_author(conn: sqlc.AsyncConnection, name: str, bio: Optional[str]) -> Awaitable[Optional[models.Author]]:
pass


def create_author(conn: sqlc.GenericConnection, name: str, bio: Optional[str]) -> sqlc.ReturnType[Optional[models.Author]]:
return conn.execute_one_model(models.Author, CREATE_AUTHOR, name, bio)


@overload
def delete_author(conn: sqlc.Connection, id: int) -> None:
pass


@overload
def delete_author(conn: sqlc.AsyncConnection, id: int) -> Awaitable[None]:
pass


def delete_author(conn: sqlc.GenericConnection, id: int) -> sqlc.ReturnType[None]:
return conn.execute_none(DELETE_AUTHOR, id)


@overload
def get_author(conn: sqlc.Connection, id: int) -> Optional[models.Author]:
pass


@overload
def get_author(conn: sqlc.AsyncConnection, id: int) -> Awaitable[Optional[models.Author]]:
pass


def get_author(conn: sqlc.GenericConnection, id: int) -> sqlc.ReturnType[Optional[models.Author]]:
return conn.execute_one_model(models.Author, GET_AUTHOR, id)


@overload
def list_authors(conn: sqlc.Connection) -> Iterator[models.Author]:
pass


@overload
def list_authors(conn: sqlc.AsyncConnection) -> AsyncIterator[models.Author]:
pass


def list_authors(conn: sqlc.GenericConnection) -> sqlc.IteratorReturn[models.Author]:
return conn.execute_many_model(models.Author, LIST_AUTHORS)

class Querier:
def __init__(self, conn: sqlalchemy.engine.Connection):
self._conn = conn

def create_author(self, *, name: str, bio: Optional[str]) -> Optional[models.Author]:
row = self._conn.execute(sqlalchemy.text(CREATE_AUTHOR), {"p1": name, "p2": bio}).first()
if row is None:
return None
return models.Author(
id=row[0],
name=row[1],
bio=row[2],
)

def delete_author(self, *, id: int) -> None:
self._conn.execute(sqlalchemy.text(DELETE_AUTHOR), {"p1": id})

def get_author(self, *, id: int) -> Optional[models.Author]:
row = self._conn.execute(sqlalchemy.text(GET_AUTHOR), {"p1": id}).first()
if row is None:
return None
return models.Author(
id=row[0],
name=row[1],
bio=row[2],
)

def list_authors(self) -> Iterator[models.Author]:
result = self._conn.execute(sqlalchemy.text(LIST_AUTHORS))
for row in result:
yield models.Author(
id=row[0],
name=row[1],
bio=row[2],
)


class AsyncQuerier:
def __init__(self, conn: sqlalchemy.ext.asyncio.AsyncConnection):
self._conn = conn

async def create_author(self, *, name: str, bio: Optional[str]) -> Optional[models.Author]:
row = (await self._conn.execute(sqlalchemy.text(CREATE_AUTHOR), {"p1": name, "p2": bio})).first()
if row is None:
return None
return models.Author(
id=row[0],
name=row[1],
bio=row[2],
)

async def delete_author(self, *, id: int) -> None:
await self._conn.execute(sqlalchemy.text(DELETE_AUTHOR), {"p1": id})

async def get_author(self, *, id: int) -> Optional[models.Author]:
row = (await self._conn.execute(sqlalchemy.text(GET_AUTHOR), {"p1": id})).first()
if row is None:
return None
return models.Author(
id=row[0],
name=row[1],
bio=row[2],
)

async def list_authors(self) -> AsyncIterator[models.Author]:
result = await self._conn.stream(sqlalchemy.text(LIST_AUTHORS))
async for row in result:
yield models.Author(
id=row[0],
name=row[1],
bio=row[2],
)

12 changes: 7 additions & 5 deletions examples/python/src/booktest/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,24 @@
import datetime
import enum

import pydantic
import dataclasses



# Enums
class BookType(str, enum.Enum):
FICTION = "FICTION"
NONFICTION = "NONFICTION"


# Models
class Author(pydantic.BaseModel):
@dataclasses.dataclass()
class Author:
author_id: int
name: str


class Book(pydantic.BaseModel):

@dataclasses.dataclass()
class Book:
book_id: int
author_id: int
isbn: str
Expand Down
Loading