-- Test Database Schema for Integration Testing -- Creates tables needed for database integration tests -- Test trades table for testing trade persistence CREATE TABLE IF NOT EXISTS test_trades ( id SERIAL PRIMARY KEY, trade_id VARCHAR(100) UNIQUE NOT NULL, symbol VARCHAR(20) NOT NULL, side VARCHAR(10) NOT NULL CHECK (side IN ('BUY', 'SELL')), quantity DECIMAL(20,8) NOT NULL CHECK (quantity > 0), price DECIMAL(20,8) NOT NULL CHECK (price > 0), commission DECIMAL(20,8) DEFAULT 0, timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(), execution_venue VARCHAR(50) DEFAULT 'TEST_EXCHANGE', order_id VARCHAR(100), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Test positions table for testing position management CREATE TABLE IF NOT EXISTS test_positions ( id SERIAL PRIMARY KEY, account_id VARCHAR(50) NOT NULL, symbol VARCHAR(20) NOT NULL, quantity DECIMAL(20,8) NOT NULL, average_price DECIMAL(20,8) NOT NULL, market_value DECIMAL(20,8) NOT NULL, unrealized_pnl DECIMAL(20,8) DEFAULT 0, realized_pnl DECIMAL(20,8) DEFAULT 0, last_updated TIMESTAMPTZ DEFAULT NOW(), created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(account_id, symbol) ); -- Test orders table for testing order lifecycle CREATE TABLE IF NOT EXISTS test_orders ( id SERIAL PRIMARY KEY, order_id VARCHAR(100) UNIQUE NOT NULL, client_order_id VARCHAR(100), account_id VARCHAR(50) NOT NULL, symbol VARCHAR(20) NOT NULL, side VARCHAR(10) NOT NULL CHECK (side IN ('BUY', 'SELL')), order_type VARCHAR(20) NOT NULL CHECK (order_type IN ('MARKET', 'LIMIT', 'STOP', 'STOP_LIMIT')), quantity DECIMAL(20,8) NOT NULL CHECK (quantity > 0), price DECIMAL(20,8), stop_price DECIMAL(20,8), filled_quantity DECIMAL(20,8) DEFAULT 0, remaining_quantity DECIMAL(20,8), status VARCHAR(20) NOT NULL DEFAULT 'PENDING' CHECK (status IN ('PENDING', 'ACTIVE', 'FILLED', 'CANCELLED', 'REJECTED')), time_in_force VARCHAR(10) DEFAULT 'DAY' CHECK (time_in_force IN ('DAY', 'GTC', 'IOC', 'FOK')), created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), expires_at TIMESTAMPTZ ); -- Test executions table for testing execution tracking CREATE TABLE IF NOT EXISTS test_executions ( id SERIAL PRIMARY KEY, execution_id VARCHAR(100) UNIQUE NOT NULL, order_id VARCHAR(100) NOT NULL, trade_id VARCHAR(100), symbol VARCHAR(20) NOT NULL, side VARCHAR(10) NOT NULL CHECK (side IN ('BUY', 'SELL')), quantity DECIMAL(20,8) NOT NULL CHECK (quantity > 0), price DECIMAL(20,8) NOT NULL CHECK (price > 0), commission DECIMAL(20,8) DEFAULT 0, execution_venue VARCHAR(50) DEFAULT 'TEST_EXCHANGE', executed_at TIMESTAMPTZ DEFAULT NOW(), created_at TIMESTAMPTZ DEFAULT NOW() ); -- Performance-optimized indexes for testing CREATE INDEX IF NOT EXISTS idx_test_trades_symbol_timestamp ON test_trades(symbol, timestamp DESC); CREATE INDEX IF NOT EXISTS idx_test_trades_trade_id_hash ON test_trades USING HASH(trade_id); CREATE INDEX IF NOT EXISTS idx_test_trades_timestamp ON test_trades(timestamp DESC); CREATE INDEX IF NOT EXISTS idx_test_positions_account_symbol ON test_positions(account_id, symbol); CREATE INDEX IF NOT EXISTS idx_test_positions_symbol ON test_positions(symbol); CREATE INDEX IF NOT EXISTS idx_test_positions_updated ON test_positions(last_updated DESC); CREATE INDEX IF NOT EXISTS idx_test_orders_status ON test_orders(status) WHERE status IN ('PENDING', 'ACTIVE'); CREATE INDEX IF NOT EXISTS idx_test_orders_symbol_status ON test_orders(symbol, status); CREATE INDEX IF NOT EXISTS idx_test_orders_account ON test_orders(account_id); CREATE INDEX IF NOT EXISTS idx_test_orders_created ON test_orders(created_at DESC); CREATE INDEX IF NOT EXISTS idx_test_executions_order_id ON test_executions(order_id); CREATE INDEX IF NOT EXISTS idx_test_executions_symbol_executed ON test_executions(symbol, executed_at DESC); CREATE INDEX IF NOT EXISTS idx_test_executions_executed_at ON test_executions(executed_at DESC); -- Triggers for maintaining updated_at timestamps CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ language 'plpgsql'; CREATE TRIGGER update_test_trades_updated_at BEFORE UPDATE ON test_trades FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_test_positions_updated_at BEFORE UPDATE ON test_positions FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER update_test_orders_updated_at BEFORE UPDATE ON test_orders FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- Function to calculate remaining quantity for orders CREATE OR REPLACE FUNCTION update_order_remaining_quantity() RETURNS TRIGGER AS $$ BEGIN NEW.remaining_quantity = NEW.quantity - NEW.filled_quantity; RETURN NEW; END; $$ language 'plpgsql'; CREATE TRIGGER update_test_orders_remaining BEFORE INSERT OR UPDATE ON test_orders FOR EACH ROW EXECUTE FUNCTION update_order_remaining_quantity(); -- Comments for documentation COMMENT ON TABLE test_trades IS 'Test table for validating trade persistence and querying performance'; COMMENT ON TABLE test_positions IS 'Test table for validating position management and portfolio tracking'; COMMENT ON TABLE test_orders IS 'Test table for validating order lifecycle management'; COMMENT ON TABLE test_executions IS 'Test table for validating execution tracking and reporting'; COMMENT ON COLUMN test_trades.trade_id IS 'Unique identifier for the trade execution'; COMMENT ON COLUMN test_trades.symbol IS 'Trading symbol (e.g., AAPL, GOOGL)'; COMMENT ON COLUMN test_trades.side IS 'Buy or sell side of the trade'; COMMENT ON COLUMN test_trades.quantity IS 'Number of shares/units traded'; COMMENT ON COLUMN test_trades.price IS 'Execution price per share/unit'; COMMENT ON COLUMN test_positions.account_id IS 'Account identifier owning the position'; COMMENT ON COLUMN test_positions.symbol IS 'Trading symbol for the position'; COMMENT ON COLUMN test_positions.quantity IS 'Current position size (positive=long, negative=short)'; COMMENT ON COLUMN test_positions.average_price IS 'Average cost basis for the position'; COMMENT ON COLUMN test_positions.market_value IS 'Current market value of the position'; COMMENT ON COLUMN test_positions.unrealized_pnl IS 'Unrealized profit/loss on the position';