Define uuid_generate_v7() in the first migration and switch all table primary key defaults to it. Remove the uuid-ossp extension dependency. Update refresh token and request ID generation in Go code to use uuid.NewV7() from the existing google/uuid v1.6.0 library. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
81 lines
2.6 KiB
PL/PgSQL
81 lines
2.6 KiB
PL/PgSQL
-- +goose Up
|
||
|
||
-- Generate UUID v7 (time-ordered, millisecond precision).
|
||
-- Structure: 48-bit unix_ts_ms | 4-bit version (0111) | 12-bit rand_a | 2-bit variant (10) | 62-bit rand_b
|
||
CREATE OR REPLACE FUNCTION uuid_generate_v7()
|
||
RETURNS uuid
|
||
AS $$
|
||
DECLARE
|
||
unix_ts_ms bytea;
|
||
uuid_bytes bytea;
|
||
BEGIN
|
||
-- 48-bit Unix timestamp in milliseconds.
|
||
-- int8send produces 8 big-endian bytes; skip the first 2 zero bytes to get 6.
|
||
unix_ts_ms = substring(int8send(floor(extract(epoch from clock_timestamp()) * 1000)::bigint) from 3);
|
||
|
||
-- Use a random v4 UUID as the source of random bits for rand_a and rand_b.
|
||
uuid_bytes = uuid_send(gen_random_uuid());
|
||
|
||
-- Overwrite bytes 0–5 with the timestamp (positions 1–6 in 1-indexed bytea).
|
||
uuid_bytes = overlay(uuid_bytes placing unix_ts_ms from 1 for 6);
|
||
|
||
-- Set version nibble (bits 48–51) to 0111 (7).
|
||
uuid_bytes = set_bit(uuid_bytes, 48, 0);
|
||
uuid_bytes = set_bit(uuid_bytes, 49, 1);
|
||
uuid_bytes = set_bit(uuid_bytes, 50, 1);
|
||
uuid_bytes = set_bit(uuid_bytes, 51, 1);
|
||
|
||
-- Variant bits (64–65) stay at 10 as inherited from gen_random_uuid().
|
||
|
||
RETURN encode(uuid_bytes, 'hex')::uuid;
|
||
END
|
||
$$ LANGUAGE plpgsql VOLATILE;
|
||
|
||
CREATE TYPE user_plan AS ENUM ('free', 'paid');
|
||
CREATE TYPE user_gender AS ENUM ('male', 'female');
|
||
CREATE TYPE user_goal AS ENUM ('lose', 'maintain', 'gain');
|
||
CREATE TYPE activity_level AS ENUM ('low', 'moderate', 'high');
|
||
|
||
CREATE TABLE users (
|
||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||
firebase_uid VARCHAR(128) NOT NULL UNIQUE,
|
||
email VARCHAR(255) NOT NULL,
|
||
name VARCHAR(255) NOT NULL DEFAULT '',
|
||
avatar_url TEXT,
|
||
|
||
-- Body parameters
|
||
height_cm SMALLINT,
|
||
weight_kg DECIMAL(5,2),
|
||
age SMALLINT,
|
||
gender user_gender,
|
||
activity activity_level,
|
||
|
||
-- Goal and calculated daily norm
|
||
goal user_goal,
|
||
daily_calories INTEGER,
|
||
|
||
-- Plan
|
||
plan user_plan NOT NULL DEFAULT 'free',
|
||
|
||
-- Preferences (JSONB for flexibility)
|
||
preferences JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||
|
||
-- Refresh token
|
||
refresh_token TEXT,
|
||
token_expires_at TIMESTAMPTZ,
|
||
|
||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||
);
|
||
|
||
CREATE INDEX idx_users_firebase_uid ON users (firebase_uid);
|
||
CREATE INDEX idx_users_email ON users (email);
|
||
|
||
-- +goose Down
|
||
DROP TABLE IF EXISTS users;
|
||
DROP TYPE IF EXISTS activity_level;
|
||
DROP TYPE IF EXISTS user_goal;
|
||
DROP TYPE IF EXISTS user_gender;
|
||
DROP TYPE IF EXISTS user_plan;
|
||
DROP FUNCTION IF EXISTS uuid_generate_v7();
|