CREATE TABLE config.circ_matrix_matchpoint (
id SERIAL PRIMARY KEY,
active BOOL NOT NULL DEFAULT TRUE,
+ -- Match Fields
org_unit INT NOT NULL REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top OU for the matchpoint applicability range; we can use org_unit_prox to choose the "best"
grp INT NOT NULL REFERENCES permission.grp_tree (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top applicable group from the group tree; will need descendents and prox functions for filtering
circ_modifier TEXT REFERENCES config.circ_modifier (code) DEFERRABLE INITIALLY DEFERRED,
is_renewal BOOL,
usr_age_lower_bound INTERVAL,
usr_age_upper_bound INTERVAL,
+ -- "Result" Fields
circulate BOOL NOT NULL DEFAULT TRUE, -- Hard "can't circ" flag requiring an override
duration_rule INT NOT NULL REFERENCES config.rule_circ_duration (id) DEFERRABLE INITIALLY DEFERRED,
recurring_fine_rule INT NOT NULL REFERENCES config.rule_recurring_fine (id) DEFERRABLE INITIALLY DEFERRED,
hard_due_date INT REFERENCES config.hard_due_date (id) DEFERRABLE INITIALLY DEFERRED,
script_test TEXT, -- javascript source
total_copy_hold_ratio FLOAT,
- available_copy_hold_ratio FLOAT,
- CONSTRAINT ep_once_per_grp_loc_mod_marc UNIQUE (
- grp, org_unit, circ_modifier, marc_type, marc_form, marc_vr_format, ref_flag,
- juvenile_flag, usr_age_lower_bound, usr_age_upper_bound, is_renewal, copy_circ_lib,
- copy_owning_lib
- )
+ available_copy_hold_ratio FLOAT
);
+-- Nulls don't count for a constraint match, so we have to coalesce them into something that does.
+CREATE UNIQUE INDEX ccmm_once_per_paramset ON config.circ_matrix_matchpoint (org_unit, grp, COALESCE(circ_modifier, ''), COALESCE(marc_type, ''), COALESCE(marc_form, ''), COALESCE(marc_vr_format, ''), COALESCE(copy_circ_lib::TEXT, ''), COALESCE(copy_owning_lib::TEXT, ''), COALESCE(user_home_ou::TEXT, ''), COALESCE(ref_flag::TEXT, ''), COALESCE(juvenile_flag::TEXT, ''), COALESCE(is_renewal::TEXT, ''), COALESCE(usr_age_lower_bound::TEXT, ''), COALESCE(usr_age_upper_bound::TEXT, '')) WHERE active;
-- Tests for max items out by circ_modifier
CREATE TABLE config.circ_matrix_circ_mod_test (
id SERIAL PRIMARY KEY,
active BOOL NOT NULL DEFAULT TRUE,
strict_ou_match BOOL NOT NULL DEFAULT FALSE,
+ -- Match Fields
user_home_ou INT REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top OU for the matchpoint applicability range; we can use org_unit_prox to choose the "best"
request_ou INT REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top OU for the matchpoint applicability range; we can use org_unit_prox to choose the "best"
pickup_ou INT REFERENCES actor.org_unit (id) DEFERRABLE INITIALLY DEFERRED, -- Set to the top OU for the matchpoint applicability range; we can use org_unit_prox to choose the "best"
marc_vr_format TEXT REFERENCES config.videorecording_format_map (code) DEFERRABLE INITIALLY DEFERRED,
juvenile_flag BOOL,
ref_flag BOOL,
+ -- "Result" Fields
holdable BOOL NOT NULL DEFAULT TRUE, -- Hard "can't hold" flag requiring an override
distance_is_from_owner BOOL NOT NULL DEFAULT FALSE, -- How to calculate transit_range. True means owning lib, false means copy circ lib
transit_range INT REFERENCES actor.org_unit_type (id) DEFERRABLE INITIALLY DEFERRED, -- Can circ inside range of cn.owner/cp.circ_lib at depth of the org_unit_type specified here
max_holds INT, -- Total hold requests must be less than this, NULL means skip (always pass)
include_frozen_holds BOOL NOT NULL DEFAULT TRUE, -- Include frozen hold requests in the count for max_holds test
stop_blocked_user BOOL NOT NULL DEFAULT FALSE, -- Stop users who cannot check out items from placing holds
- age_hold_protect_rule INT REFERENCES config.rule_age_hold_protect (id) DEFERRABLE INITIALLY DEFERRED, -- still not sure we want to move this off the copy
- CONSTRAINT hous_once_per_grp_loc_mod_marc UNIQUE (user_home_ou, request_ou, pickup_ou, item_owning_ou, item_circ_ou, requestor_grp, usr_grp, circ_modifier, marc_type, marc_form, marc_vr_format, ref_flag, juvenile_flag)
+ age_hold_protect_rule INT REFERENCES config.rule_age_hold_protect (id) DEFERRABLE INITIALLY DEFERRED -- still not sure we want to move this off the copy
);
+-- Nulls don't count for a constraint match, so we have to coalesce them into something that does.
+CREATE UNIQUE INDEX chmm_once_per_paramset ON config.hold_matrix_matchpoint (COALESCE(user_home_ou::TEXT, ''), COALESCE(request_ou::TEXT, ''), COALESCE(pickup_ou::TEXT, ''), COALESCE(item_owning_ou::TEXT, ''), COALESCE(item_circ_ou::TEXT, ''), COALESCE(usr_grp::TEXT, ''), COALESCE(requestor_grp::TEXT, ''), COALESCE(circ_modifier, ''), COALESCE(marc_type, ''), COALESCE(marc_form, ''), COALESCE(marc_vr_format, ''), COALESCE(juvenile_flag::TEXT, ''), COALESCE(ref_flag::TEXT, '')) WHERE active;
+
CREATE OR REPLACE FUNCTION action.find_hold_matrix_matchpoint(pickup_ou integer, request_ou integer, match_item bigint, match_user integer, match_requestor integer)
RETURNS integer AS
$func$
--- /dev/null
+BEGIN;
+
+INSERT INTO config.upgrade_log (version) VALUES ('0482');
+
+-- Drop old (non-functional) constraints
+
+ALTER TABLE config.circ_matrix_matchpoint
+ DROP CONSTRAINT ep_once_per_grp_loc_mod_marc;
+
+ALTER TABLE config.hold_matrix_matchpoint
+ DROP CONSTRAINT hous_once_per_grp_loc_mod_marc;
+
+-- Clean up tables before making normalized index
+
+CREATE OR REPLACE FUNCTION action.cleanup_matrix_matchpoints() RETURNS void AS $func$
+DECLARE
+ temp_row RECORD;
+BEGIN
+ -- Circ Matrix
+ FOR temp_row IN
+ SELECT org_unit, grp, circ_modifier, marc_type, marc_form, marc_vr_format, copy_circ_lib, copy_owning_lib, user_home_ou, ref_flag, juvenile_flag, is_renewal, usr_age_lower_bound, usr_age_upper_bound, COUNT(id) as rowcount, MIN(id) as firstrow
+ FROM config.circ_matrix_matchpoint
+ WHERE active
+ GROUP BY org_unit, grp, circ_modifier, marc_type, marc_form, marc_vr_format, copy_circ_lib, copy_owning_lib, user_home_ou, ref_flag, juvenile_flag, is_renewal, usr_age_lower_bound, usr_age_upper_bound
+ HAVING COUNT(id) > 1 LOOP
+
+ UPDATE config.circ_matrix_matchpoint SET active=false
+ WHERE id > temp_row.firstrow
+ AND org_unit = temp_row.org_unit
+ AND grp = temp_row.grp
+ AND circ_modifier IS NOT DISTINCT FROM temp_row.circ_modifier
+ AND marc_type IS NOT DISTINCT FROM temp_row.marc_type
+ AND marc_form IS NOT DISTINCT FROM temp_row.marc_form
+ AND marc_vr_format IS NOT DISTINCT FROM temp_row.marc_vr_format
+ AND copy_circ_lib IS NOT DISTINCT FROM temp_row.copy_circ_lib
+ AND copy_owning_lib IS NOT DISTINCT FROM temp_row.copy_owning_lib
+ AND user_home_ou IS NOT DISTINCT FROM temp_row.user_home_ou
+ AND ref_flag IS NOT DISTINCT FROM temp_row.ref_flag
+ AND juvenile_flag IS NOT DISTINCT FROM temp_row.juvenile_flag
+ AND is_renewal IS NOT DISTINCT FROM temp_row.is_renewal
+ AND usr_age_lower_bound IS NOT DISTINCT FROM temp_row.usr_age_lower_bound
+ AND usr_age_upper_bound IS NOT DISTINCT FROM temp_row.usr_age_upper_bound;
+ END LOOP;
+
+ -- Hold Matrix
+ FOR temp_row IN
+ SELECT user_home_ou, request_ou, pickup_ou, item_owning_ou, item_circ_ou, usr_grp, requestor_grp, circ_modifier, marc_type, marc_form, marc_vr_format, juvenile_flag, ref_flag, COUNT(id) as rowcount, MIN(id) as firstrow
+ FROM config.hold_matrix_matchpoint
+ WHERE active
+ GROUP BY user_home_ou, request_ou, pickup_ou, item_owning_ou, item_circ_ou, usr_grp, requestor_grp, circ_modifier, marc_type, marc_form, marc_vr_format, juvenile_flag, ref_flag
+ HAVING COUNT(id) > 1 LOOP
+
+ UPDATE config.hold_matrix_matchpoint SET active=false
+ WHERE id > temp_row.firstrow
+ AND user_home_ou IS NOT DISTINCT FROM temp_row.user_home_ou
+ AND request_ou IS NOT DISTINCT FROM temp_row.request_ou
+ AND pickup_ou IS NOT DISTINCT FROM temp_row.pickup_ou
+ AND item_owning_ou IS NOT DISTINCT FROM temp_row.item_owning_ou
+ AND item_circ_ou IS NOT DISTINCT FROM temp_row.item_circ_ou
+ AND usr_grp IS NOT DISTINCT FROM temp_row.usr_grp
+ AND requestor_grp IS NOT DISTINCT FROM temp_row.requestor_grp
+ AND circ_modifier IS NOT DISTINCT FROM temp_row.circ_modifier
+ AND marc_type IS NOT DISTINCT FROM temp_row.marc_type
+ AND marc_form IS NOT DISTINCT FROM temp_row.marc_form
+ AND marc_vr_format IS NOT DISTINCT FROM temp_row.marc_vr_format
+ AND juvenile_flag IS NOT DISTINCT FROM temp_row.juvenile_flag
+ AND ref_flag IS NOT DISTINCT FROM temp_row.ref_flag;
+ END LOOP;
+END;
+$func$ LANGUAGE plpgsql;
+
+SELECT action.cleanup_matrix_matchpoints();
+
+DROP FUNCTION IF EXISTS action.cleanup_matrix_matchpoints();
+
+-- Create Normalized indexes
+
+CREATE UNIQUE INDEX ccmm_once_per_paramset ON config.circ_matrix_matchpoint (org_unit, grp, COALESCE(circ_modifier, ''), COALESCE(marc_type, ''), COALESCE(marc_form, ''), COALESCE(marc_vr_format, ''), COALESCE(copy_circ_lib::TEXT, ''), COALESCE(copy_owning_lib::TEXT, ''), COALESCE(user_home_ou::TEXT, ''), COALESCE(ref_flag::TEXT, ''), COALESCE(juvenile_flag::TEXT, ''), COALESCE(is_renewal::TEXT, ''), COALESCE(usr_age_lower_bound::TEXT, ''), COALESCE(usr_age_upper_bound::TEXT, '')) WHERE active;
+
+CREATE UNIQUE INDEX chmm_once_per_paramset ON config.hold_matrix_matchpoint (COALESCE(user_home_ou::TEXT, ''), COALESCE(request_ou::TEXT, ''), COALESCE(pickup_ou::TEXT, ''), COALESCE(item_owning_ou::TEXT, ''), COALESCE(item_circ_ou::TEXT, ''), COALESCE(usr_grp::TEXT, ''), COALESCE(requestor_grp::TEXT, ''), COALESCE(circ_modifier, ''), COALESCE(marc_type, ''), COALESCE(marc_form, ''), COALESCE(marc_vr_format, ''), COALESCE(juvenile_flag::TEXT, ''), COALESCE(ref_flag::TEXT, '')) WHERE active;
+
+COMMIT;