# frozen_string_literal: true
class InvitesRepo
class Invalid < StandardError; end
def initialize(db=DB)
@db = db
end
def unused_invites(customer_id)
promise = @db.query_defer(<<~SQL, [customer_id])
SELECT code FROM unused_invites WHERE creator_id=$1
SQL
promise.then { |result| result.map { |row| row["code"] } }
end
def claim_code(customer_id, code, &blk)
EMPromise.resolve(nil).then do
@db.transaction do
valid = @db.exec(<<~SQL, [customer_id, code]).cmd_tuples.positive?
UPDATE invites SET used_by_id=$1, used_at=LOCALTIMESTAMP
WHERE code=$2 AND used_by_id IS NULL
SQL
raise Invalid, "Not a valid invite code: #{code}" unless valid
blk.call
end
end
end
CREATE_N_SQL = <<~SQL
INSERT INTO invites
SELECT unnest(array_fill($1::text, array[$2::int]))
RETURNING code
SQL
def create_n_codes(customer_id, num)
EMPromise.resolve(nil).then {
codes = @db.exec(CREATE_N_SQL, [customer_id, num])
raise Invalid, "Failed to fetch codes" unless codes.cmd_tuples.positive?
codes.map { |row| row["code"] }
}
end
def any_existing?(codes)
promise = @db.query_one(<<~SQL, [codes])
SELECT count(1) FROM invites WHERE code = ANY($1)
SQL
promise.then { |result| result[:count].positive? }
end
def any_claimed?(codes)
promise = @db.query_one(<<~SQL, [codes])
SELECT count(1) FROM invites WHERE code = ANY($1) AND used_by_id IS NOT NULL
SQL
promise.then { |result| result[:count].positive? }
end
def create_codes(customer_id, codes)
custs = [customer_id] * codes.length
EMPromise.resolve(nil).then {
@db.transaction do
valid = @db.exec(<<~SQL, [custs, codes]).cmd_tuples.positive?
INSERT INTO invites(creator_id, code) SELECT unnest($1), unnest($2)
SQL
raise Invalid, "Failed to insert one of: #{codes}" unless valid
end
}
end
def delete_codes(codes)
EMPromise.resolve(nil).then {
@db.exec(<<~SQL, [codes])
DELETE FROM invites WHERE code = ANY($1)
SQL
}
end
end