feat(dw): Add auth token accumulating fact table

tmessi-cp-monthly-active-users
Timothy Messier 2 years ago
parent 5b5a9722a5
commit 97efca17b2
No known key found for this signature in database
GPG Key ID: EFD2F184F7600572

@ -0,0 +1,101 @@
-- Copyright (c) HashiCorp, Inc.
-- SPDX-License-Identifier: BUSL-1.1
begin;
-- wh_user_id is similar to wt_user_id but for the data warehouse.
-- Unlike wt_user_id, this allows for nulls.
create domain wh_user_id as text
check(
length(trim(value)) > 10 or value in ('u_anon', 'u_auth', 'u_recovery')
);
comment on domain wh_user_id is
'"u_anon", "u_auth", "u_recovery" or random ID generated with github.com/hashicorp/go-secure-stdlib/base62';
create table wh_auth_token_accumulating_fact (
auth_token_id wt_public_id primary key,
user_id wh_user_id not null,
user_key wh_dim_key not null
references wh_user_dimension (key)
on delete restrict
on update cascade,
-- date and time foreign keys
auth_token_issued_date_key integer not null
references wh_date_dimension (key)
on delete restrict
on update cascade,
auth_token_issued_time_key integer not null
references wh_time_of_day_dimension (key)
on delete restrict
on update cascade,
auth_token_issued_time wh_timestamp,
auth_token_deleted_date_key integer default -1 not null
references wh_date_dimension (key)
on delete restrict
on update cascade,
auth_token_deleted_time_key integer default -1 not null
references wh_time_of_day_dimension (key)
on delete restrict
on update cascade,
auth_token_deleted_time wh_timestamp default 'infinity'::timestamptz,
auth_token_approximate_last_access_date_key integer default -1 not null
references wh_date_dimension (key)
on delete restrict
on update cascade,
auth_token_approximate_last_access_time_key integer default -1 not null
references wh_time_of_day_dimension (key)
on delete restrict
on update cascade,
auth_token_approximate_last_access_time wh_timestamp,
auth_token_approximate_active_time_range tstzrange not null default tstzrange(current_timestamp, current_timestamp, '[]'),
auth_token_valid_time_range tstzrange not null default tstzrange(current_timestamp, 'infinity'::timestamptz, '[]'),
-- the auth_token_count must always be 1
-- this is a common pattern in data warehouse models
-- See The Data Warehouse Toolkit, Third Edition
-- by Ralph Kimball and Margy Ross for more information
auth_token_count smallint default 1 not null
constraint auth_token_count_must_be_1
check(auth_token_count = 1),
constraint last_accessed_time_lte_deleted_time
check(auth_token_approximate_last_access_time <= auth_token_deleted_time),
constraint active_time_lower_eq_issued_time
check(lower(auth_token_approximate_active_time_range) = auth_token_issued_time),
constraint active_time_upper_eq_last_accessed_time
check(upper(auth_token_approximate_active_time_range) = auth_token_approximate_last_access_time),
constraint valid_time_lower_eq_issued
check(lower(auth_token_valid_time_range) = auth_token_issued_time),
constraint valid_time_upper_eq_deleted
check(upper(auth_token_valid_time_range) = auth_token_deleted_time),
constraint active_time_contained_by_valid_time
check(auth_token_approximate_active_time_range <@ auth_token_valid_time_range)
);
comment on table wh_auth_token_accumulating_fact is
'The Wh Auth Token Accumulating Fact table is an accumulating fact table. '
'The grain of the fact table is one row per auth token.';
create function wh_insert_auth_token() returns trigger
as $$
begin
select user_id
into new.user_id
from wh_user_dimension
where key = new.user_key;
return new;
end;
$$ language plpgsql;
create trigger wh_insert_auth_token before insert on wh_auth_token_accumulating_fact
for each row execute function wh_insert_auth_token();
create trigger immutable_columns before update on wh_auth_token_accumulating_fact
for each row execute procedure immutable_columns('user_id', 'user_key', 'auth_token_issued_time', 'auth_token_issued_time_key', 'auth_token_issued_date_key');
commit;

