Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "0.36.0",
"version": "0.39.0",
"npmClient": "pnpm"
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"jest": "^30.2.0",
"jest-in-case": "^1.0.2",
"lerna": "^8.2.3",
"pgsql-test": "^5.4.1",
"pgsql-test": "^5.10.6",
"pnpm-policy": "^0.2.2",
"prettier": "^3.0.2",
"rimraf": "4.4.1",
Expand Down
2 changes: 1 addition & 1 deletion packages/achievements/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
EXTENSION = pgpm-achievements
DATA = sql/pgpm-achievements--0.36.0.sql
DATA = sql/pgpm-achievements--0.39.0.sql

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
Expand Down
2 changes: 1 addition & 1 deletion packages/achievements/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pgpm/achievements",
"version": "0.36.0",
"version": "0.39.0",
"description": "Achievement system for tracking user progress and milestones",
"author": "Dan Lynch <pyramation@gmail.com>",
"contributors": [
Expand Down
2 changes: 1 addition & 1 deletion packages/achievements/pgpm-achievements.control
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pgpm-achievements extension
comment = 'pgpm-achievements extension'
default_version = '0.36.0'
default_version = '0.39.0'
module_pathname = '$libdir/pgpm-achievements'
requires = 'plpgsql,pgpm-jwt-claims,pgpm-verify'
relocatable = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

BEGIN;

DROP FUNCTION status_private.tg_achievement;
DROP FUNCTION status_private.tg_achievement_toggle;
DROP FUNCTION status_private.tg_achievement_boolean;
DROP FUNCTION status_private.tg_achievement_toggle_boolean;
DROP FUNCTION status_private.tg_achievement_toggle_boolean();
DROP FUNCTION status_private.tg_achievement_boolean();
DROP FUNCTION status_private.tg_achievement_toggle();
DROP FUNCTION status_private.tg_achievement();

COMMIT;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

DROP FUNCTION status_private.upsert_achievement;
DROP FUNCTION status_private.upsert_achievement(uuid, text, int4);

COMMIT;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

DROP FUNCTION status_private.user_completed_step;
DROP FUNCTION status_private.user_completed_step(text, uuid);

COMMIT;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

DROP FUNCTION status_private.user_incompleted_step;
DROP FUNCTION status_private.user_incompleted_step(text, uuid);

COMMIT;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

DROP FUNCTION status_public.steps_required;
DROP FUNCTION status_public.steps_required(text, uuid);

COMMIT;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

DROP FUNCTION status_public.user_achieved;
DROP FUNCTION status_public.user_achieved(text, uuid);

COMMIT;
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
BEGIN;

DROP TRIGGER update_achievements_tg ON status_public.user_steps;
DROP FUNCTION status_private.tg_update_achievements_tg;
DROP FUNCTION status_private.tg_update_achievements_tg();

COMMIT;
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

BEGIN;

SELECT verify_function ('status_private.tg_achievement');
SELECT verify_function ('status_private.tg_achievement_toggle');
SELECT verify_function ('status_private.tg_achievement_boolean');
SELECT verify_function ('status_private.tg_achievement_toggle_boolean');
SELECT assert_function('status_private.tg_achievement()'::regprocedure);
SELECT assert_function('status_private.tg_achievement_toggle()'::regprocedure);
SELECT assert_function('status_private.tg_achievement_boolean()'::regprocedure);
SELECT assert_function('status_private.tg_achievement_toggle_boolean()'::regprocedure);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_function ('status_private.upsert_achievement');
SELECT assert_function('status_private.upsert_achievement(uuid, text, int4)'::regprocedure);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_function ('status_private.user_completed_step');
SELECT assert_function('status_private.user_completed_step(text, uuid)'::regprocedure);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_function ('status_private.user_incompleted_step');
SELECT assert_function('status_private.user_incompleted_step(text, uuid)'::regprocedure);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_schema ('status_private');
SELECT assert_schema('status_private'::regnamespace);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_function ('status_public.steps_required');
SELECT assert_function('status_public.steps_required(text, uuid)'::regprocedure);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_function ('status_public.user_achieved');
SELECT assert_function('status_public.user_achieved(text, uuid)'::regprocedure);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_schema ('status_public');
SELECT assert_schema('status_public'::regnamespace);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_table ('status_public.level_requirements');
SELECT assert_table('status_public.level_requirements'::regclass);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_table ('status_public.levels');
SELECT assert_table('status_public.levels'::regclass);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_security ('status_public.user_achievements');
SELECT assert_table_security('status_public.user_achievements'::regclass);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

BEGIN;

SELECT verify_policy ('can_select_user_achievements', 'status_public.user_achievements');
SELECT verify_policy ('can_insert_user_achievements', 'status_public.user_achievements');
SELECT verify_policy ('can_update_user_achievements', 'status_public.user_achievements');
SELECT verify_policy ('can_delete_user_achievements', 'status_public.user_achievements');

SELECT has_table_privilege('authenticated', 'status_public.user_achievements', 'INSERT');
SELECT has_table_privilege('authenticated', 'status_public.user_achievements', 'SELECT');
SELECT has_table_privilege('authenticated', 'status_public.user_achievements', 'UPDATE');
SELECT has_table_privilege('authenticated', 'status_public.user_achievements', 'DELETE');
SELECT assert_policy('status_public.user_achievements'::regclass, 'can_select_user_achievements', 'select', true, true, false);
SELECT assert_policy('status_public.user_achievements'::regclass, 'can_insert_user_achievements', 'insert', true, false, true);
SELECT assert_policy('status_public.user_achievements'::regclass, 'can_update_user_achievements', 'update', true, true, false);
SELECT assert_policy('status_public.user_achievements'::regclass, 'can_delete_user_achievements', 'delete', true, true, false);

SELECT assert_table_grant('status_public.user_achievements'::regclass, 'authenticated', 'INSERT');
SELECT assert_table_grant('status_public.user_achievements'::regclass, 'authenticated', 'SELECT');
SELECT assert_table_grant('status_public.user_achievements'::regclass, 'authenticated', 'UPDATE');
SELECT assert_table_grant('status_public.user_achievements'::regclass, 'authenticated', 'DELETE');

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_table ('status_public.user_achievements');
SELECT assert_table('status_public.user_achievements'::regclass);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

BEGIN;

SELECT verify_table ('status_public.user_steps');
SELECT assert_table('status_public.user_steps'::regclass);

ROLLBACK;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

BEGIN;

SELECT verify_function ('status_private.tg_update_achievements_tg');
SELECT verify_trigger ('status_public.update_achievements_tg');
SELECT assert_function('status_private.tg_update_achievements_tg()'::regprocedure);
SELECT assert_trigger('status_public.user_steps'::regclass, 'update_achievements_tg', 'status_private.tg_update_achievements_tg'::regproc, 5);

ROLLBACK;
2 changes: 1 addition & 1 deletion packages/app-scope/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
EXTENSION = pgpm-app-scope
DATA = sql/pgpm-app-scope--0.36.0.sql
DATA = sql/pgpm-app-scope--0.39.0.sql

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
Expand Down
6 changes: 5 additions & 1 deletion packages/app-scope/__tests__/membership.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ describe('app_scope scope frames (membership climb + platform fall-through)', ()
]);
});

