Skip to content
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ RUN docker-entrypoint.sh postgres & \
&& sqitch --chdir src deploy -t db:pg://ci:postgres@/ci_database \
&& pg_dump -s -h localhost -U ci -p 5432 ci_database | sed -e '/^-- Dumped/d' > schema.sql \
&& psql -h localhost -U ci -d ci_database -q -f ./test/logic/main.sql \
-v TEST_DIRECTORY=./test/logic -v ON_ERROR_STOP=on \
-v TEST_DIRECTORY=./test/logic \
&& sqitch --chdir src revert -t db:pg://ci:postgres@/ci_database

##############################
Expand Down
10 changes: 6 additions & 4 deletions src/deploy/function_event_search.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ BEGIN

RETURN QUERY
SELECT
*
e.*
FROM
vibetype.event
vibetype.event e
JOIN vibetype.event_search_vector esv ON esv.event_id = e.id
WHERE
search_vector @@ websearch_to_tsquery(ts_config, event_search.query)
esv.search_vector @@ websearch_to_tsquery(ts_config, event_search.query)
AND esv.language = event_search.language
ORDER BY
ts_rank_cd(search_vector, websearch_to_tsquery(ts_config, event_search.query)) DESC;
ts_rank_cd(esv.search_vector, websearch_to_tsquery(ts_config, event_search.query)) DESC;
END;
$$ LANGUAGE PLPGSQL STABLE SECURITY INVOKER;

Expand Down
36 changes: 23 additions & 13 deletions src/deploy/table_event.sql
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,10 @@ CREATE TABLE vibetype.event (

created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by UUID NOT NULL REFERENCES vibetype.account(id) ON DELETE CASCADE,
search_vector TSVECTOR,
Comment thread
dargmuesli marked this conversation as resolved.

UNIQUE (created_by, slug)
);

CREATE INDEX idx_event_search_vector ON vibetype.event USING gin (search_vector);

COMMENT ON TABLE vibetype.event IS 'An event.';
COMMENT ON COLUMN vibetype.event.id IS E'@omit create,update\nThe event''s internal id.';
COMMENT ON COLUMN vibetype.event.address_id IS 'Optional reference to the physical address of the event.';
Expand All @@ -42,31 +39,44 @@ COMMENT ON COLUMN vibetype.event.url IS 'The event''s unified resource locator.'
COMMENT ON COLUMN vibetype.event.visibility IS 'The event''s visibility.';
COMMENT ON COLUMN vibetype.event.created_at IS E'@omit create,update\nTimestamp of when the event was created, defaults to the current timestamp.';
COMMENT ON COLUMN vibetype.event.created_by IS 'The event creator''s id.';
COMMENT ON COLUMN vibetype.event.search_vector IS E'@omit\nA vector used for full-text search on events.';
COMMENT ON INDEX vibetype.idx_event_search_vector IS 'GIN index on the search vector to improve full-text search performance.';

CREATE FUNCTION vibetype.trigger_event_search_vector() RETURNS TRIGGER AS $$
DECLARE
rec RECORD;
ts_config regconfig;
_search_vector TSVECTOR;
BEGIN
ts_config := vibetype.language_iso_full_text_search(NEW.language);
FOR rec IN
SELECT unnest as language
FROM unnest(enum_range(NULL::vibetype.language))
LOOP
ts_config := vibetype.language_iso_full_text_search(rec.language);

_search_vector :=
setweight(to_tsvector(ts_config, NEW.name), 'A') ||
setweight(to_tsvector(ts_config, coalesce(NEW.description, '')), 'B');

NEW.search_vector :=
setweight(to_tsvector(ts_config, NEW.name), 'A') ||
setweight(to_tsvector(ts_config, coalesce(NEW.description, '')), 'B');
MERGE INTO vibetype.event_search_vector e
USING (SELECT NEW.id as event_id, rec.language, _search_vector as search_vector) t
ON e.event_id = t.event_id and e.language = t.language
WHEN NOT MATCHED THEN
INSERT (event_id, language, search_vector) VALUES (t.event_id, t.language, t.search_vector)
WHEN MATCHED THEN
UPDATE SET search_vector = t.search_vector;
END LOOP;

RETURN NEW;
END;
$$ LANGUAGE PLPGSQL STRICT SECURITY DEFINER;

COMMENT ON FUNCTION vibetype.trigger_event_search_vector() IS 'Generates a search vector for the event based on the name and description columns, weighted by their relevance and language configuration.';
COMMENT ON FUNCTION vibetype.trigger_event_search_vector() IS 'Creates or updates search vectors for the event based on the name and description columns, weighted by their relevance, and for all supported languages.';

GRANT EXECUTE ON FUNCTION vibetype.trigger_event_search_vector() TO vibetype_account, vibetype_anonymous;

