first commit

Made-with: Cursor
This commit is contained in:
Michilis
2026-02-28 02:17:55 +00:00
commit 41f6ae916f
92 changed files with 12332 additions and 0 deletions

23
sqlc/queries/api_keys.sql Normal file
View File

@@ -0,0 +1,23 @@
-- name: CreateAPIKey :one
INSERT INTO api_keys (id, user_id, name, key_hash, scopes)
VALUES ($1, $2, $3, $4, $5)
RETURNING id, user_id, name, key_hash, scopes, created_at, revoked_at;
-- name: ListAPIKeysByUser :many
SELECT id, name, scopes, created_at, revoked_at
FROM api_keys
WHERE user_id = $1
ORDER BY created_at DESC;
-- name: GetAPIKeyByHash :one
SELECT id, user_id, name, key_hash, scopes, created_at, revoked_at
FROM api_keys
WHERE key_hash = $1 AND revoked_at IS NULL;
-- name: RevokeAPIKey :exec
UPDATE api_keys SET revoked_at = now()
WHERE id = $1 AND user_id = $2 AND revoked_at IS NULL;
-- name: RevokeAllUserAPIKeys :exec
UPDATE api_keys SET revoked_at = now()
WHERE user_id = $1 AND revoked_at IS NULL;

View File

@@ -0,0 +1,13 @@
-- name: ListAttachmentsByEvent :many
SELECT id, event_id, file_url
FROM event_attachments
WHERE event_id = $1
ORDER BY id ASC;
-- name: CreateAttachment :one
INSERT INTO event_attachments (id, event_id, file_url)
VALUES ($1, $2, $3)
RETURNING id, event_id, file_url;
-- name: DeleteAttachment :exec
DELETE FROM event_attachments WHERE id = $1 AND event_id = $2;

View File

@@ -0,0 +1,25 @@
-- name: CreateAttendee :one
INSERT INTO event_attendees (id, event_id, user_id, email, status)
VALUES ($1, $2, $3, $4, 'pending')
RETURNING id, event_id, user_id, email, status;
-- name: ListAttendeesByEvent :many
SELECT id, event_id, user_id, email, status
FROM event_attendees
WHERE event_id = $1
ORDER BY id ASC;
-- name: UpdateAttendeeStatus :one
UPDATE event_attendees
SET status = $2
WHERE id = $1
RETURNING id, event_id, user_id, email, status;
-- name: DeleteAttendee :exec
DELETE FROM event_attendees
WHERE id = $1 AND event_id = $2;
-- name: GetAttendeeByID :one
SELECT id, event_id, user_id, email, status
FROM event_attendees
WHERE id = $1;

View File

@@ -0,0 +1,3 @@
-- name: CreateAuditLog :exec
INSERT INTO audit_logs (entity_type, entity_id, action, user_id)
VALUES ($1, $2, $3, $4);

View File

@@ -0,0 +1,23 @@
-- name: CreateBookingLink :one
INSERT INTO booking_links (id, calendar_id, token, duration_minutes, buffer_minutes, timezone, working_hours, active)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING *;
-- name: GetBookingLinkByToken :one
SELECT * FROM booking_links
WHERE token = $1;
-- name: GetBookingLinkByCalendar :one
SELECT * FROM booking_links
WHERE calendar_id = $1;
-- name: UpdateBookingLink :one
UPDATE booking_links
SET duration_minutes = COALESCE($2, duration_minutes),
buffer_minutes = COALESCE($3, buffer_minutes),
timezone = COALESCE($4, timezone),
working_hours = COALESCE($5, working_hours),
active = COALESCE($6, active),
updated_at = now()
WHERE id = $1
RETURNING *;

View File