@ -0,0 +1,37 @@
-- Copyright (c) HashiCorp, Inc.
-- SPDX-License-Identifier: BUSL-1.1
begin;
select plan(3);
create table test_wh_user_id (
id wh_user_id
);
prepare too_short as
insert into test_wh_user_id (id)
values ('short');
select throws_ok(
'too_short',
'23514',
'value for domain wh_user_id violates check constraint "wh_user_id_check"'
);
prepare too_short_trim as
insert into test_wh_user_id (id)
values (' short ');
select throws_ok(
'too_short_trim',
'23514',
'value for domain wh_user_id violates check constraint "wh_user_id_check"'
);
prepare valid as
insert into test_wh_user_id (id)
values ('u_123456789'),
('u_anon'),
('u_auth'),
('u_recovery');
select lives_ok('valid');
select * from finish();
rollback;

@ -0,0 +1,507 @@
-- Copyright (c) HashiCorp, Inc.
-- SPDX-License-Identifier: BUSL-1.1
begin;
select plan(13);
-- Create a user dimension for corresponding auth token's user.
insert into wh_user_dimension (
user_id, user_name, user_description,
auth_account_id, auth_account_type, auth_account_name, auth_account_description,
auth_method_id, auth_method_type, auth_method_name, auth_method_description,
user_organization_id, user_organization_name, user_organization_description,
current_row_indicator,
row_effective_time, row_expiration_time,
auth_method_external_id, auth_account_external_id, auth_account_full_name, auth_account_email
) values (
'u_____user1', 'None', 'None',
'a______acc1', 'None', 'None', 'None',
'am______am1', 'None', 'None', 'None',
'o______org1', 'None', 'None',
'current',
now(), 'infinity'::timestamptz,
'None', 'None', 'None', 'None'
);
prepare insert_access_time_after_delete as
with
issued_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 10:00:00'::timestamptz),
wh_time_key('2023-12-13 10:00:00'::timestamptz),
'2023-12-13 10:00:00'::timestamptz
),
accessed_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 12:00:00'::timestamptz),
wh_time_key('2023-12-13 12:00:00'::timestamptz),
'2023-12-13 12:00:00'::timestamptz
),
deleted_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 11:00:00'::timestamptz),
wh_time_key('2023-12-13 11:00:00'::timestamptz),
'2023-12-13 11:00:00'::timestamptz
),
user_dim(key) as (
select key
from wh_user_dimension
where user_id = 'u_____user1'
)
insert into wh_auth_token_accumulating_fact (
auth_token_id,
user_key,
auth_token_issued_date_key,
auth_token_issued_time_key,
auth_token_issued_time,
auth_token_deleted_date_key,
auth_token_deleted_time_key,
auth_token_deleted_time,
auth_token_approximate_last_access_date_key,
auth_token_approximate_last_access_time_key,
auth_token_approximate_last_access_time,
auth_token_approximate_active_time_range,
auth_token_valid_time_range,
auth_token_count
)
select 'tok___token1',
user_dim.key,
issued_timestamp.date_dim_key,
issued_timestamp.time_dim_key,
issued_timestamp.ts,
deleted_timestamp.date_dim_key,
deleted_timestamp.time_dim_key,
deleted_timestamp.ts,
accessed_timestamp.date_dim_key,
accessed_timestamp.time_dim_key,
accessed_timestamp.ts,
tstzrange(issued_timestamp.ts, accessed_timestamp.ts),
tstzrange(issued_timestamp.ts, accessed_timestamp.ts),
1
from user_dim,
issued_timestamp,
deleted_timestamp,
accessed_timestamp;
select throws_ok(
'insert_access_time_after_delete',
'23514',
'new row for relation "wh_auth_token_accumulating_fact" violates check constraint "last_accessed_time_lte_deleted_time"'
);
prepare insert_active_time_after_issued as
with
issued_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 10:00:00'::timestamptz),
wh_time_key('2023-12-13 10:00:00'::timestamptz),
'2023-12-13 10:00:00'::timestamptz
),
accessed_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 12:00:00'::timestamptz),
wh_time_key('2023-12-13 12:00:00'::timestamptz),
'2023-12-13 12:00:00'::timestamptz
),
deleted_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 13:00:00'::timestamptz),
wh_time_key('2023-12-13 13:00:00'::timestamptz),
'2023-12-13 13:00:00'::timestamptz
),
user_dim(key) as (
select key
from wh_user_dimension
where user_id = 'u_____user1'
)
insert into wh_auth_token_accumulating_fact (
auth_token_id,
user_key,
auth_token_issued_date_key,
auth_token_issued_time_key,
auth_token_issued_time,
auth_token_deleted_date_key,
auth_token_deleted_time_key,
auth_token_deleted_time,
auth_token_approximate_last_access_date_key,
auth_token_approximate_last_access_time_key,
auth_token_approximate_last_access_time,
auth_token_approximate_active_time_range,
auth_token_valid_time_range,
auth_token_count
)
select 'tok___token2',
user_dim.key,
issued_timestamp.date_dim_key,
issued_timestamp.time_dim_key,
issued_timestamp.ts,
deleted_timestamp.date_dim_key,
deleted_timestamp.time_dim_key,
deleted_timestamp.ts,
accessed_timestamp.date_dim_key,
accessed_timestamp.time_dim_key,
accessed_timestamp.ts,
tstzrange(issued_timestamp.ts + interval '10 minutes', accessed_timestamp.ts),
tstzrange(issued_timestamp.ts, deleted_timestamp.ts),
1
from user_dim,
issued_timestamp,
deleted_timestamp,
accessed_timestamp;
select throws_ok(
'insert_active_time_after_issued',
'23514',
'new row for relation "wh_auth_token_accumulating_fact" violates check constraint "active_time_lower_eq_issued_time"'
);
prepare insert_active_time_before_access as
with
issued_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 10:00:00'::timestamptz),
wh_time_key('2023-12-13 10:00:00'::timestamptz),
'2023-12-13 10:00:00'::timestamptz
),
accessed_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 12:00:00'::timestamptz),
wh_time_key('2023-12-13 12:00:00'::timestamptz),
'2023-12-13 12:00:00'::timestamptz
),
deleted_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 13:00:00'::timestamptz),
wh_time_key('2023-12-13 13:00:00'::timestamptz),
'2023-12-13 13:00:00'::timestamptz
),
user_dim(key) as (
select key
from wh_user_dimension
where user_id = 'u_____user1'
)
insert into wh_auth_token_accumulating_fact (
auth_token_id,
user_key,
auth_token_issued_date_key,
auth_token_issued_time_key,
auth_token_issued_time,
auth_token_deleted_date_key,
auth_token_deleted_time_key,
auth_token_deleted_time,
auth_token_approximate_last_access_date_key,
auth_token_approximate_last_access_time_key,
auth_token_approximate_last_access_time,
auth_token_approximate_active_time_range,
auth_token_valid_time_range,
auth_token_count
)
select 'tok___token2',
user_dim.key,
issued_timestamp.date_dim_key,
issued_timestamp.time_dim_key,
issued_timestamp.ts,
deleted_timestamp.date_dim_key,
deleted_timestamp.time_dim_key,
deleted_timestamp.ts,
accessed_timestamp.date_dim_key,
accessed_timestamp.time_dim_key,
accessed_timestamp.ts,
tstzrange(issued_timestamp.ts, accessed_timestamp.ts - interval '10 minutes'),
tstzrange(issued_timestamp.ts, deleted_timestamp.ts),
1
from user_dim,
issued_timestamp,
deleted_timestamp,
accessed_timestamp;
select throws_ok(
'insert_active_time_before_access',
'23514',
'new row for relation "wh_auth_token_accumulating_fact" violates check constraint "active_time_upper_eq_last_accessed_time"'
);
prepare insert_active_not_contained_by_valid as
with
issued_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 10:00:00'::timestamptz),
wh_time_key('2023-12-13 10:00:00'::timestamptz),
'2023-12-13 10:00:00'::timestamptz
),
accessed_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 12:00:00'::timestamptz),
wh_time_key('2023-12-13 12:00:00'::timestamptz),
'2023-12-13 12:00:00'::timestamptz
),
deleted_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 11:00:00'::timestamptz),
wh_time_key('2023-12-13 11:00:00'::timestamptz),
'2023-12-13 11:00:00'::timestamptz
),
user_dim(key) as (
select key
from wh_user_dimension
where user_id = 'u_____user1'
)
insert into wh_auth_token_accumulating_fact (
auth_token_id,
user_key,
auth_token_issued_date_key,
auth_token_issued_time_key,
auth_token_issued_time,
auth_token_deleted_date_key,
auth_token_deleted_time_key,
auth_token_deleted_time,
auth_token_approximate_last_access_date_key,
auth_token_approximate_last_access_time_key,
auth_token_approximate_last_access_time,
auth_token_approximate_active_time_range,
auth_token_valid_time_range,
auth_token_count
)
select 'tok___token1',
user_dim.key,
issued_timestamp.date_dim_key,
issued_timestamp.time_dim_key,
issued_timestamp.ts,
deleted_timestamp.date_dim_key,
deleted_timestamp.time_dim_key,
deleted_timestamp.ts,
accessed_timestamp.date_dim_key,
accessed_timestamp.time_dim_key,
accessed_timestamp.ts,
tstzrange(issued_timestamp.ts, accessed_timestamp.ts),
tstzrange(issued_timestamp.ts, deleted_timestamp.ts),
1
from user_dim,
issued_timestamp,
deleted_timestamp,
accessed_timestamp;
select throws_ok(
'insert_active_not_contained_by_valid',
'23514',
'new row for relation "wh_auth_token_accumulating_fact" violates check constraint "active_time_contained_by_valid_time"'
);
prepare insert_valid_time_before_issued as
with
issued_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 10:00:00'::timestamptz),
wh_time_key('2023-12-13 10:00:00'::timestamptz),
'2023-12-13 10:00:00'::timestamptz
),
accessed_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 12:00:00'::timestamptz),
wh_time_key('2023-12-13 12:00:00'::timestamptz),
'2023-12-13 12:00:00'::timestamptz
),
deleted_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 13:00:00'::timestamptz),
wh_time_key('2023-12-13 13:00:00'::timestamptz),
'2023-12-13 13:00:00'::timestamptz
),
user_dim(key) as (
select key
from wh_user_dimension
where user_id = 'u_____user1'
)
insert into wh_auth_token_accumulating_fact (
auth_token_id,
user_key,
auth_token_issued_date_key,
auth_token_issued_time_key,
auth_token_issued_time,
auth_token_deleted_date_key,
auth_token_deleted_time_key,
auth_token_deleted_time,
auth_token_approximate_last_access_date_key,
auth_token_approximate_last_access_time_key,
auth_token_approximate_last_access_time,
auth_token_approximate_active_time_range,
auth_token_valid_time_range,
auth_token_count
)
select 'tok___token2',
user_dim.key,
issued_timestamp.date_dim_key,
issued_timestamp.time_dim_key,
issued_timestamp.ts,
deleted_timestamp.date_dim_key,
deleted_timestamp.time_dim_key,
deleted_timestamp.ts,
accessed_timestamp.date_dim_key,
accessed_timestamp.time_dim_key,
accessed_timestamp.ts,
tstzrange(issued_timestamp.ts, accessed_timestamp.ts),
tstzrange(issued_timestamp.ts - interval '10 minutes', deleted_timestamp.ts),
1
from user_dim,
issued_timestamp,
deleted_timestamp,
accessed_timestamp;
select throws_ok(
'insert_valid_time_before_issued',
'23514',
'new row for relation "wh_auth_token_accumulating_fact" violates check constraint "valid_time_lower_eq_issued"'
);
prepare insert_valid_time_before_deleted as
with
issued_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 10:00:00'::timestamptz),
wh_time_key('2023-12-13 10:00:00'::timestamptz),
'2023-12-13 10:00:00'::timestamptz
),
accessed_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 12:00:00'::timestamptz),
wh_time_key('2023-12-13 12:00:00'::timestamptz),
'2023-12-13 12:00:00'::timestamptz
),
deleted_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 13:00:00'::timestamptz),
wh_time_key('2023-12-13 13:00:00'::timestamptz),
'2023-12-13 13:00:00'::timestamptz
),
user_dim(key) as (
select key
from wh_user_dimension
where user_id = 'u_____user1'
)
insert into wh_auth_token_accumulating_fact (
auth_token_id,
user_key,
auth_token_issued_date_key,
auth_token_issued_time_key,
auth_token_issued_time,
auth_token_deleted_date_key,
auth_token_deleted_time_key,
auth_token_deleted_time,
auth_token_approximate_last_access_date_key,
auth_token_approximate_last_access_time_key,
auth_token_approximate_last_access_time,
auth_token_approximate_active_time_range,
auth_token_valid_time_range,
auth_token_count
)
select 'tok___token2',
user_dim.key,
issued_timestamp.date_dim_key,
issued_timestamp.time_dim_key,
issued_timestamp.ts,
deleted_timestamp.date_dim_key,
deleted_timestamp.time_dim_key,
deleted_timestamp.ts,
accessed_timestamp.date_dim_key,
accessed_timestamp.time_dim_key,
accessed_timestamp.ts,
tstzrange(issued_timestamp.ts, accessed_timestamp.ts),
tstzrange(issued_timestamp.ts, deleted_timestamp.ts - interval '10 minutes'),
1
from user_dim,
issued_timestamp,
deleted_timestamp,
accessed_timestamp;
select throws_ok(
'insert_valid_time_before_deleted',
'23514',
'new row for relation "wh_auth_token_accumulating_fact" violates check constraint "valid_time_upper_eq_deleted"'
);
prepare insert_success as
with
issued_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 10:00:00'::timestamptz),
wh_time_key('2023-12-13 10:00:00'::timestamptz),
'2023-12-13 10:00:00'::timestamptz
),
accessed_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 12:00:00'::timestamptz),
wh_time_key('2023-12-13 12:00:00'::timestamptz),
'2023-12-13 12:00:00'::timestamptz
),
deleted_timestamp(date_dim_key, time_dim_key, ts) as (
select wh_date_key('2023-12-13 13:00:00'::timestamptz),
wh_time_key('2023-12-13 13:00:00'::timestamptz),
'2023-12-13 13:00:00'::timestamptz
),
user_dim(key) as (
select key
from wh_user_dimension
where user_id = 'u_____user1'
)
insert into wh_auth_token_accumulating_fact (
auth_token_id,
user_key,
auth_token_issued_date_key,
auth_token_issued_time_key,
auth_token_issued_time,
auth_token_deleted_date_key,
auth_token_deleted_time_key,
auth_token_deleted_time,
auth_token_approximate_last_access_date_key,
auth_token_approximate_last_access_time_key,
auth_token_approximate_last_access_time,
auth_token_approximate_active_time_range,
auth_token_valid_time_range,
auth_token_count
)
select 'tok___token2',
user_dim.key,
issued_timestamp.date_dim_key,
issued_timestamp.time_dim_key,
issued_timestamp.ts,
deleted_timestamp.date_dim_key,
deleted_timestamp.time_dim_key,
deleted_timestamp.ts,
accessed_timestamp.date_dim_key,
accessed_timestamp.time_dim_key,
accessed_timestamp.ts,
tstzrange(issued_timestamp.ts, accessed_timestamp.ts),
tstzrange(issued_timestamp.ts, deleted_timestamp.ts),
1
from user_dim,
issued_timestamp,
deleted_timestamp,
accessed_timestamp;
select lives_ok('insert_success');
-- ensure user_id was properly set
select is(wh_auth_token_accumulating_fact.user_id, 'u_____user1')
from wh_auth_token_accumulating_fact
where auth_token_id = 'tok___token2';
prepare update_user_id as
update wh_auth_token_accumulating_fact set user_id = 'u_____user2'
where auth_token_id = 'tok___token2';
select throws_ok(
'update_user_id',
'23601',
'immutable column: wh_auth_token_accumulating_fact.user_id'
);
prepare update_user_key as
update wh_auth_token_accumulating_fact set user_key = 'key_2'
where auth_token_id = 'tok___token2';
select throws_ok(
'update_user_key',
'23601',
'immutable column: wh_auth_token_accumulating_fact.user_key'
);
prepare update_auth_token_issued_time as
update wh_auth_token_accumulating_fact set auth_token_issued_time = '2023-12-13 11:01:00'::timestamptz
where auth_token_id = 'tok___token2';
select throws_ok(
'update_auth_token_issued_time',
'23601',
'immutable column: wh_auth_token_accumulating_fact.auth_token_issued_time'
);
prepare update_auth_token_issued_time_key as
update wh_auth_token_accumulating_fact set auth_token_issued_time_key = wh_time_key('2023-12-13 11:01:00'::timestamptz)
where auth_token_id = 'tok___token2';
select throws_ok(
'update_auth_token_issued_time_key',
'23601',
'immutable column: wh_auth_token_accumulating_fact.auth_token_issued_time_key'
);
prepare update_auth_token_issued_date_key as
update wh_auth_token_accumulating_fact set auth_token_issued_date_key = wh_date_key('2023-12-14 11:00:00'::timestamptz)
where auth_token_id = 'tok___token2';
select throws_ok(
'update_auth_token_issued_date_key',
'23601',
'immutable column: wh_auth_token_accumulating_fact.auth_token_issued_date_key'
);
select * from finish();
rollback;
Loading…
Cancel
Save