CREATE TRIGGER vibetype_trigger_event_search_vector
BEFORE
INSERT
OR UPDATE OF name, description, language
AFTER
INSERT
OR UPDATE OF name, description
ON vibetype.event
FOR EACH ROW
EXECUTE FUNCTION vibetype.trigger_event_search_vector();
Expand Down
30 changes: 30 additions & 0 deletions src/deploy/table_event_search_vector.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
BEGIN;

CREATE TABLE vibetype.event_search_vector (
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introducing a new table makes the availability of search vectors more flexible which can be a good or bad thing. Right now I'd like to rely on search vectors to be available / not null for all supported languages to prevent confusion when data is missing partly.

id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
event_id UUID REFERENCES vibetype.event(id) ON DELETE SET NULL,
language vibetype.language NOT NULL,
search_vector TSVECTOR,

UNIQUE (event_id, language)
);

COMMENT ON TABLE vibetype.event_search_vector IS E'@omit create,update,delete\nA language-specific search vector for an event.';
COMMENT ON COLUMN vibetype.event_search_vector.id IS 'The records''s internal id.';
COMMENT ON COLUMN vibetype.event_search_vector.event_id IS 'The reference to the event.';
COMMENT ON COLUMN vibetype.event_search_vector.language IS 'The language associated with the search vector.';
COMMENT ON COLUMN vibetype.event_search_vector.search_vector IS 'A vector used for full-text search on events.';

CREATE INDEX idx_event_search_vector ON vibetype.event_search_vector USING gin (search_vector);

COMMENT ON INDEX vibetype.idx_event_search_vector IS 'GIN index on the search vector to improve full-text search performance.';

GRANT SELECT ON TABLE vibetype.event_search_vector TO vibetype_anonymous;
GRANT INSERT, SELECT, UPDATE, DELETE ON TABLE vibetype.event_search_vector TO vibetype_account;

CREATE POLICY event_search_vector_select ON vibetype.event_search_vector FOR SELECT
USING (
event_id IN (SELECT id FROM vibetype_private.event_policy_select())
);

COMMIT;
1 change: 0 additions & 1 deletion src/revert/table_event.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ BEGIN;

DROP TRIGGER vibetype_trigger_event_search_vector ON vibetype.event;
DROP FUNCTION vibetype.trigger_event_search_vector();
DROP INDEX vibetype.idx_event_search_vector;
DROP TABLE vibetype.event;

COMMIT;
6 changes: 6 additions & 0 deletions src/revert/table_event_search_vector.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
BEGIN;

DROP INDEX vibetype.idx_event_search_vector;
DROP TABLE vibetype.event_search_vector;

COMMIT;
1 change: 1 addition & 0 deletions src/sqitch.plan
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,4 @@ function_account_location_update [privilege_execute_revoke schema_public table_a
table_preference_event_location [schema_public table_account_public role_account function_invoker_account_id] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+vibetype/sqitch@jonas-thelemann.de> # Stores preferred event locations for user accounts, including coordinates and search radius.
role_zammad 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Add role zammad.
database_zammad [role_zammad] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Add the database for zammad.
table_event_search_vector [schema_public table_event role_account role_anonymous] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Add table event_search_vector.
3 changes: 1 addition & 2 deletions src/verify/table_event.sql
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ SELECT id,
url,
visibility,
created_at,
created_by,
search_vector
created_by
FROM vibetype.event WHERE FALSE;


Expand Down
30 changes: 30 additions & 0 deletions src/verify/table_event_search_vector.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
BEGIN;

SELECT id,
event_id,
language,
search_vector
FROM vibetype.event_search_vector WHERE FALSE;

\set role_service_vibetype_username `cat /run/secrets/postgres_role_service_vibetype_username`
SET local role.vibetype_username TO :'role_service_vibetype_username';

DO $$
BEGIN
ASSERT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.event_search_vector', 'SELECT'));
ASSERT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.event_search_vector', 'INSERT'));
ASSERT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.event_search_vector', 'UPDATE'));
ASSERT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.event_search_vector', 'DELETE'));
ASSERT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.event_search_vector', 'SELECT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.event_search_vector', 'INSERT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.event_search_vector', 'UPDATE'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.event_search_vector', 'DELETE'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege(current_setting('role.vibetype_username'), 'vibetype.event_search_vector', 'SELECT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege(current_setting('role.vibetype_username'), 'vibetype.event_search_vector', 'INSERT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege(current_setting('role.vibetype_username'), 'vibetype.event_search_vector', 'UPDATE'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege(current_setting('role.vibetype_username'), 'vibetype.event_search_vector', 'DELETE'));
END $$;

ROLLBACK;

ROLLBACK;
Loading
Loading