@@ -0,0 +1,23 @@
-- name: UpsertCalendarMember :exec
INSERT INTO calendar_members (calendar_id, user_id, role)
VALUES ($1, $2, $3)
ON CONFLICT (calendar_id, user_id) DO UPDATE SET role = $3;
-- name: GetCalendarMemberRole :one
SELECT role FROM calendar_members
WHERE calendar_id = $1 AND user_id = $2;
-- name: ListCalendarMembers :many
SELECT cm.user_id, u.email, cm.role
FROM calendar_members cm
JOIN users u ON u.id = cm.user_id
WHERE cm.calendar_id = $1 AND u.deleted_at IS NULL
ORDER BY cm.role ASC;
-- name: DeleteCalendarMember :exec
DELETE FROM calendar_members
WHERE calendar_id = $1 AND user_id = $2;
-- name: DeleteAllCalendarMembers :exec
DELETE FROM calendar_members
WHERE calendar_id = $1;

View File

@@ -0,0 +1,33 @@
-- name: CreateCalendar :one
INSERT INTO calendars (id, owner_id, name, color, is_public)
VALUES ($1, $2, $3, $4, $5)
RETURNING id, owner_id, name, color, is_public, public_token, created_at, updated_at;
-- name: GetCalendarByID :one
SELECT id, owner_id, name, color, is_public, public_token, created_at, updated_at
FROM calendars
WHERE id = $1 AND deleted_at IS NULL;
-- name: ListCalendarsByUser :many
SELECT c.id, c.owner_id, c.name, c.color, c.is_public, c.created_at, c.updated_at, cm.role
FROM calendars c
JOIN calendar_members cm ON cm.calendar_id = c.id
WHERE cm.user_id = $1 AND c.deleted_at IS NULL
ORDER BY c.created_at ASC;
-- name: UpdateCalendar :one
UPDATE calendars
SET name = COALESCE(sqlc.narg('name')::TEXT, name),
color = COALESCE(sqlc.narg('color')::TEXT, color),
is_public = COALESCE(sqlc.narg('is_public')::BOOLEAN, is_public),
updated_at = now()
WHERE id = @id AND deleted_at IS NULL
RETURNING id, owner_id, name, color, is_public, public_token, created_at, updated_at;
-- name: SoftDeleteCalendar :exec
UPDATE calendars SET deleted_at = now(), updated_at = now()
WHERE id = $1 AND deleted_at IS NULL;
-- name: SoftDeleteCalendarsByOwner :exec
UPDATE calendars SET deleted_at = now(), updated_at = now()
WHERE owner_id = $1 AND deleted_at IS NULL;

46
sqlc/queries/contacts.sql Normal file
View File

@@ -0,0 +1,46 @@
-- name: CreateContact :one
INSERT INTO contacts (id, owner_id, first_name, last_name, email, phone, company, notes)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING *;
-- name: GetContactByID :one
SELECT * FROM contacts
WHERE id = $1 AND owner_id = $2 AND deleted_at IS NULL;
-- name: ListContacts :many
SELECT * FROM contacts
WHERE owner_id = @owner_id
AND deleted_at IS NULL
AND (
sqlc.narg('search')::TEXT IS NULL
OR first_name ILIKE '%' || sqlc.narg('search')::TEXT || '%'
OR last_name ILIKE '%' || sqlc.narg('search')::TEXT || '%'
OR email ILIKE '%' || sqlc.narg('search')::TEXT || '%'
OR company ILIKE '%' || sqlc.narg('search')::TEXT || '%'
)
AND (
sqlc.narg('cursor_time')::TIMESTAMPTZ IS NULL
OR (created_at, id) > (sqlc.narg('cursor_time')::TIMESTAMPTZ, sqlc.narg('cursor_id')::UUID)
)
ORDER BY created_at ASC, id ASC
LIMIT @lim;
-- name: UpdateContact :one
UPDATE contacts
SET first_name = COALESCE(sqlc.narg('first_name'), first_name),
last_name = COALESCE(sqlc.narg('last_name'), last_name),
email = COALESCE(sqlc.narg('email'), email),
phone = COALESCE(sqlc.narg('phone'), phone),
company = COALESCE(sqlc.narg('company'), company),
notes = COALESCE(sqlc.narg('notes'), notes),
updated_at = now()
WHERE id = @id AND owner_id = @owner_id AND deleted_at IS NULL
RETURNING *;
-- name: SoftDeleteContact :exec
UPDATE contacts SET deleted_at = now(), updated_at = now()
WHERE id = $1 AND owner_id = $2 AND deleted_at IS NULL;
-- name: SoftDeleteContactsByOwner :exec
UPDATE contacts SET deleted_at = now(), updated_at = now()
WHERE owner_id = $1 AND deleted_at IS NULL;