it('frames(): custom entity climb then full platform fall-through (8 frames)', async () => {
it('frames(): custom entity climb then full platform fall-through (9 frames)', async () => {
const rows = await pg.any(
`SELECT scope, lookup_database_id, key_value
FROM app_scope.frames($1, 'team', $2)`,
Expand All @@ -184,6 +184,10 @@ describe('app_scope scope frames (membership climb + platform fall-through)', ()
{ scope: 'department', lookup_database_id: TENANT_DB, key_value: DEPT_ID },
{ scope: 'org', lookup_database_id: TENANT_DB, key_value: ORG_ID },
{ scope: 'app', lookup_database_id: TENANT_DB, key_value: null },
// the tenant's OWN database frame precedes the platform fall-through, so a
// surface the tenant provisioned for itself outranks the shared platform
// plane the fall-through serves for the same tenant key.
{ scope: 'database', lookup_database_id: TENANT_DB, key_value: TENANT_DB },
// platform database full chain, then the global platform terminal.
// The fall-through database frame is re-keyed by the EXECUTION database:
// rows the tenant sees on this shared plane are keyed by the tenant's id.
Expand Down
21 changes: 21 additions & 0 deletions packages/app-scope/deploy/schemas/app_scope/procedures/frames.sql
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ BEGIN;
-- tenant custom entity execution (e.g. `team` owned by `department` owned by
-- an org):
-- team -> department -> org -> app (in the tenant database)
-- -> database (the tenant's own database frame)
-- -> database -> org -> app -> platform (in the platform database)
-- A non-`database` tenant execution inserts the tenant's own `database` frame
-- before the platform fall-through, so a surface the tenant provisioned for
-- itself outranks the shared platform plane the fall-through serves for that
-- same tenant key. A `database` execution already emits it in its local chain.
-- platform database execution (any scope):
-- <local chain in the platform database> -> platform
-- `platform` execution scope (anywhere):
Expand Down Expand Up @@ -89,6 +94,22 @@ BEGIN
RETURN;
END IF;

-- Before falling through to the platform's shared planes, a tenant execution
-- resolves the execution database's OWN `database` frame: a surface the
-- tenant has provisioned for itself must answer ahead of the shared platform
-- plane the fall-through would otherwise serve for that same tenant key. The
-- fall-through already re-keys the platform `database` frame by this tenant
-- (below), so both frames name the identity (database, this tenant); the
-- tenant's own is strictly more specific and comes first. Skipped for a
-- `database` execution (its local chain already emitted this frame) and for
-- the platform database itself (which has no tenant fall-through).
IF NOT v_is_platform_db AND frames.execution_scope <> 'database' THEN
scope := 'database';
lookup_database_id := frames.database_id;
key_value := frames.database_id;
RETURN NEXT;
END IF;

-- Fall through to the platform database's OWN full local chain (its
-- database -> org -> app), unless the execution already ran inside the
-- platform database (in which case its local chain above already covered it).
Expand Down
Loading
Loading