Changeset ef1c1c7 for server/db


Ignore:
Timestamp:
09/24/26 17:43:19 (5 days ago)
Author:
Stefan <trsunovstefan@…>
Branches:
main
Children:
0cee8ec
Parents:
a531b45
Message:

Wiki docs, phase 6 and phase 7 added

Location:
server/db
Files:
3 added
4 edited

Legend:

Unmodified
Added
Removed
  • server/db/data_load.sql

    ra531b45 ref1c1c7  
    88--
    99-- All sample users have the password: test123
     10--
     11-- One transaction: the P7 checks in advanced_db.sql compare balances with
     12-- the ledger at COMMIT, and the users are inserted with their balances
     13-- before the deposit rows that back them. In an auto-commit client
     14-- (DBeaver) every statement would otherwise be checked on its own.
     15
     16BEGIN;
    1017
    1118SET search_path TO project, public;
    … …  
    104111-- Shows a fully-filled market buy and its resulting holding & ledger entry.
    105112-- ============================================================================
    106 INSERT INTO project.orders (id, user_id, market_id, side, type, status, quantity, price, placed_at, executed_at) VALUES
     113-- Imported as already completely filled (filled_quantity = quantity).
     114INSERT INTO project.orders (id, user_id, market_id, side, type, status, quantity, filled_quantity, price, placed_at, executed_at) VALUES
    107115    ('c1111111-1111-1111-1111-111111111111',
    108116     'b1111111-1111-1111-1111-111111111111',
    109117     'a2222222-2222-2222-2222-222222222222',
    110      'buy', 'market', 'executed', 0.5000, 3500.000000,
     118     'buy', 'market', 'executed', 0.5000, 0.5000, 3500.000000,
    111119     now() - interval '1 hour', now() - interval '1 hour');
    112120
    … …  
    118126INSERT INTO project.transactions (user_id, type, amount, currency, related_order, description) VALUES
    119127    ('b1111111-1111-1111-1111-111111111111', 'deposit',  10000.0000, 'USD', NULL,
     128        'Initial virtual deposit'),
     129    ('b2222222-2222-2222-2222-222222222222', 'deposit',   5000.0000, 'USD', NULL,
     130        'Initial virtual deposit'),
     131    ('b3333333-3333-3333-3333-333333333333', 'deposit',   2500.0000, 'USD', NULL,
    120132        'Initial virtual deposit'),
    121133    ('b1111111-1111-1111-1111-111111111111', 'buy',      -1750.0000, 'USD',
    … …  
    143155    ('d2222222-2222-2222-2222-222222222222', '11111111-1111-1111-1111-111111111111'),
    144156    ('d2222222-2222-2222-2222-222222222222', '55555555-5555-5555-5555-555555555555');
     157
     158COMMIT;
  • server/db/db.go

    ra531b45 ref1c1c7  
    1111        "strings"
    1212
    13         _ "github.com/lib/pq"
     13        "github.com/lib/pq"
    1414)
    1515
    … …  
    1919// which directory the program is started from.
    2020//
    21 //go:embed schema_creation.sql data_load.sql
     21//go:embed schema_creation.sql advanced_db.sql data_load.sql
    2222var sqlScripts embed.FS
    2323
    … …  
    3636        )
    3737
    38         var err error
    39         DB, err = sql.Open("postgres", dsn)
    40         if err != nil {
    41                 return fmt.Errorf("sql.Open: %w", err)
     38        // Optional SSH tunnel, the same thing DBeaver's "SSH" tab does. When
     39        // SSH_HOST is set, DBHOST/DBPORT are resolved from the SSH server's side
     40        // (for the faculty server that is usually localhost:5432).
     41        if sshHost := os.Getenv("SSH_HOST"); sshHost != "" {
     42                dialer, err := newSSHDialer(sshHost)
     43                if err != nil {
     44                        return err
     45                }
     46                connector, err := pq.NewConnector(dsn)
     47                if err != nil {
     48                        return fmt.Errorf("pq.NewConnector: %w", err)
     49                }
     50                connector.Dialer(dialer)
     51                DB = sql.OpenDB(connector)
     52        } else {
     53                var err error
     54                DB, err = sql.Open("postgres", dsn)
     55                if err != nil {
     56                        return fmt.Errorf("sql.Open: %w", err)
     57                }
    4258        }
    4359        if err := DB.Ping(); err != nil {
    … …  
    7288}
    7389
    74 // InitSchema runs schema_creation.sql then data_load.sql.
     90// InitSchema runs schema_creation.sql, advanced_db.sql (P7) and data_load.sql.
    7591// Destructive: drops the `project` schema. Intended for the -init flag.
    7692func InitSchema() error {
    77         log.Println("Running schema_creation.sql ...")
    78         if err := runScript("schema_creation.sql"); err != nil {
    79                 return err
     93        for _, name := range []string{"schema_creation.sql", "advanced_db.sql"} {
     94                log.Printf("Running %s ...", name)
     95                if err := runScript(name); err != nil {
     96                        return err
     97                }
    8098        }
    8199        if err := LoadData(); err != nil {
  • server/db/reports_demo_data.sql

    ra531b45 ref1c1c7  
    2828-- description/source) before re-inserting.
    2929
     30-- P7: users' cash (available + reserved) must equal their ledger at
     31-- COMMIT, so the balance moves by exactly what this script removes and
     32-- re-adds to the ledger, all in one transaction. The historical orders are
     33-- imported as completely filled.
     34
     35BEGIN;
     36
    3037SET search_path TO project, public;
     38
     39UPDATE users u
     40   SET available_balance = u.available_balance - d.total
     41  FROM (SELECT user_id, SUM(amount) AS total FROM transactions
     42         WHERE description = 'P6 demo data' GROUP BY user_id) d
     43 WHERE u.id = d.user_id;
    3144
    3245DELETE FROM transactions  WHERE description = 'P6 demo data';
    … …  
    98111-- Executed orders: who participated in which market, across the same quarters.
    99112-- ============================================================================
    100 INSERT INTO orders (id, user_id, market_id, side, type, status, quantity, price, placed_at, executed_at) VALUES
     113INSERT INTO orders (id, user_id, market_id, side, type, status, quantity, filled_quantity, price, placed_at, executed_at) VALUES
    101114    ('e1111111-1111-1111-1111-111111111111', 'b1111111-1111-1111-1111-111111111111',
    102      'a1111111-1111-1111-1111-111111111111', 'buy', 'market', 'executed', 0.5000, 40000.000000,
     115     'a1111111-1111-1111-1111-111111111111', 'buy', 'market', 'executed', 0.5000, 0.5000, 40000.000000,
    103116     '2025-07-15 10:00', '2025-07-15 10:00'),
    104117    ('e2222222-2222-2222-2222-222222222222', 'b1111111-1111-1111-1111-111111111111',
    105      'a2222222-2222-2222-2222-222222222222', 'sell', 'market', 'executed', 3.0000, 4000.000000,
     118     'a2222222-2222-2222-2222-222222222222', 'sell', 'market', 'executed', 3.0000, 3.0000, 4000.000000,
    106119     '2025-10-15 10:00', '2025-10-15 10:00'),
    107120    ('e3333333-3333-3333-3333-333333333333', 'b2222222-2222-2222-2222-222222222222',
    108      'a1111111-1111-1111-1111-111111111111', 'buy', 'market', 'executed', 1.2000, 55000.000000,
     121     'a1111111-1111-1111-1111-111111111111', 'buy', 'market', 'executed', 1.2000, 1.2000, 55000.000000,
    109122     '2026-01-15 10:00', '2026-01-15 10:00'),
    110123    ('e4444444-4444-4444-4444-444444444444', 'b2222222-2222-2222-2222-222222222222',
    111      'a1111111-1111-1111-1111-111111111111', 'buy', 'market', 'executed', 1.0000, 60000.000000,
     124     'a1111111-1111-1111-1111-111111111111', 'buy', 'market', 'executed', 1.0000, 1.0000, 60000.000000,
    112125     '2026-04-15 10:00', '2026-04-15 10:00'),
    113126    ('e5555555-5555-5555-5555-555555555555', 'b3333333-3333-3333-3333-333333333333',
    114      'a2222222-2222-2222-2222-222222222222', 'sell', 'market', 'executed', 2.0000, 3600.000000,
     127     'a2222222-2222-2222-2222-222222222222', 'sell', 'market', 'executed', 2.0000, 2.0000, 3600.000000,
    115128     '2026-01-15 10:00', '2026-01-15 10:00');
     129
     130UPDATE users u
     131   SET available_balance = u.available_balance + d.total
     132  FROM (SELECT user_id, SUM(amount) AS total FROM transactions
     133         WHERE description = 'P6 demo data' GROUP BY user_id) d
     134 WHERE u.id = d.user_id;
     135
     136COMMIT;
  • server/db/schema_creation.sql

    ra531b45 ref1c1c7  
    2626    available_balance numeric(18,4)   NOT NULL DEFAULT 0 CHECK (available_balance >= 0),
    2727    invested_balance  numeric(18,4)   NOT NULL DEFAULT 0 CHECK (invested_balance  >= 0),
     28    -- P7: cash committed to the user's active buy orders, moved out of
     29    -- available_balance when the order is placed and consumed as it fills.
     30    reserved_balance  numeric(18,4)   NOT NULL DEFAULT 0 CHECK (reserved_balance  >= 0),
    2831    created_at        timestamptz     NOT NULL DEFAULT now(),
    2932    updated_at        timestamptz
    … …  
    8689    side        varchar(4)     NOT NULL CHECK (side   IN ('buy', 'sell')),
    8790    type        varchar(20)    NOT NULL CHECK (type   IN ('market', 'limit')),
    88     status      varchar(20)    NOT NULL CHECK (status IN ('open', 'executed', 'cancelled')),
     91    status      varchar(20)    NOT NULL CHECK (status IN ('open', 'partially_filled', 'executed', 'cancelled')),
    8992    quantity    numeric(20,4)  NOT NULL CHECK (quantity > 0),
     93    -- P7: how much of the order has been traded so far; remaining is
     94    -- quantity - filled_quantity. Maintained from market_trades.
     95    filled_quantity numeric(20,4) NOT NULL DEFAULT 0
     96                               CHECK (filled_quantity >= 0 AND filled_quantity <= quantity),
    9097    price       numeric(18,6),
    9198    placed_at   timestamptz    NOT NULL DEFAULT now(),
    … …  
    125132    quantity    numeric(20,6)  NOT NULL CHECK (quantity > 0),
    126133    side        varchar(4)     CHECK (side IN ('buy', 'sell')),
    127     source      varchar(50)    NOT NULL DEFAULT 'simulation'
     134    source      varchar(50)    NOT NULL DEFAULT 'simulation',
     135    -- P7: the orders this trade filled. NULL on a side means the counterparty
     136    -- was the simulated market (bot ticks have both NULL).
     137    buy_order_id  uuid         REFERENCES project.orders(id),
     138    sell_order_id uuid         REFERENCES project.orders(id)
    128139);
    129140
    130141CREATE INDEX idx_market_trades_market_time ON project.market_trades(market_id, executed_at DESC);
     142CREATE INDEX idx_market_trades_buy_order  ON project.market_trades(buy_order_id)  WHERE buy_order_id  IS NOT NULL;
     143CREATE INDEX idx_market_trades_sell_order ON project.market_trades(sell_order_id) WHERE sell_order_id IS NOT NULL;
    131144
    132145-- ============================================================================
Note: See TracChangeset for help on using the changeset viewer.