View File

@@ -0,0 +1,10 @@
-- name: ListExceptionsByEvent :many
SELECT id, event_id, exception_date, action
FROM event_exceptions
WHERE event_id = $1
ORDER BY exception_date ASC;
-- name: CreateEventException :one
INSERT INTO event_exceptions (id, event_id, exception_date, action)
VALUES ($1, $2, $3, $4)
RETURNING id, event_id, exception_date, action;

98
sqlc/queries/events.sql Normal file
View File

@@ -0,0 +1,98 @@
-- name: CreateEvent :one
INSERT INTO events (id, calendar_id, title, description, location, start_time, end_time, timezone, all_day, recurrence_rule, tags, created_by, updated_by)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
RETURNING *;
-- name: GetEventByID :one
SELECT * FROM events
WHERE id = $1 AND deleted_at IS NULL;
-- name: ListEventsInRange :many
SELECT e.* FROM events e
JOIN calendar_members cm ON cm.calendar_id = e.calendar_id
WHERE cm.user_id = @user_id
AND e.deleted_at IS NULL
AND e.start_time < @range_end
AND e.end_time > @range_start
AND (sqlc.narg('calendar_id')::UUID IS NULL OR e.calendar_id = sqlc.narg('calendar_id')::UUID)
AND (sqlc.narg('search')::TEXT IS NULL OR (e.title ILIKE '%' || sqlc.narg('search')::TEXT || '%' OR e.description ILIKE '%' || sqlc.narg('search')::TEXT || '%'))
AND (sqlc.narg('tag')::TEXT IS NULL OR sqlc.narg('tag')::TEXT = ANY(e.tags))
AND (
sqlc.narg('cursor_time')::TIMESTAMPTZ IS NULL
OR (e.start_time, e.id) > (sqlc.narg('cursor_time')::TIMESTAMPTZ, sqlc.narg('cursor_id')::UUID)
)
ORDER BY e.start_time ASC, e.id ASC
LIMIT @lim;
-- name: ListRecurringEventsInRange :many
SELECT e.* FROM events e
JOIN calendar_members cm ON cm.calendar_id = e.calendar_id
WHERE cm.user_id = @user_id
AND e.deleted_at IS NULL
AND e.recurrence_rule IS NOT NULL
AND e.start_time <= @range_end
AND (sqlc.narg('calendar_id')::UUID IS NULL OR e.calendar_id = sqlc.narg('calendar_id')::UUID)
ORDER BY e.start_time ASC;
-- name: UpdateEvent :one
UPDATE events
SET title = COALESCE(sqlc.narg('title'), title),
description = COALESCE(sqlc.narg('description'), description),
location = COALESCE(sqlc.narg('location'), location),
start_time = COALESCE(sqlc.narg('start_time'), start_time),
end_time = COALESCE(sqlc.narg('end_time'), end_time),
timezone = COALESCE(sqlc.narg('timezone'), timezone),
all_day = COALESCE(sqlc.narg('all_day'), all_day),
recurrence_rule = sqlc.narg('recurrence_rule'),
tags = COALESCE(sqlc.narg('tags'), tags),
updated_by = @updated_by,
updated_at = now()
WHERE id = @id AND deleted_at IS NULL
RETURNING *;
-- name: SoftDeleteEvent :exec
UPDATE events SET deleted_at = now(), updated_at = now()
WHERE id = $1 AND deleted_at IS NULL;
-- name: SoftDeleteEventsByCalendar :exec
UPDATE events SET deleted_at = now(), updated_at = now()
WHERE calendar_id = $1 AND deleted_at IS NULL;
-- name: SoftDeleteEventsByCreator :exec
UPDATE events SET deleted_at = now(), updated_at = now()
WHERE created_by = $1 AND deleted_at IS NULL;
-- name: CheckEventOverlap :one
SELECT EXISTS(
SELECT 1 FROM events
WHERE calendar_id = $1
AND deleted_at IS NULL
AND start_time < $3
AND end_time > $2
) AS overlap;
-- name: CheckEventOverlapForUpdate :one
SELECT EXISTS(
SELECT 1 FROM events
WHERE calendar_id = $1
AND deleted_at IS NULL
AND start_time < $3
AND end_time > $2
FOR UPDATE
) AS overlap;
-- name: ListEventsByCalendarInRange :many
SELECT * FROM events
WHERE calendar_id = $1
AND deleted_at IS NULL
AND start_time < $3
AND end_time > $2
ORDER BY start_time ASC;
-- name: ListRecurringEventsByCalendar :many
SELECT * FROM events
WHERE calendar_id = $1
AND deleted_at IS NULL
AND recurrence_rule IS NOT NULL
AND start_time <= $2
ORDER BY start_time ASC;

