77 lines
2.5 KiB
Python
77 lines
2.5 KiB
Python
async def create(conn):
|
|
# Households table
|
|
await conn.execute(
|
|
"""
|
|
CREATE TABLE IF NOT EXISTS Household (
|
|
id INTEGER PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
slug TEXT NOT NULL UNIQUE
|
|
);
|
|
"""
|
|
)
|
|
|
|
# Membership table
|
|
await conn.execute(
|
|
"""
|
|
CREATE TABLE IF NOT EXISTS HouseholdMember (
|
|
user_id INTEGER NOT NULL,
|
|
household_id INTEGER NOT NULL,
|
|
role TEXT NOT NULL,
|
|
PRIMARY KEY (user_id, household_id),
|
|
FOREIGN KEY(user_id) REFERENCES User(id) ON DELETE CASCADE,
|
|
FOREIGN KEY(household_id) REFERENCES Household(id) ON DELETE CASCADE
|
|
);
|
|
"""
|
|
)
|
|
|
|
# Invitations table
|
|
await conn.execute(
|
|
"""
|
|
CREATE TABLE IF NOT EXISTS HouseholdInvitation (
|
|
id INTEGER PRIMARY KEY,
|
|
household_id INTEGER NOT NULL,
|
|
email TEXT NOT NULL,
|
|
invited_by_user_id INTEGER NOT NULL,
|
|
token TEXT NOT NULL UNIQUE,
|
|
expires_at DATETIME NOT NULL,
|
|
status TEXT NOT NULL,
|
|
FOREIGN KEY(household_id) REFERENCES Household(id) ON DELETE CASCADE,
|
|
FOREIGN KEY(invited_by_user_id) REFERENCES User(id) ON DELETE SET NULL
|
|
);
|
|
"""
|
|
)
|
|
|
|
# Indices
|
|
await conn.execute("CREATE INDEX IF NOT EXISTS idx_household_slug ON Household(slug);")
|
|
await conn.execute(
|
|
"CREATE INDEX IF NOT EXISTS idx_household_member_household ON HouseholdMember(household_id);"
|
|
)
|
|
|
|
|
|
async def member_ids_in_household(conn, household_id: int, user_ids: list[int]) -> set[int]:
|
|
"""Return the subset of user_ids that are members of the given household.
|
|
|
|
Uses HouseholdMember join User to ensure users exist.
|
|
"""
|
|
if not user_ids:
|
|
return set()
|
|
placeholders = ",".join(["?"] * len(user_ids))
|
|
query = f"""
|
|
SELECT u.id
|
|
FROM HouseholdMember hm
|
|
JOIN User u ON u.id = hm.user_id
|
|
WHERE hm.household_id = ? AND u.id IN ({placeholders})
|
|
"""
|
|
valid: set[int] = set()
|
|
async with conn.execute(query, (household_id, *sorted(user_ids))) as c:
|
|
async for row in c:
|
|
valid.add(int(row[0]))
|
|
return valid
|
|
|
|
|
|
async def are_members(conn, household_id: int, user_ids: list[int]) -> bool:
|
|
"""True only if all provided user_ids are members of the household."""
|
|
if not user_ids:
|
|
return True
|
|
found = await member_ids_in_household(conn, household_id, user_ids)
|
|
return found == set(user_ids)
|