srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/export_store.js
blob: d69ac29bf4829526792810051ce597307eda48e0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/bin/env node
// Writes the store catalogue to web/src/data/store.json.
//
// The store reads its catalogue from the server. With no server the page
// rendered its heading over an empty shop, which looks like a fault rather
// than a feature that needs signing in. This file is the same fallback the
// text packs already use: bundled with the client, served from the database
// and merged over the top once a server exists.
//
// Run it after changing prices or adding items:
//   node scripts/export_store.js
//
// It shells out to psql so it needs no node dependencies, matching the rest
// of the scripts here.
const { execFileSync } = require('node:child_process');
const { writeFileSync } = require('node:fs');
const { join } = require('node:path');

const URL = process.env.DATABASE_URL
    || 'postgresql://typerpunk:typerpunk@localhost/typerpunk';

function query(sql) {
    const out = execFileSync('psql', [URL, '-At', '-c', sql], { encoding: 'utf8' });
    return JSON.parse(out.trim() || '[]');
}

const cosmetics = query(`
    SELECT COALESCE(json_agg(row_to_json(c) ORDER BY c.category, c.price_cents), '[]'::json)
    FROM (SELECT id, name, category, price_cents, value FROM cosmetics) c`);

const bundles = query(`
    SELECT COALESCE(json_agg(b ORDER BY b.sort_order), '[]'::json) FROM (
        SELECT b.id, b.name, b.description, b.price_cents, b.sort_order,
               COALESCE(SUM(c.price_cents), 0)::int AS full_price_cents,
               COALESCE(ARRAY_AGG(c.id ORDER BY c.id)
                        FILTER (WHERE c.id IS NOT NULL), '{}') AS items
        FROM bundles b
        LEFT JOIN bundle_items bi ON bi.bundle_id = b.id
        LEFT JOIN cosmetics c ON c.id = bi.cosmetic_id
        GROUP BY b.id, b.name, b.description, b.price_cents, b.sort_order
    ) b`);

const merch = query(`
    SELECT COALESCE(json_agg(m ORDER BY m.sort_order), '[]'::json) FROM (
        SELECT id, name, description, price_cents, shipping_cents, kind, variants, sort_order
        FROM merch WHERE available
    ) m`);

for (const row of [...bundles, ...merch]) delete row.sort_order;

const out = join(__dirname, '..', 'web', 'src', 'data', 'store.json');
writeFileSync(out, JSON.stringify({ cosmetics, bundles, merch }, null, 2) + '\n');
console.log(`Wrote ${cosmetics.length} cosmetics, ${bundles.length} bundles and ${merch.length} merch items to ${out}`);