View File

@@ -0,0 +1,16 @@
-- name: CreateRefreshToken :one
INSERT INTO refresh_tokens (id, user_id, token_hash, expires_at)
VALUES ($1, $2, $3, $4)
RETURNING id, user_id, token_hash, expires_at, revoked_at, created_at;
-- name: GetRefreshTokenByHash :one
SELECT id, user_id, token_hash, expires_at, revoked_at, created_at
FROM refresh_tokens
WHERE token_hash = $1 AND revoked_at IS NULL;
-- name: RevokeRefreshToken :exec
UPDATE refresh_tokens SET revoked_at = now() WHERE token_hash = $1;
-- name: RevokeAllUserRefreshTokens :exec
UPDATE refresh_tokens SET revoked_at = now()
WHERE user_id = $1 AND revoked_at IS NULL;

View File

@@ -0,0 +1,18 @@
-- name: CreateReminder :one
INSERT INTO event_reminders (id, event_id, minutes_before)
VALUES ($1, $2, $3)
RETURNING id, event_id, minutes_before;
-- name: ListRemindersByEvent :many
SELECT id, event_id, minutes_before
FROM event_reminders
WHERE event_id = $1
ORDER BY minutes_before ASC;
-- name: DeleteReminder :exec
DELETE FROM event_reminders
WHERE id = $1 AND event_id = $2;
-- name: DeleteRemindersByEvent :exec
DELETE FROM event_reminders
WHERE event_id = $1;

25
sqlc/queries/users.sql Normal file
View File

@@ -0,0 +1,25 @@
-- name: CreateUser :one
INSERT INTO users (id, email, password_hash, timezone)
VALUES ($1, $2, $3, $4)
RETURNING id, email, password_hash, timezone, is_active, created_at, updated_at;
-- name: GetUserByID :one
SELECT id, email, password_hash, timezone, is_active, created_at, updated_at
FROM users
WHERE id = $1 AND deleted_at IS NULL;
-- name: GetUserByEmail :one
SELECT id, email, password_hash, timezone, is_active, created_at, updated_at
FROM users
WHERE email = $1 AND deleted_at IS NULL;
-- name: UpdateUser :one
UPDATE users
SET timezone = COALESCE(sqlc.narg('timezone')::TEXT, timezone),
updated_at = now()
WHERE id = @id AND deleted_at IS NULL
RETURNING id, email, password_hash, timezone, is_active, created_at, updated_at;
-- name: SoftDeleteUser :exec
UPDATE users SET deleted_at = now(), is_active = false, updated_at = now()
WHERE id = $1 AND deleted_at IS NULL;