1# frozen_string_literal: true
2
3class InvitesRepo
4 class Invalid < StandardError; end
5
6 def initialize(db=DB)
7 @db = db
8 end
9
10 def unused_invites(customer_id)
11 promise = @db.query_defer(<<~SQL, [customer_id])
12 SELECT code FROM unused_invites WHERE creator_id=$1
13 SQL
14 promise.then { |result| result.map { |row| row["code"] } }
15 end
16
17 def claim_code(customer_id, code, &blk)
18 EMPromise.resolve(nil).then do
19 @db.transaction do
20 valid = @db.exec(<<~SQL, [customer_id, code]).cmd_tuples.positive?
21 UPDATE invites SET used_by_id=$1, used_at=LOCALTIMESTAMP
22 WHERE code=$2 AND used_by_id IS NULL
23 SQL
24 raise Invalid, "Not a valid invite code: #{code}" unless valid
25
26 blk.call
27 end
28 end
29 end
30
31 CREATE_N_SQL = <<~SQL
32 INSERT INTO invites
33 SELECT unnest(array_fill($1::text, array[$2::int]))
34 RETURNING code
35 SQL
36
37 def create_n_codes(customer_id, num)
38 EMPromise.resolve(nil).then {
39 codes = @db.exec(CREATE_N_SQL, [customer_id, num])
40 raise Invalid, "Failed to fetch codes" unless codes.cmd_tuples.positive?
41
42 codes.map { |row| row["code"] }
43 }
44 end
45
46 def any_existing?(codes)
47 promise = @db.query_one(<<~SQL, [codes])
48 SELECT count(1) FROM invites WHERE code = ANY($1)
49 SQL
50 promise.then { |result| result[:count].positive? }
51 end
52
53 def any_claimed?(codes)
54 promise = @db.query_one(<<~SQL, [codes])
55 SELECT count(1) FROM invites WHERE code = ANY($1) AND used_by_id IS NOT NULL
56 SQL
57 promise.then { |result| result[:count].positive? }
58 end
59
60 def create_codes(customer_id, codes)
61 custs = [customer_id] * codes.length
62 EMPromise.resolve(nil).then {
63 @db.transaction do
64 valid = @db.exec(<<~SQL, [custs, codes]).cmd_tuples.positive?
65 INSERT INTO invites(creator_id, code) SELECT unnest($1), unnest($2)
66 SQL
67 raise Invalid, "Failed to insert one of: #{codes}" unless valid
68 end
69 }
70 end
71
72 def delete_codes(codes)
73 EMPromise.resolve(nil).then {
74 @db.exec(<<~SQL, [codes])
75 DELETE FROM invites WHERE code = ANY($1)
76 SQL
77 }
78 end
79end