munch-ease-backend/users/repository.py

118 lines
3.7 KiB
Python
Raw Permalink Normal View History

async def create(conn):
# Users core table
await conn.execute(
"""
CREATE TABLE IF NOT EXISTS User (
id INTEGER PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
display_name TEXT NOT NULL,
profile_photo_url TEXT
);
"""
)
# Local credential storage for password auth
await conn.execute(
"""
CREATE TABLE IF NOT EXISTS LocalCredentials (
user_id INTEGER PRIMARY KEY,
hashed_password TEXT NOT NULL,
FOREIGN KEY(user_id) REFERENCES User(id) ON DELETE CASCADE
);
"""
)
# OAuth provider links (e.g., Google)
await conn.execute(
"""
CREATE TABLE IF NOT EXISTS OAuthCredentials (
user_id INTEGER NOT NULL,
provider TEXT NOT NULL,
provider_user_id TEXT NOT NULL,
PRIMARY KEY (provider, provider_user_id),
FOREIGN KEY(user_id) REFERENCES User(id) ON DELETE CASCADE
);
"""
)
# Helpful indices
2025-11-01 04:34:01 +00:00
await conn.execute("CREATE INDEX IF NOT EXISTS idx_user_email ON User(email);")
async def get_by_email(conn, email: str):
async with conn.execute(
"SELECT id, email, display_name, profile_photo_url FROM User WHERE email = ? LIMIT 1",
(email,),
) as c:
row = await c.fetchone()
if not row:
return None
from users.models import User
return User(id=int(row[0]), email=row[1], display_name=row[2], profile_photo_url=row[3])
async def get_by_id(conn, user_id: int):
async with conn.execute(
"SELECT id, email, display_name, profile_photo_url FROM User WHERE id = ? LIMIT 1",
(user_id,),
) as c:
row = await c.fetchone()
if not row:
return None
from users.models import User
return User(id=int(row[0]), email=row[1], display_name=row[2], profile_photo_url=row[3])
async def get_by_ids(conn, ids: list[int]):
if not ids:
return {}
placeholders = ",".join(["?"] * len(ids))
results: dict[int, "User"] = {}
async with conn.execute(
f"SELECT id, email, display_name, profile_photo_url FROM User WHERE id IN ({placeholders})",
list(ids),
) as c:
async for row in c:
from users.models import User
u = User(id=int(row[0]), email=row[1], display_name=row[2], profile_photo_url=row[3])
results[u.id] = u
return results
async def insert_user(conn, email: str, display_name: str, profile_photo_url: str | None = None):
async with conn.execute(
"INSERT INTO User (email, display_name, profile_photo_url) VALUES (?, ?, ?)",
(email, display_name, profile_photo_url),
) as cur:
user_id = cur.lastrowid
return user_id
async def insert_user_with_id(
conn, user_id: int, email: str, display_name: str, profile_photo_url: str | None = None
):
"""Insert a user with an explicit id (primarily for tests/fixtures)."""
await conn.execute(
"INSERT OR REPLACE INTO User (id, email, display_name, profile_photo_url) VALUES (?, ?, ?, ?)",
(user_id, email, display_name, profile_photo_url),
)
async def set_local_credentials(conn, user_id: int, hashed_password: str):
await conn.execute(
"INSERT OR REPLACE INTO LocalCredentials (user_id, hashed_password) VALUES (?, ?)",
(user_id, hashed_password),
)
async def get_local_password_hash(conn, user_id: int) -> str | None:
async with conn.execute(
"SELECT hashed_password FROM LocalCredentials WHERE user_id = ?",
(user_id,),
) as c:
row = await c.fetchone()
return row[0] if row else None