action-policy-repo.js
2.44 KB
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import { billingActionPolicyTable } from '../db/index.js'
const POLICY = billingActionPolicyTable.tableName
export function createActionPolicyRepo(db, runner = db) {
async function findActionPolicy(action) {
const row = await runner(POLICY).where({ action }).first()
if (row === undefined) return null
return actionPolicyFromRow(row)
}
async function listActionPolicies() {
const rows = await runner(POLICY).orderBy('action')
return rows.map(actionPolicyFromRow)
}
async function updateActionPolicy(policy) {
await runner(POLICY).where({ action: policy.action }).update({
points: policy.points,
period_kind: policy.period_kind,
timezone: policy.timezone,
enabled: policy.enabled,
updated_by: policy.updated_by,
updated_at: new Date(),
})
return findActionPolicy(policy.action)
}
return { findActionPolicy, listActionPolicies, updateActionPolicy }
}
function actionPolicyFromRow(row) {
const action = requiredString(row.action, 'billing_action_policy.action')
const policy = {
action,
points: requiredInteger(row.points, 'billing_action_policy.points', action),
period_kind: requiredString(row.period_kind, 'billing_action_policy.period_kind', action),
timezone: nullableString(row.timezone, 'billing_action_policy.timezone', action),
enabled: Boolean(row.enabled),
updated_by: nullableString(row.updated_by, 'billing_action_policy.updated_by', action),
}
assertActionPolicy(policy)
return policy
}
function assertActionPolicy(policy) {
switch (policy.period_kind) {
case 'daily':
if (policy.timezone === null) throw new Error(`Daily billing action requires timezone, id=${policy.action}`)
return
case 'none':
if (policy.timezone !== null) throw new Error(`Non-periodic billing action cannot have timezone, id=${policy.action}`)
return
default:
throw new Error(`Unhandled billing action period: ${policy.period_kind}, id: ${policy.action}`)
}
}
function requiredString(value, field, id = 'unknown') {
if (typeof value !== 'string' || value === '') throw new Error(`Invalid ${field}, id=${id}`)
return value
}
function nullableString(value, field, id) {
if (value === null) return null
return requiredString(value, field, id)
}
function requiredInteger(value, field, id) {
const number = Number(value)
if (!Number.isSafeInteger(number) || number <= 0) throw new Error(`Invalid ${field}, id=${id}`)
return number
}