feat: moved lua scripts to new cache structure
This commit is contained in:
@@ -1,101 +1,139 @@
|
||||
-- ============================================================================
|
||||
-- READ BALANCES
|
||||
-- Functions to read current balance state from Redis
|
||||
-- READ SUBJECT BALANCES
|
||||
-- Functions to read shared SubjectBalance payloads from Redis hashes
|
||||
-- ============================================================================
|
||||
|
||||
-- ============================================================================
|
||||
-- HELPER: Read rollover data from Redis (fresh read)
|
||||
-- Returns: { balance, usage, entities } or nil if not found
|
||||
-- ============================================================================
|
||||
local function read_rollover_data(cache_key, rollover_path)
|
||||
local result = redis.call('JSON.GET', cache_key, rollover_path)
|
||||
if not result or result == cjson.null then
|
||||
local function build_shared_subject_balance_key(params)
|
||||
return '{'
|
||||
.. params.customer_id
|
||||
.. '}:'
|
||||
.. params.org_id
|
||||
.. ':'
|
||||
.. params.env
|
||||
.. ':full_subject:shared_balances:'
|
||||
.. params.feature_id
|
||||
end
|
||||
|
||||
local function decode_subject_balance(raw_value)
|
||||
if is_nil(raw_value) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local decoded = cjson.decode(result)
|
||||
-- JSONPath returns an array of matches, extract the first element
|
||||
if type(decoded) == 'table' and decoded[1] ~= nil then
|
||||
decoded = decoded[1]
|
||||
end
|
||||
|
||||
|
||||
local decoded = cjson.decode(raw_value)
|
||||
if type(decoded) ~= 'table' then
|
||||
return nil
|
||||
end
|
||||
|
||||
return {
|
||||
balance = safe_number(decoded.balance),
|
||||
usage = safe_number(decoded.usage),
|
||||
entities = safe_table(decoded.entities),
|
||||
}
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- HELPER: Read current balance from Redis (fresh read, not from snapshot)
|
||||
-- ============================================================================
|
||||
local function read_current_balance(cache_key, base_path)
|
||||
local result = redis.call('JSON.GET', cache_key, base_path .. '.balance')
|
||||
if not result or result == cjson.null then
|
||||
return 0
|
||||
end
|
||||
-- JSON.GET returns a JSON string, need to decode
|
||||
local decoded = cjson.decode(result)
|
||||
-- JSONPath returns an array of matches, extract the first element
|
||||
if type(decoded) == 'table' and decoded[1] ~= nil then
|
||||
decoded = decoded[1]
|
||||
end
|
||||
return safe_number(decoded)
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- HELPER: Read current entity balance from Redis (fresh read)
|
||||
-- ============================================================================
|
||||
local function read_current_entity_balance(cache_key, base_path, entity_id)
|
||||
-- Use bracket notation for entity access (handles special characters in entity_id)
|
||||
local entity_path = build_entity_path(base_path, entity_id)
|
||||
local result = redis.call('JSON.GET', cache_key, entity_path)
|
||||
|
||||
if not result or result == cjson.null then
|
||||
return nil -- Entity doesn't exist
|
||||
end
|
||||
|
||||
local decoded = cjson.decode(result)
|
||||
|
||||
-- JSONPath returns an array of matches, extract the first element
|
||||
if type(decoded) == 'table' and decoded[1] ~= nil then
|
||||
decoded = decoded[1]
|
||||
end
|
||||
|
||||
if type(decoded) ~= 'table' then
|
||||
return nil
|
||||
end
|
||||
|
||||
return {
|
||||
balance = safe_number(decoded.balance),
|
||||
adjustment = safe_number(decoded.adjustment)
|
||||
}
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- HELPER: Read all entity balances from Redis (fresh read)
|
||||
-- ============================================================================
|
||||
local function read_current_entities(cache_key, base_path)
|
||||
local entities_path = base_path .. '.entities'
|
||||
local result = redis.call('JSON.GET', cache_key, entities_path)
|
||||
if not result or result == cjson.null then
|
||||
return {}
|
||||
end
|
||||
local decoded = cjson.decode(result)
|
||||
-- JSONPath returns an array of matches, extract the first element
|
||||
if type(decoded) == 'table' and decoded[1] ~= nil and type(decoded[1]) == 'table' then
|
||||
-- Check if this looks like a JSONPath array wrapper (first element is an object with entity keys)
|
||||
-- vs an actual entity object (first element would be a number or have 'balance' field directly)
|
||||
if decoded.balance == nil and decoded.adjustment == nil then
|
||||
decoded = decoded[1]
|
||||
end
|
||||
end
|
||||
if type(decoded) ~= 'table' then
|
||||
return {}
|
||||
end
|
||||
return decoded
|
||||
end
|
||||
|
||||
local function read_subject_balances(params)
|
||||
local balances_by_id = {}
|
||||
local missing_customer_entitlement_ids = {}
|
||||
local entries_by_balance_key = {}
|
||||
|
||||
for _, ent_obj in ipairs(params.customer_entitlement_deductions or {}) do
|
||||
local customer_entitlement_id = ent_obj.customer_entitlement_id
|
||||
local feature_id = ent_obj.feature_id
|
||||
|
||||
if customer_entitlement_id and feature_id then
|
||||
local balance_key = build_shared_subject_balance_key({
|
||||
org_id = params.org_id,
|
||||
env = params.env,
|
||||
customer_id = params.customer_id,
|
||||
feature_id = feature_id,
|
||||
})
|
||||
|
||||
if entries_by_balance_key[balance_key] == nil then
|
||||
entries_by_balance_key[balance_key] = {
|
||||
feature_id = feature_id,
|
||||
customer_entitlement_ids = {},
|
||||
}
|
||||
end
|
||||
|
||||
table.insert(
|
||||
entries_by_balance_key[balance_key].customer_entitlement_ids,
|
||||
customer_entitlement_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
for balance_key, entry in pairs(entries_by_balance_key) do
|
||||
local hmget_args = { 'HMGET', balance_key }
|
||||
for _, customer_entitlement_id in ipairs(entry.customer_entitlement_ids) do
|
||||
table.insert(hmget_args, customer_entitlement_id)
|
||||
end
|
||||
|
||||
local raw_values = redis.call(unpack(hmget_args))
|
||||
|
||||
for index, customer_entitlement_id in ipairs(entry.customer_entitlement_ids) do
|
||||
local raw_value = raw_values[index]
|
||||
local subject_balance = decode_subject_balance(raw_value)
|
||||
|
||||
if subject_balance == nil then
|
||||
table.insert(
|
||||
missing_customer_entitlement_ids,
|
||||
customer_entitlement_id
|
||||
)
|
||||
else
|
||||
balances_by_id[customer_entitlement_id] = {
|
||||
balance_key = balance_key,
|
||||
customer_entitlement_id = customer_entitlement_id,
|
||||
feature_id = entry.feature_id,
|
||||
subject_balance = subject_balance,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
balances_by_id = balances_by_id,
|
||||
missing_customer_entitlement_ids = missing_customer_entitlement_ids,
|
||||
}
|
||||
end
|
||||
|
||||
local function read_rollover_data(rollover)
|
||||
if type(rollover) ~= 'table' then
|
||||
return nil
|
||||
end
|
||||
|
||||
return {
|
||||
balance = safe_number(rollover.balance),
|
||||
usage = safe_number(rollover.usage),
|
||||
entities = safe_table(rollover.entities),
|
||||
}
|
||||
end
|
||||
|
||||
local function read_current_balance(subject_balance)
|
||||
if type(subject_balance) ~= 'table' then
|
||||
return 0
|
||||
end
|
||||
|
||||
return safe_number(subject_balance.balance)
|
||||
end
|
||||
|
||||
local function read_current_entity_balance(subject_balance, entity_id)
|
||||
if type(subject_balance) ~= 'table' or is_nil(entity_id) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local entities = safe_table(subject_balance.entities)
|
||||
local entity_balance = entities[entity_id]
|
||||
|
||||
if type(entity_balance) ~= 'table' then
|
||||
return nil
|
||||
end
|
||||
|
||||
return {
|
||||
balance = safe_number(entity_balance.balance),
|
||||
adjustment = safe_number(entity_balance.adjustment),
|
||||
}
|
||||
end
|
||||
|
||||
local function read_current_entities(subject_balance)
|
||||
if type(subject_balance) ~= 'table' then
|
||||
return {}
|
||||
end
|
||||
|
||||
return safe_table(subject_balance.entities)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user