-
Notifications
You must be signed in to change notification settings - Fork 5
ENG-1311 Unify ConceptAccess and ContentAccess tables #712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: eng-1310-database-change-allow-concepts-to-exist-without-content
Are you sure you want to change the base?
Conversation
|
Updates to Preview Branch (eng-1311-unify-conceptaccess-and-contentaccess-tables) ↗︎
Tasks are run on every commit but only new migration files are pushed.
View logs for this Workflow Run ↗︎. |
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
📝 WalkthroughWalkthroughThis pull request consolidates access control between Content and Concept entities by removing the ConceptAccess table, restructuring ContentAccess to use space_id and source_local_id identifiers instead of content_id, introducing trigger-based lifecycle management, and creating new views with updated security policies. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Content as Content Table
participant Trigger as Delete Trigger
participant CheckRef as is_last_local_reference()
participant ContentAcc as ContentAccess Table
Client->>Content: DELETE Content (space_id, source_local_id)
Content-->>Trigger: AFTER DELETE event
Trigger->>CheckRef: is_last_local_reference(space_id, source_local_id)
CheckRef-->>Trigger: true (no more refs in Content/Concept/Document)
Trigger->>ContentAcc: DELETE WHERE space_id & source_local_id match
ContentAcc-->>Client: Access records cleaned up
sequenceDiagram
participant Client
participant Content as Content Table
participant Trigger as Update Trigger
participant ContentAcc as ContentAccess Table
Client->>Content: UPDATE Content (source_local_id or space_id)
Content-->>Trigger: AFTER UPDATE event
Trigger->>ContentAcc: DELETE old (space_id, source_local_id) references
ContentAcc-->>Trigger: Old access records removed
Trigger-->>Client: Local reference update propagated
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/database/supabase/schemas/content.sql (1)
648-680: Document access via ContentAccess won’t surface inmy_documentsview.Line 650 now allows document access via
can_view_specific_content, butpublic.my_documentsstill filters only onmy_space_ids(). This means users granted local-reference access (anddocument_of_contentlookups) won’t see documents unless they’re space members. Consider aligning the view predicate with the new policy.Based on learnings, the `my_*` views are the performance-critical path and should stay consistent with RLS behavior.♻️ Suggested view alignment (outside this range)
-FROM public."Document" WHERE space_id = any(public.my_space_ids()); +FROM public."Document" +WHERE ( + space_id = any(public.my_space_ids()) + OR public.can_view_specific_content(space_id, source_local_id) +);
🤖 Fix all issues with AI agents
In
`@packages/database/supabase/migrations/20260117210851_unify_concept_content_access_tables.sql`:
- Around line 159-171: The trigger function on_delete_space_revoke_local_access
uses a non-existent column OLD.space_id causing failures on Space deletes;
update the DELETE statement in function on_delete_space_revoke_local_access to
use OLD.id (i.e., DELETE FROM public."ContentAccess" WHERE space_id = OLD.id) so
it correctly revokes ContentAccess rows for the deleted Space; no change needed
to the trigger declaration on_delete_space_revoke_access_trigger beyond this
fix.
- Around line 140-158: The trigger function on_update_local_reference uses
NULL-unsafe comparisons (OLD.space_id != NEW.space_id / OLD.source_local_id !=
NEW.source_local_id) so updates that set fields to NULL can yield NULL and skip
cleanup; change the conditional to use NULL-safe IS DISTINCT FROM (e.g. IF
(OLD.space_id IS DISTINCT FROM NEW.space_id OR OLD.source_local_id IS DISTINCT
FROM NEW.source_local_id) AND public.is_last_local_reference(OLD.space_id,
OLD.source_local_id) THEN ...) so the function reliably detects changes
including to/from NULL and still calls public.is_last_local_reference with the
OLD values before deleting from public."ContentAccess"; update the
on_update_local_reference function accordingly and keep the three CREATE TRIGGER
lines unchanged.
- Line 1: Before dropping the ConceptAccess table, migrate its grants into the
unified ContentAccess scheme by inserting rows into public."ContentAccess" using
ca.account_uid joined with public."Concept" c to obtain c.space_id and
c.source_local_id (only when source_local_id IS NOT NULL), and use ON CONFLICT
DO NOTHING to avoid duplicates; then drop public."ConceptAccess" CASCADE.
Reference the ConceptAccess rows as ca and join to Concept (c) on c.id =
ca.concept_id, mapping to ContentAccess(account_uid, space_id, source_local_id).
- Around line 9-21: Before adding the new primary key "ContentAccess_pkey" on
public."ContentAccess" (account_uid, source_local_id, space_id), deduplicate
existing rows that will collapse when you replace content_id with (space_id,
source_local_id): detect duplicates on (account_uid, space_id, source_local_id)
and remove all but one row per tuple in public."ContentAccess" (for example by
keeping the latest/first by ctid or timestamp), then proceed with the UPDATE
from public."Content" and drop content_id and add the NOT NULL constraints and
primary key; ensure the duplicate-check query and the dedupe DELETE target
public."ContentAccess" so the PK creation will not fail.
In `@packages/database/supabase/schemas/concept.sql`:
- Around line 471-483: The trigger function on_delete_space_revoke_local_access
is referencing a non-existent OLD.space_id on deletes from public."Space";
update the function to use OLD.id (the Space primary key) when deleting rows
from public."ContentAccess" (i.e., DELETE FROM public."ContentAccess" WHERE
space_id = OLD.id) so the delete succeeds; keep the function name
on_delete_space_revoke_local_access and the trigger
on_delete_space_revoke_access_trigger unchanged.
- Around line 452-469: The trigger function on_update_local_reference uses
NULL-unsafe comparisons (OLD.space_id != NEW.space_id and OLD.source_local_id !=
NEW.source_local_id) so updates that set those fields to NULL can yield NULL and
skip cleanup; change those comparisons to NULL-safe "IS DISTINCT FROM" (e.g., IF
(OLD.space_id IS DISTINCT FROM NEW.space_id OR OLD.source_local_id IS DISTINCT
FROM NEW.source_local_id) AND public.is_last_local_reference(OLD.space_id,
OLD.source_local_id) THEN ...) so the delete of public."ContentAccess" runs
correctly when values change to/from NULL; keep the rest of the function and
triggers (on_update_content_trigger, on_update_concept_trigger,
on_update_document_trigger) unchanged.
| @@ -0,0 +1,171 @@ | |||
| DROP TABLE public."ConceptAccess" CASCADE; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat packages/database/supabase/migrations/20260117210851_unify_concept_content_access_tables.sqlRepository: DiscourseGraphs/discourse-graph
Length of output: 7321
🏁 Script executed:
# Search for ConceptAccess references in SQL files and other parts of codebase
rg "ConceptAccess" --type sql -iRepository: DiscourseGraphs/discourse-graph
Length of output: 5007
Migrate ConceptAccess grants before dropping the table.
The migration drops ConceptAccess without transferring its data to the unified ContentAccess system. Concept grants must be migrated using the new (account_uid, space_id, source_local_id) keys by joining the Concept table, similar to how ContentAccess data is being updated from the Content table.
Suggested migration
-- Migrate concept access to the unified content access table
INSERT INTO public."ContentAccess"(account_uid, space_id, source_local_id)
SELECT ca.account_uid, c.space_id, c.source_local_id
FROM public."ConceptAccess" ca
JOIN public."Concept" c ON c.id = ca.concept_id
WHERE c.source_local_id IS NOT NULL
ON CONFLICT DO NOTHING;
DROP TABLE public."ConceptAccess" CASCADE;🤖 Prompt for AI Agents
In
`@packages/database/supabase/migrations/20260117210851_unify_concept_content_access_tables.sql`
at line 1, Before dropping the ConceptAccess table, migrate its grants into the
unified ContentAccess scheme by inserting rows into public."ContentAccess" using
ca.account_uid joined with public."Concept" c to obtain c.space_id and
c.source_local_id (only when source_local_id IS NOT NULL), and use ON CONFLICT
DO NOTHING to avoid duplicates; then drop public."ConceptAccess" CASCADE.
Reference the ConceptAccess rows as ca and join to Concept (c) on c.id =
ca.concept_id, mapping to ContentAccess(account_uid, space_id, source_local_id).
| UPDATE public."ContentAccess" AS ca | ||
| SET space_id = ct.space_id, source_local_id = ct.source_local_id | ||
| FROM public."Content" AS ct WHERE ct.id = content_id; | ||
|
|
||
| ALTER TABLE public."ContentAccess" DROP COLUMN content_id CASCADE; | ||
| -- cascades to Content policies, indices, primary key... | ||
|
|
||
| ALTER TABLE public."ContentAccess" ALTER COLUMN space_id SET NOT NULL; | ||
| ALTER TABLE public."ContentAccess" ALTER COLUMN source_local_id SET NOT NULL; | ||
|
|
||
| ALTER TABLE ONLY public."ContentAccess" | ||
| ADD CONSTRAINT "ContentAccess_pkey" PRIMARY KEY (account_uid, source_local_id, space_id); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
find . -name "20260117210851_unify_concept_content_access_tables.sql" -type fRepository: DiscourseGraphs/discourse-graph
Length of output: 169
🏁 Script executed:
cat -n ./packages/database/supabase/migrations/20260117210851_unify_concept_content_access_tables.sqlRepository: DiscourseGraphs/discourse-graph
Length of output: 8518
🏁 Script executed:
find ./packages/database -name "*.sql" -type f | head -20Repository: DiscourseGraphs/discourse-graph
Length of output: 1624
🏁 Script executed:
cat -n ./packages/database/supabase/migrations/20250504202930_content_tables.sqlRepository: DiscourseGraphs/discourse-graph
Length of output: 11119
🏁 Script executed:
cat -n ./packages/database/supabase/migrations/20250610201801_create_access_table.sqlRepository: DiscourseGraphs/discourse-graph
Length of output: 2846
🏁 Script executed:
rg "CREATE TABLE.*ContentAccess" --type sqlRepository: DiscourseGraphs/discourse-graph
Length of output: 316
🏁 Script executed:
cat -n ./packages/database/supabase/migrations/20260102140646_content_and_concept_access_tables.sqlRepository: DiscourseGraphs/discourse-graph
Length of output: 10855
🏁 Script executed:
rg "variant" ./packages/database/supabase/migrations/ -t sqlRepository: DiscourseGraphs/discourse-graph
Length of output: 1775
🏁 Script executed:
cat -n ./packages/database/supabase/migrations/20250718131540_content_variant.sql | head -20Repository: DiscourseGraphs/discourse-graph
Length of output: 951
🏁 Script executed:
cat -n ./packages/database/supabase/migrations/20260117210851_unify_concept_content_access_tables.sql | sed -n '1,30p'Repository: DiscourseGraphs/discourse-graph
Length of output: 1640
Deduplicate before adding the new ContentAccess PK.
The Content table has a unique constraint on (space_id, source_local_id, variant), allowing multiple content rows with the same (space_id, source_local_id) but different variants. Mapping content_id → (space_id, source_local_id) can collapse multiple access records into duplicate (account_uid, source_local_id, space_id) tuples, causing the primary key constraint at line 20 to fail. Add deduplication before altering the primary key:
Deduplication queries
-- Verify duplicates exist
SELECT account_uid, space_id, source_local_id, count(*) AS dupes
FROM public."ContentAccess"
GROUP BY 1,2,3
HAVING count(*) > 1;
-- Cleanup: keep one row per (account_uid, space_id, source_local_id)
DELETE FROM public."ContentAccess" a
USING public."ContentAccess" b
WHERE a.ctid < b.ctid
AND a.account_uid = b.account_uid
AND a.space_id = b.space_id
AND a.source_local_id = b.source_local_id;🤖 Prompt for AI Agents
In
`@packages/database/supabase/migrations/20260117210851_unify_concept_content_access_tables.sql`
around lines 9 - 21, Before adding the new primary key "ContentAccess_pkey" on
public."ContentAccess" (account_uid, source_local_id, space_id), deduplicate
existing rows that will collapse when you replace content_id with (space_id,
source_local_id): detect duplicates on (account_uid, space_id, source_local_id)
and remove all but one row per tuple in public."ContentAccess" (for example by
keeping the latest/first by ctid or timestamp), then proceed with the UPDATE
from public."Content" and drop content_id and add the NOT NULL constraints and
primary key; ensure the duplicate-check query and the dedupe DELETE target
public."ContentAccess" so the PK creation will not fail.
| CREATE OR REPLACE FUNCTION on_update_local_reference() RETURNS TRIGGER | ||
| STABLE | ||
| SET search_path = '' | ||
| SECURITY DEFINER | ||
| LANGUAGE plpgsql | ||
| AS $$ | ||
| BEGIN | ||
| IF (OLD.space_id != NEW.space_id OR OLD.source_local_id != NEW.source_local_id) | ||
| AND public.is_last_local_reference(OLD.space_id, OLD.source_local_id) THEN | ||
| DELETE FROM public."ContentAccess" WHERE space_id=OLD.space_id AND source_local_id=OLD.source_local_id; | ||
| END IF; | ||
| RETURN NEW; | ||
| END; | ||
| $$; | ||
|
|
||
| CREATE TRIGGER on_update_content_trigger AFTER UPDATE ON public."Content" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); | ||
| CREATE TRIGGER on_update_concept_trigger AFTER UPDATE ON public."Concept" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); | ||
| CREATE TRIGGER on_update_document_trigger AFTER UPDATE ON public."Document" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use NULL-safe comparisons in on_update_local_reference.
Same issue as in schema: != yields NULL with NULLs, so updates that clear fields won’t clean stale access rows.
🐛 Proposed fix
- IF (OLD.space_id != NEW.space_id OR OLD.source_local_id != NEW.source_local_id)
+ IF (OLD.space_id IS DISTINCT FROM NEW.space_id
+ OR OLD.source_local_id IS DISTINCT FROM NEW.source_local_id)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| CREATE OR REPLACE FUNCTION on_update_local_reference() RETURNS TRIGGER | |
| STABLE | |
| SET search_path = '' | |
| SECURITY DEFINER | |
| LANGUAGE plpgsql | |
| AS $$ | |
| BEGIN | |
| IF (OLD.space_id != NEW.space_id OR OLD.source_local_id != NEW.source_local_id) | |
| AND public.is_last_local_reference(OLD.space_id, OLD.source_local_id) THEN | |
| DELETE FROM public."ContentAccess" WHERE space_id=OLD.space_id AND source_local_id=OLD.source_local_id; | |
| END IF; | |
| RETURN NEW; | |
| END; | |
| $$; | |
| CREATE TRIGGER on_update_content_trigger AFTER UPDATE ON public."Content" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); | |
| CREATE TRIGGER on_update_concept_trigger AFTER UPDATE ON public."Concept" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); | |
| CREATE TRIGGER on_update_document_trigger AFTER UPDATE ON public."Document" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); | |
| CREATE OR REPLACE FUNCTION on_update_local_reference() RETURNS TRIGGER | |
| STABLE | |
| SET search_path = '' | |
| SECURITY DEFINER | |
| LANGUAGE plpgsql | |
| AS $$ | |
| BEGIN | |
| IF (OLD.space_id IS DISTINCT FROM NEW.space_id | |
| OR OLD.source_local_id IS DISTINCT FROM NEW.source_local_id) | |
| AND public.is_last_local_reference(OLD.space_id, OLD.source_local_id) THEN | |
| DELETE FROM public."ContentAccess" WHERE space_id=OLD.space_id AND source_local_id=OLD.source_local_id; | |
| END IF; | |
| RETURN NEW; | |
| END; | |
| $$; | |
| CREATE TRIGGER on_update_content_trigger AFTER UPDATE ON public."Content" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); | |
| CREATE TRIGGER on_update_concept_trigger AFTER UPDATE ON public."Concept" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); | |
| CREATE TRIGGER on_update_document_trigger AFTER UPDATE ON public."Document" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); |
🤖 Prompt for AI Agents
In
`@packages/database/supabase/migrations/20260117210851_unify_concept_content_access_tables.sql`
around lines 140 - 158, The trigger function on_update_local_reference uses
NULL-unsafe comparisons (OLD.space_id != NEW.space_id / OLD.source_local_id !=
NEW.source_local_id) so updates that set fields to NULL can yield NULL and skip
cleanup; change the conditional to use NULL-safe IS DISTINCT FROM (e.g. IF
(OLD.space_id IS DISTINCT FROM NEW.space_id OR OLD.source_local_id IS DISTINCT
FROM NEW.source_local_id) AND public.is_last_local_reference(OLD.space_id,
OLD.source_local_id) THEN ...) so the function reliably detects changes
including to/from NULL and still calls public.is_last_local_reference with the
OLD values before deleting from public."ContentAccess"; update the
on_update_local_reference function accordingly and keep the three CREATE TRIGGER
lines unchanged.
| CREATE OR REPLACE FUNCTION on_delete_space_revoke_local_access() RETURNS TRIGGER | ||
| STABLE | ||
| SET search_path = '' | ||
| SECURITY DEFINER | ||
| LANGUAGE plpgsql | ||
| AS $$ | ||
| BEGIN | ||
| DELETE FROM public."ContentAccess" WHERE space_id=OLD.space_id; | ||
| RETURN OLD; | ||
| END; | ||
| $$; | ||
|
|
||
| CREATE TRIGGER on_delete_space_revoke_access_trigger AFTER DELETE ON public."Space" FOR EACH ROW EXECUTE FUNCTION public.on_delete_space_revoke_local_access(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space-delete trigger references a non-existent field.
Line 166 should use OLD.id, not OLD.space_id, or the trigger will error on deletes.
🐛 Proposed fix
- DELETE FROM public."ContentAccess" WHERE space_id=OLD.space_id;
+ DELETE FROM public."ContentAccess" WHERE space_id=OLD.id;🤖 Prompt for AI Agents
In
`@packages/database/supabase/migrations/20260117210851_unify_concept_content_access_tables.sql`
around lines 159 - 171, The trigger function on_delete_space_revoke_local_access
uses a non-existent column OLD.space_id causing failures on Space deletes;
update the DELETE statement in function on_delete_space_revoke_local_access to
use OLD.id (i.e., DELETE FROM public."ContentAccess" WHERE space_id = OLD.id) so
it correctly revokes ContentAccess rows for the deleted Space; no change needed
to the trigger declaration on_delete_space_revoke_access_trigger beyond this
fix.
| CREATE OR REPLACE FUNCTION on_update_local_reference() RETURNS TRIGGER | ||
| STABLE | ||
| SET search_path = '' | ||
| SECURITY DEFINER | ||
| LANGUAGE plpgsql | ||
| AS $$ | ||
| BEGIN | ||
| IF (OLD.space_id != NEW.space_id OR OLD.source_local_id != NEW.source_local_id) | ||
| AND public.is_last_local_reference(OLD.space_id, OLD.source_local_id) THEN | ||
| DELETE FROM public."ContentAccess" WHERE space_id=OLD.space_id AND source_local_id=OLD.source_local_id; | ||
| END IF; | ||
| RETURN NEW; | ||
| END; | ||
| $$; | ||
|
|
||
| CREATE TRIGGER on_update_content_trigger AFTER UPDATE ON public."Content" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); | ||
| CREATE TRIGGER on_update_concept_trigger AFTER UPDATE ON public."Concept" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); | ||
| CREATE TRIGGER on_update_document_trigger AFTER UPDATE ON public."Document" FOR EACH ROW EXECUTE FUNCTION public.on_update_local_reference(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use NULL-safe comparisons when deciding cleanup on update.
!= returns NULL if either side is NULL, so updates that clear source_local_id/space_id won’t delete stale ContentAccess rows. Prefer IS DISTINCT FROM.
🐛 Proposed fix
- IF (OLD.space_id != NEW.space_id OR OLD.source_local_id != NEW.source_local_id)
+ IF (OLD.space_id IS DISTINCT FROM NEW.space_id
+ OR OLD.source_local_id IS DISTINCT FROM NEW.source_local_id)🤖 Prompt for AI Agents
In `@packages/database/supabase/schemas/concept.sql` around lines 452 - 469, The
trigger function on_update_local_reference uses NULL-unsafe comparisons
(OLD.space_id != NEW.space_id and OLD.source_local_id != NEW.source_local_id) so
updates that set those fields to NULL can yield NULL and skip cleanup; change
those comparisons to NULL-safe "IS DISTINCT FROM" (e.g., IF (OLD.space_id IS
DISTINCT FROM NEW.space_id OR OLD.source_local_id IS DISTINCT FROM
NEW.source_local_id) AND public.is_last_local_reference(OLD.space_id,
OLD.source_local_id) THEN ...) so the delete of public."ContentAccess" runs
correctly when values change to/from NULL; keep the rest of the function and
triggers (on_update_content_trigger, on_update_concept_trigger,
on_update_document_trigger) unchanged.
| CREATE OR REPLACE FUNCTION on_delete_space_revoke_local_access() RETURNS TRIGGER | ||
| STABLE | ||
| SET search_path = '' | ||
| SECURITY DEFINER | ||
| LANGUAGE plpgsql | ||
| AS $$ | ||
| BEGIN | ||
| DELETE FROM public."ContentAccess" WHERE space_id=OLD.space_id; | ||
| RETURN OLD; | ||
| END; | ||
| $$; | ||
|
|
||
| CREATE TRIGGER on_delete_space_revoke_access_trigger AFTER DELETE ON public."Space" FOR EACH ROW EXECUTE FUNCTION public.on_delete_space_revoke_local_access(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trigger uses a non-existent field on Space deletes.
Line 478 references OLD.space_id, but public."Space" uses id. This will error and block deletes.
🐛 Proposed fix
- DELETE FROM public."ContentAccess" WHERE space_id=OLD.space_id;
+ DELETE FROM public."ContentAccess" WHERE space_id=OLD.id;🤖 Prompt for AI Agents
In `@packages/database/supabase/schemas/concept.sql` around lines 471 - 483, The
trigger function on_delete_space_revoke_local_access is referencing a
non-existent OLD.space_id on deletes from public."Space"; update the function to
use OLD.id (the Space primary key) when deleting rows from
public."ContentAccess" (i.e., DELETE FROM public."ContentAccess" WHERE space_id
= OLD.id) so the delete succeeds; keep the function name
on_delete_space_revoke_local_access and the trigger
on_delete_space_revoke_access_trigger unchanged.
4913e56 to
c306427
Compare
edd277a to
b0c533b
Compare
https://linear.app/discourse-graphs/issue/ENG-1311/unify-conceptaccess-and-contentaccess-tables
Define ContentAccess in term of source_local_id.
It can then be used to gate access to both Content and Concepts.
Note that this is not a foreign key, so delete cascades have to be handled manually.
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.