@takaro/db 0.4.0 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"20250809122020-add-player-name-history.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/20250809122020-add-player-name-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,wBAAsB,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BlD;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAapD"}
1
+ {"version":3,"file":"20250809122020-add-player-name-history.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/20250809122020-add-player-name-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,wBAAsB,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAalD;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAapD"}
@@ -10,18 +10,6 @@ export async function up(knex) {
10
10
  table.index(['playerId', 'createdAt'], 'idx_player_name_history_player_created');
11
11
  table.index('name', 'idx_player_name_history_name');
12
12
  });
13
- // Populate initial data from existing player names
14
- const players = await knex('players').select('id', 'name', 'domain', 'createdAt').whereNotNull('name');
15
- if (players.length > 0) {
16
- const nameHistoryRecords = players.map((player) => ({
17
- playerId: player.id,
18
- name: player.name,
19
- domain: player.domain,
20
- createdAt: player.createdAt,
21
- updatedAt: player.createdAt,
22
- }));
23
- await knex('playerNameHistory').insert(nameHistoryRecords);
24
- }
25
13
  }
26
14
  export async function down(knex) {
27
15
  // Update players table with latest name from history before dropping
@@ -1 +1 @@
1
- {"version":3,"file":"20250809122020-add-player-name-history.js","sourceRoot":"","sources":["../../../src/migrations/sql/20250809122020-add-player-name-history.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC,IAAU;IACjC,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE;QAC3D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC;QACrE,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACnC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAClF,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAClF,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;QACxF,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAEnC,0BAA0B;QAC1B,KAAK,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,wCAAwC,CAAC,CAAC;QACjF,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,mDAAmD;IACnD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAEvG,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAClD,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS;SAC5B,CAAC,CAAC,CAAC;QAEJ,MAAM,IAAI,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAU;IACnC,qEAAqE;IACrE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC;SAChD,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC;SAC1B,UAAU,CAAC,UAAU,CAAC;SACtB,OAAO,CAAC,UAAU,CAAC;SACnB,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAEhC,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;QACjC,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;AACnD,CAAC"}
1
+ {"version":3,"file":"20250809122020-add-player-name-history.js","sourceRoot":"","sources":["../../../src/migrations/sql/20250809122020-add-player-name-history.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC,IAAU;IACjC,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,mBAAmB,EAAE,CAAC,KAAK,EAAE,EAAE;QAC3D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC;QACrE,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACnC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAClF,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QAClF,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;QACxF,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAEnC,0BAA0B;QAC1B,KAAK,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,wCAAwC,CAAC,CAAC;QACjF,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAU;IACnC,qEAAqE;IACrE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC;SAChD,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC;SAC1B,UAAU,CAAC,UAAU,CAAC;SACtB,OAAO,CAAC,UAAU,CAAC;SACnB,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAEhC,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;QACjC,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Knex } from 'knex';
2
+ export declare function up(knex: Knex): Promise<void>;
3
+ export declare function down(knex: Knex): Promise<void>;
4
+ //# sourceMappingURL=20251014120000-shop-order-auto-cancel-on-listing-delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20251014120000-shop-order-auto-cancel-on-listing-delete.d.ts","sourceRoot":"","sources":["../../../src/migrations/sql/20251014120000-shop-order-auto-cancel-on-listing-delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,wBAAsB,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DlD;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAYpD"}
@@ -0,0 +1,70 @@
1
+ export async function up(knex) {
2
+ // Step 1: Create trigger function that auto-cancels orders when listing is deleted
3
+ await knex.raw(`
4
+ CREATE OR REPLACE FUNCTION cancel_orders_on_listing_delete()
5
+ RETURNS TRIGGER AS $$
6
+ BEGIN
7
+ -- Only proceed if deletedAt changed from NULL to a value (soft-delete)
8
+ IF OLD."deletedAt" IS NULL AND NEW."deletedAt" IS NOT NULL THEN
9
+ -- Cancel all PAID orders for this listing and refund currency
10
+ -- Aggregate refunds by player to handle multiple orders correctly
11
+ WITH orders_to_cancel AS (
12
+ SELECT
13
+ so.id AS order_id,
14
+ so."playerId",
15
+ NEW."gameServerId",
16
+ NEW.domain AS domain,
17
+ NEW.price * so.amount AS refund_amount
18
+ FROM "shopOrder" so
19
+ WHERE so."listingId" = NEW.id
20
+ AND so.status = 'PAID'
21
+ ),
22
+ aggregated_refunds AS (
23
+ SELECT
24
+ "playerId",
25
+ "gameServerId",
26
+ domain,
27
+ SUM(refund_amount) AS total_refund
28
+ FROM orders_to_cancel
29
+ GROUP BY "playerId", "gameServerId", domain
30
+ )
31
+ -- Update playerOnGameServer currency with aggregated total
32
+ UPDATE "playerOnGameServer" pogs
33
+ SET currency = pogs.currency + ar.total_refund
34
+ FROM aggregated_refunds ar
35
+ WHERE pogs."playerId" = ar."playerId"
36
+ AND pogs."gameServerId" = ar."gameServerId"
37
+ AND pogs.domain = ar.domain;
38
+
39
+ -- Update order status to CANCELED
40
+ UPDATE "shopOrder"
41
+ SET status = 'CANCELED'
42
+ WHERE "listingId" = NEW.id
43
+ AND status = 'PAID';
44
+ END IF;
45
+
46
+ RETURN NEW;
47
+ END;
48
+ $$ LANGUAGE plpgsql;
49
+ `);
50
+ // Step 2: Create trigger on shopListing table
51
+ await knex.raw(`
52
+ CREATE TRIGGER auto_cancel_orders_on_listing_delete
53
+ AFTER UPDATE ON "shopListing"
54
+ FOR EACH ROW
55
+ WHEN (OLD."deletedAt" IS NULL AND NEW."deletedAt" IS NOT NULL)
56
+ EXECUTE FUNCTION cancel_orders_on_listing_delete();
57
+ `);
58
+ }
59
+ export async function down(knex) {
60
+ // Drop trigger
61
+ await knex.raw(`
62
+ DROP TRIGGER IF EXISTS auto_cancel_orders_on_listing_delete ON "shopListing";
63
+ `);
64
+ // Drop function
65
+ await knex.raw(`
66
+ DROP FUNCTION IF EXISTS cancel_orders_on_listing_delete();
67
+ `);
68
+ // Note: We don't reverse the data cleanup since those were genuinely bad orders
69
+ }
70
+ //# sourceMappingURL=20251014120000-shop-order-auto-cancel-on-listing-delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20251014120000-shop-order-auto-cancel-on-listing-delete.js","sourceRoot":"","sources":["../../../src/migrations/sql/20251014120000-shop-order-auto-cancel-on-listing-delete.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC,IAAU;IACjC,mFAAmF;IACnF,MAAM,IAAI,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8Cd,CAAC,CAAC;IAEH,8CAA8C;IAC9C,MAAM,IAAI,CAAC,GAAG,CAAC;;;;;;GAMd,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAU;IACnC,eAAe;IACf,MAAM,IAAI,CAAC,GAAG,CAAC;;GAEd,CAAC,CAAC;IAEH,gBAAgB;IAChB,MAAM,IAAI,CAAC,GAAG,CAAC;;GAEd,CAAC,CAAC;IAEH,gFAAgF;AAClF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takaro/db",
3
- "version": "0.4.0",
3
+ "version": "0.4.4",
4
4
  "description": "An opinionated data layer",
5
5
  "main": "dist/main.js",
6
6
  "types": "dist/main.d.ts",
@@ -13,21 +13,6 @@ export async function up(knex: Knex): Promise<void> {
13
13
  table.index(['playerId', 'createdAt'], 'idx_player_name_history_player_created');
14
14
  table.index('name', 'idx_player_name_history_name');
15
15
  });
16
-
17
- // Populate initial data from existing player names
18
- const players = await knex('players').select('id', 'name', 'domain', 'createdAt').whereNotNull('name');
19
-
20
- if (players.length > 0) {
21
- const nameHistoryRecords = players.map((player) => ({
22
- playerId: player.id,
23
- name: player.name,
24
- domain: player.domain,
25
- createdAt: player.createdAt,
26
- updatedAt: player.createdAt,
27
- }));
28
-
29
- await knex('playerNameHistory').insert(nameHistoryRecords);
30
- }
31
16
  }
32
17
 
33
18
  export async function down(knex: Knex): Promise<void> {
@@ -0,0 +1,75 @@
1
+ import { Knex } from 'knex';
2
+
3
+ export async function up(knex: Knex): Promise<void> {
4
+ // Step 1: Create trigger function that auto-cancels orders when listing is deleted
5
+ await knex.raw(`
6
+ CREATE OR REPLACE FUNCTION cancel_orders_on_listing_delete()
7
+ RETURNS TRIGGER AS $$
8
+ BEGIN
9
+ -- Only proceed if deletedAt changed from NULL to a value (soft-delete)
10
+ IF OLD."deletedAt" IS NULL AND NEW."deletedAt" IS NOT NULL THEN
11
+ -- Cancel all PAID orders for this listing and refund currency
12
+ -- Aggregate refunds by player to handle multiple orders correctly
13
+ WITH orders_to_cancel AS (
14
+ SELECT
15
+ so.id AS order_id,
16
+ so."playerId",
17
+ NEW."gameServerId",
18
+ NEW.domain AS domain,
19
+ NEW.price * so.amount AS refund_amount
20
+ FROM "shopOrder" so
21
+ WHERE so."listingId" = NEW.id
22
+ AND so.status = 'PAID'
23
+ ),
24
+ aggregated_refunds AS (
25
+ SELECT
26
+ "playerId",
27
+ "gameServerId",
28
+ domain,
29
+ SUM(refund_amount) AS total_refund
30
+ FROM orders_to_cancel
31
+ GROUP BY "playerId", "gameServerId", domain
32
+ )
33
+ -- Update playerOnGameServer currency with aggregated total
34
+ UPDATE "playerOnGameServer" pogs
35
+ SET currency = pogs.currency + ar.total_refund
36
+ FROM aggregated_refunds ar
37
+ WHERE pogs."playerId" = ar."playerId"
38
+ AND pogs."gameServerId" = ar."gameServerId"
39
+ AND pogs.domain = ar.domain;
40
+
41
+ -- Update order status to CANCELED
42
+ UPDATE "shopOrder"
43
+ SET status = 'CANCELED'
44
+ WHERE "listingId" = NEW.id
45
+ AND status = 'PAID';
46
+ END IF;
47
+
48
+ RETURN NEW;
49
+ END;
50
+ $$ LANGUAGE plpgsql;
51
+ `);
52
+
53
+ // Step 2: Create trigger on shopListing table
54
+ await knex.raw(`
55
+ CREATE TRIGGER auto_cancel_orders_on_listing_delete
56
+ AFTER UPDATE ON "shopListing"
57
+ FOR EACH ROW
58
+ WHEN (OLD."deletedAt" IS NULL AND NEW."deletedAt" IS NOT NULL)
59
+ EXECUTE FUNCTION cancel_orders_on_listing_delete();
60
+ `);
61
+ }
62
+
63
+ export async function down(knex: Knex): Promise<void> {
64
+ // Drop trigger
65
+ await knex.raw(`
66
+ DROP TRIGGER IF EXISTS auto_cancel_orders_on_listing_delete ON "shopListing";
67
+ `);
68
+
69
+ // Drop function
70
+ await knex.raw(`
71
+ DROP FUNCTION IF EXISTS cancel_orders_on_listing_delete();
72
+ `);
73
+
74
+ // Note: We don't reverse the data cleanup since those were genuinely bad orders
75
+ }