diff --git a/projects/extension/build.py b/projects/extension/build.py index 96e01e98..a876e412 100755 --- a/projects/extension/build.py +++ b/projects/extension/build.py @@ -26,6 +26,7 @@ - clean-sql removes sql file artifacts from the sql dir - clean-py removes python build artifacts from the extension src dir - test runs the tests in the docker container +- test-update runs the tests in the docker container and updates snapshots - test-server runs the test http server in the docker container - lint-sql runs pgspot against the `ai--.sql` file - lint-py runs ruff linter against the python source files @@ -605,6 +606,16 @@ def test() -> None: subprocess.run("pytest", shell=True, check=True, env=os.environ, cwd=tests_dir()) +def test_update() -> None: + subprocess.run( + "pytest --snapshot-update", + shell=True, + check=True, + env=os.environ, + cwd=tests_dir(), + ) + + def lint_sql() -> None: sql = sql_dir().joinpath(f"ai--{this_version()}.sql") cmd = " ".join( @@ -721,6 +732,8 @@ def run() -> None: test_server() elif action == "test": test() + elif action == "test-update": + test_update() elif action == "lint-sql": lint_sql() elif action == "lint-py": diff --git a/projects/extension/justfile b/projects/extension/justfile index a4cf73ad..22227439 100644 --- a/projects/extension/justfile +++ b/projects/extension/justfile @@ -67,6 +67,9 @@ test-server: test: @./build.py test +test-update: + @./build.py test-update + lint-sql: @./build.py lint-sql diff --git a/projects/extension/requirements-test.txt b/projects/extension/requirements-test.txt index de44c0f1..b873cf2b 100644 --- a/projects/extension/requirements-test.txt +++ b/projects/extension/requirements-test.txt @@ -7,3 +7,4 @@ python-dotenv==1.0.1 fastapi==0.112.0 fastapi-cli==0.0.5 psycopg[binary]==3.2.1 +syrupy==4.7.2 diff --git a/projects/extension/tests/contents/__snapshots__/test_contents.ambr b/projects/extension/tests/contents/__snapshots__/test_contents.ambr new file mode 100644 index 00000000..dbe2511c --- /dev/null +++ b/projects/extension/tests/contents/__snapshots__/test_contents.ambr @@ -0,0 +1,238 @@ +# serializer version: 1 +# name: test_contents + ''' + DROP DATABASE + CREATE DATABASE + You are now connected to database "toc" as user "postgres". + CREATE EXTENSION + Objects in extension "ai" + Object description + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + event trigger _vectorizer_handle_drops + function ai.anthropic_generate(text,jsonb,integer,text,text,text,double precision,integer,text,text,text[],double precision,jsonb,jsonb,integer,double precision) + function ai.chunking_character_text_splitter(name,integer,integer,text,boolean) + function ai.chunking_recursive_character_text_splitter(name,integer,integer,text[],boolean) + function ai.cohere_chat_complete(text,text,text,text,text,jsonb,text,text,jsonb,boolean,jsonb,text,double precision,integer,integer,integer,double precision,integer,text[],double precision,double precision,jsonb,jsonb,boolean) + function ai.cohere_classify_simple(text,text[],text,text,jsonb,text) + function ai.cohere_classify(text,text[],text,text,jsonb,text) + function ai.cohere_detokenize(text,integer[],text,text) + function ai.cohere_embed(text,text,text,text,text,text) + function ai.cohere_list_models(text,text,text,boolean) + function ai.cohere_rerank_simple(text,text,jsonb,text,text,integer,integer) + function ai.cohere_rerank(text,text,jsonb,text,text,integer,text[],boolean,integer) + function ai.cohere_tokenize(text,text,text,text) + function ai.create_vectorizer(regclass,name,jsonb,jsonb,jsonb,jsonb,jsonb,jsonb,name,name,name,name,name,name,name[],boolean) + function ai.disable_vectorizer_schedule(integer) + function ai.drop_vectorizer(integer,boolean) + function ai.embedding_openai(text,integer,text,text) + function ai.enable_vectorizer_schedule(integer) + function ai.execute_vectorizer(integer) + function ai.formatting_python_template(text) + function ai.grant_ai_usage(name,boolean) + function ai.grant_secret(text,text) + function ai.grant_to() + function ai.grant_to(name[]) + function ai.indexing_default() + function ai.indexing_diskann(integer,text,integer,integer,double precision,integer,integer,boolean) + function ai.indexing_hnsw(integer,text,integer,integer,boolean) + function ai.indexing_none() + function ai.ollama_chat_complete(text,jsonb,text,double precision,jsonb) + function ai.ollama_embed(text,text,text,double precision,jsonb) + function ai.ollama_generate(text,text,text,bytea[],double precision,jsonb,text,text,integer[]) + function ai.ollama_list_models(text) + function ai.ollama_ps(text) + function ai.openai_chat_complete_simple(text,text,text) + function ai.openai_chat_complete(text,jsonb,text,text,text,double precision,jsonb,boolean,integer,integer,integer,double precision,jsonb,integer,text,double precision,double precision,jsonb,jsonb,text) + function ai.openai_detokenize(text,integer[]) + function ai.openai_embed(text,integer[],text,text,text,integer,text) + function ai.openai_embed(text,text,text,text,text,integer,text) + function ai.openai_embed(text,text[],text,text,text,integer,text) + function ai.openai_list_models(text,text,text) + function ai.openai_moderate(text,text,text,text,text) + function ai.openai_tokenize(text,text) + function ai.processing_default(integer,integer) + function ai._resolve_indexing_default() + function ai._resolve_scheduling_default() + function ai.reveal_secret(text,boolean) + function ai.revoke_secret(text,text) + function ai.scheduling_default() + function ai.scheduling_none() + function ai.scheduling_timescaledb(interval,timestamp with time zone,boolean,text) + function ai._validate_chunking(jsonb,name,name) + function ai._validate_embedding(jsonb) + function ai._validate_formatting(jsonb,name,name) + function ai._validate_formatting_python_template(jsonb,name,name) + function ai._validate_indexing_diskann(jsonb) + function ai._validate_indexing_hnsw(jsonb) + function ai._validate_indexing(jsonb) + function ai._validate_processing(jsonb) + function ai._validate_scheduling(jsonb) + function ai._vectorizer_create_queue_table(name,name,jsonb,name[]) + function ai._vectorizer_create_source_trigger(name,name,name,name,name,jsonb) + function ai._vectorizer_create_target_table(name,name,jsonb,name,name,integer,name[]) + function ai._vectorizer_create_vector_index(name,name,jsonb) + function ai._vectorizer_create_view(name,name,name,name,jsonb,name,name,name[]) + function ai._vectorizer_grant_to_source(name,name,name[]) + function ai._vectorizer_grant_to_vectorizer(name[]) + function ai._vectorizer_handle_drops() + function ai._vectorizer_job(integer,jsonb) + function ai.vectorizer_queue_pending(integer,boolean) + function ai._vectorizer_schedule_job(integer,jsonb) + function ai._vectorizer_should_create_vector_index(ai.vectorizer) + function ai._vectorizer_source_pk(regclass) + function ai._vectorizer_vector_index_exists(name,name,jsonb) + sequence ai.vectorizer_id_seq + table ai.feature_flag + table ai.migration + table ai._secret_permissions + table ai.vectorizer + table ai.vectorizer_errors + view ai.secret_permissions + view ai.vectorizer_status + (81 rows) + + Table "ai._secret_permissions" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description + --------+------+-----------+----------+---------+----------+-------------+--------------+------------- + name | text | | not null | | extended | | | + role | text | | not null | | extended | | | + Indexes: + "_secret_permissions_pkey" PRIMARY KEY, btree (name, role) + Check constraints: + "_secret_permissions_name_check" CHECK (name = '*'::text OR name ~ '^[A-Za-z0-9_.]+$'::text) + Access method: heap + + Index "ai._secret_permissions_pkey" + Column | Type | Key? | Definition | Storage | Stats target + --------+------+------+------------+----------+-------------- + name | text | yes | name | extended | + role | text | yes | role | extended | + primary key, btree, for table "ai._secret_permissions" + + Table "ai.feature_flag" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description + --------------------+--------------------------+-----------+----------+-------------------+----------+-------------+--------------+------------- + name | text | | not null | | extended | | | + applied_at_version | text | | not null | | extended | | | + applied_at | timestamp with time zone | | not null | clock_timestamp() | plain | | | + Indexes: + "feature_flag_pkey" PRIMARY KEY, btree (name) + Access method: heap + + Index "ai.feature_flag_pkey" + Column | Type | Key? | Definition | Storage | Stats target + --------+------+------+------------+----------+-------------- + name | text | yes | name | extended | + primary key, btree, for table "ai.feature_flag" + + Table "ai.migration" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description + --------------------+--------------------------+-----------+----------+-------------------+----------+-------------+--------------+------------- + name | text | | not null | | extended | | | + applied_at_version | text | | not null | | extended | | | + applied_at | timestamp with time zone | | not null | clock_timestamp() | plain | | | + body | text | | not null | | extended | | | + Indexes: + "migration_pkey" PRIMARY KEY, btree (name) + Access method: heap + + Index "ai.migration_pkey" + Column | Type | Key? | Definition | Storage | Stats target + --------+------+------+------------+----------+-------------- + name | text | yes | name | extended | + primary key, btree, for table "ai.migration" + + View "ai.secret_permissions" + Column | Type | Collation | Nullable | Default | Storage | Description + --------+------+-----------+----------+---------+----------+------------- + name | text | | | | extended | + role | text | | | | extended | + View definition: + SELECT name, + role + FROM ai._secret_permissions + WHERE to_regrole(role) IS NOT NULL AND pg_has_role(CURRENT_USER, role::name, 'member'::text); + + Table "ai.vectorizer" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description + ---------------+---------+-----------+----------+----------------------------------+----------+-------------+--------------+------------- + id | integer | | not null | generated by default as identity | plain | | | + source_schema | name | | not null | | plain | | | + source_table | name | | not null | | plain | | | + source_pk | jsonb | | not null | | extended | | | + target_schema | name | | not null | | plain | | | + target_table | name | | not null | | plain | | | + view_schema | name | | not null | | plain | | | + view_name | name | | not null | | plain | | | + trigger_name | name | | not null | | plain | | | + queue_schema | name | | | | plain | | | + queue_table | name | | | | plain | | | + config | jsonb | | not null | | extended | | | + Indexes: + "vectorizer_pkey" PRIMARY KEY, btree (id) + "vectorizer_target_schema_target_table_key" UNIQUE CONSTRAINT, btree (target_schema, target_table) + Referenced by: + TABLE "ai.vectorizer_errors" CONSTRAINT "vectorizer_errors_id_fkey" FOREIGN KEY (id) REFERENCES ai.vectorizer(id) ON DELETE CASCADE + Access method: heap + + Table "ai.vectorizer_errors" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description + ----------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- + id | integer | | not null | | plain | | | + message | text | | | | extended | | | + details | jsonb | | | | extended | | | + recorded | timestamp with time zone | | not null | now() | plain | | | + Indexes: + "vectorizer_errors_id_recorded_idx" btree (id, recorded) + Foreign-key constraints: + "vectorizer_errors_id_fkey" FOREIGN KEY (id) REFERENCES ai.vectorizer(id) ON DELETE CASCADE + Access method: heap + + Index "ai.vectorizer_errors_id_recorded_idx" + Column | Type | Key? | Definition | Storage | Stats target + ----------+--------------------------+------+------------+---------+-------------- + id | integer | yes | id | plain | + recorded | timestamp with time zone | yes | recorded | plain | + btree, for table "ai.vectorizer_errors" + + Sequence "ai.vectorizer_id_seq" + Type | Start | Minimum | Maximum | Increment | Cycles? | Cache + ---------+-------+---------+------------+-----------+---------+------- + integer | 1 | 1 | 2147483647 | 1 | no | 1 + Sequence for identity column: ai.vectorizer.id + + Index "ai.vectorizer_pkey" + Column | Type | Key? | Definition | Storage | Stats target + --------+---------+------+------------+---------+-------------- + id | integer | yes | id | plain | + primary key, btree, for table "ai.vectorizer" + + View "ai.vectorizer_status" + Column | Type | Collation | Nullable | Default | Storage | Description + ---------------+---------+-----------+----------+---------+----------+------------- + id | integer | | | | plain | + source_table | text | C | | | extended | + target_table | text | C | | | extended | + view | text | C | | | extended | + pending_items | bigint | | | | plain | + View definition: + SELECT id, + format('%I.%I'::text, source_schema, source_table) AS source_table, + format('%I.%I'::text, target_schema, target_table) AS target_table, + format('%I.%I'::text, view_schema, view_name) AS view, + CASE + WHEN queue_table IS NOT NULL AND has_table_privilege(CURRENT_USER, format('%I.%I'::text, queue_schema, queue_table), 'select'::text) THEN ai.vectorizer_queue_pending(id) + ELSE NULL::bigint + END AS pending_items + FROM ai.vectorizer v; + + Index "ai.vectorizer_target_schema_target_table_key" + Column | Type | Key? | Definition | Storage | Stats target + ---------------+---------+------+---------------+---------+-------------- + target_schema | cstring | yes | target_schema | plain | + target_table | cstring | yes | target_table | plain | + unique, btree, for table "ai.vectorizer" + + + ''' +# --- diff --git a/projects/extension/tests/contents/output.expected b/projects/extension/tests/contents/output.expected deleted file mode 100644 index 90a7d780..00000000 --- a/projects/extension/tests/contents/output.expected +++ /dev/null @@ -1,231 +0,0 @@ -DROP DATABASE -CREATE DATABASE -CREATE EXTENSION - Objects in extension "ai" - Object description ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - event trigger _vectorizer_handle_drops - function ai.anthropic_generate(text,jsonb,integer,text,text,text,double precision,integer,text,text,text[],double precision,jsonb,jsonb,integer,double precision) - function ai.chunking_character_text_splitter(name,integer,integer,text,boolean) - function ai.chunking_recursive_character_text_splitter(name,integer,integer,text[],boolean) - function ai.cohere_chat_complete(text,text,text,text,text,jsonb,text,text,jsonb,boolean,jsonb,text,double precision,integer,integer,integer,double precision,integer,text[],double precision,double precision,jsonb,jsonb,boolean) - function ai.cohere_classify_simple(text,text[],text,text,jsonb,text) - function ai.cohere_classify(text,text[],text,text,jsonb,text) - function ai.cohere_detokenize(text,integer[],text,text) - function ai.cohere_embed(text,text,text,text,text,text) - function ai.cohere_list_models(text,text,text,boolean) - function ai.cohere_rerank_simple(text,text,jsonb,text,text,integer,integer) - function ai.cohere_rerank(text,text,jsonb,text,text,integer,text[],boolean,integer) - function ai.cohere_tokenize(text,text,text,text) - function ai.create_vectorizer(regclass,name,jsonb,jsonb,jsonb,jsonb,jsonb,jsonb,name,name,name,name,name,name,name[],boolean) - function ai.disable_vectorizer_schedule(integer) - function ai.drop_vectorizer(integer,boolean) - function ai.embedding_openai(text,integer,text,text) - function ai.enable_vectorizer_schedule(integer) - function ai.execute_vectorizer(integer) - function ai.formatting_python_template(text) - function ai.grant_ai_usage(name,boolean) - function ai.grant_secret(text,text) - function ai.grant_to() - function ai.grant_to(name[]) - function ai.indexing_default() - function ai.indexing_diskann(integer,text,integer,integer,double precision,integer,integer,boolean) - function ai.indexing_hnsw(integer,text,integer,integer,boolean) - function ai.indexing_none() - function ai.ollama_chat_complete(text,jsonb,text,double precision,jsonb) - function ai.ollama_embed(text,text,text,double precision,jsonb) - function ai.ollama_generate(text,text,text,bytea[],double precision,jsonb,text,text,integer[]) - function ai.ollama_list_models(text) - function ai.ollama_ps(text) - function ai.openai_chat_complete_simple(text,text,text) - function ai.openai_chat_complete(text,jsonb,text,text,text,double precision,jsonb,boolean,integer,integer,integer,double precision,jsonb,integer,text,double precision,double precision,jsonb,jsonb,text) - function ai.openai_detokenize(text,integer[]) - function ai.openai_embed(text,integer[],text,text,text,integer,text) - function ai.openai_embed(text,text,text,text,text,integer,text) - function ai.openai_embed(text,text[],text,text,text,integer,text) - function ai.openai_list_models(text,text,text) - function ai.openai_moderate(text,text,text,text,text) - function ai.openai_tokenize(text,text) - function ai.processing_default(integer,integer) - function ai._resolve_indexing_default() - function ai._resolve_scheduling_default() - function ai.reveal_secret(text,boolean) - function ai.revoke_secret(text,text) - function ai.scheduling_default() - function ai.scheduling_none() - function ai.scheduling_timescaledb(interval,timestamp with time zone,boolean,text) - function ai._validate_chunking(jsonb,name,name) - function ai._validate_embedding(jsonb) - function ai._validate_formatting(jsonb,name,name) - function ai._validate_formatting_python_template(jsonb,name,name) - function ai._validate_indexing_diskann(jsonb) - function ai._validate_indexing_hnsw(jsonb) - function ai._validate_indexing(jsonb) - function ai._validate_processing(jsonb) - function ai._validate_scheduling(jsonb) - function ai._vectorizer_create_queue_table(name,name,jsonb,name[]) - function ai._vectorizer_create_source_trigger(name,name,name,name,name,jsonb) - function ai._vectorizer_create_target_table(name,name,jsonb,name,name,integer,name[]) - function ai._vectorizer_create_vector_index(name,name,jsonb) - function ai._vectorizer_create_view(name,name,name,name,jsonb,name,name,name[]) - function ai._vectorizer_grant_to_source(name,name,name[]) - function ai._vectorizer_grant_to_vectorizer(name[]) - function ai._vectorizer_handle_drops() - function ai._vectorizer_job(integer,jsonb) - function ai.vectorizer_queue_pending(integer,boolean) - function ai._vectorizer_schedule_job(integer,jsonb) - function ai._vectorizer_should_create_vector_index(ai.vectorizer) - function ai._vectorizer_source_pk(regclass) - function ai._vectorizer_vector_index_exists(name,name,jsonb) - sequence ai.vectorizer_id_seq - table ai.feature_flag - table ai.migration - table ai._secret_permissions - table ai.vectorizer - table ai.vectorizer_errors - view ai.secret_permissions - view ai.vectorizer_status -(81 rows) - - Table "ai._secret_permissions" - Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description ---------+------+-----------+----------+---------+----------+-------------+--------------+------------- - name | text | | not null | | extended | | | - role | text | | not null | | extended | | | -Indexes: - "_secret_permissions_pkey" PRIMARY KEY, btree (name, role) -Check constraints: - "_secret_permissions_name_check" CHECK (name = '*'::text OR name ~ '^[A-Za-z0-9_.]+$'::text) -Access method: heap - - Index "ai._secret_permissions_pkey" - Column | Type | Key? | Definition | Storage | Stats target ---------+------+------+------------+----------+-------------- - name | text | yes | name | extended | - role | text | yes | role | extended | -primary key, btree, for table "ai._secret_permissions" - - Table "ai.feature_flag" - Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description ---------------------+--------------------------+-----------+----------+-------------------+----------+-------------+--------------+------------- - name | text | | not null | | extended | | | - applied_at_version | text | | not null | | extended | | | - applied_at | timestamp with time zone | | not null | clock_timestamp() | plain | | | -Indexes: - "feature_flag_pkey" PRIMARY KEY, btree (name) -Access method: heap - - Index "ai.feature_flag_pkey" - Column | Type | Key? | Definition | Storage | Stats target ---------+------+------+------------+----------+-------------- - name | text | yes | name | extended | -primary key, btree, for table "ai.feature_flag" - - Table "ai.migration" - Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description ---------------------+--------------------------+-----------+----------+-------------------+----------+-------------+--------------+------------- - name | text | | not null | | extended | | | - applied_at_version | text | | not null | | extended | | | - applied_at | timestamp with time zone | | not null | clock_timestamp() | plain | | | - body | text | | not null | | extended | | | -Indexes: - "migration_pkey" PRIMARY KEY, btree (name) -Access method: heap - - Index "ai.migration_pkey" - Column | Type | Key? | Definition | Storage | Stats target ---------+------+------+------------+----------+-------------- - name | text | yes | name | extended | -primary key, btree, for table "ai.migration" - - View "ai.secret_permissions" - Column | Type | Collation | Nullable | Default | Storage | Description ---------+------+-----------+----------+---------+----------+------------- - name | text | | | | extended | - role | text | | | | extended | -View definition: - SELECT name, - role - FROM ai._secret_permissions - WHERE to_regrole(role) IS NOT NULL AND pg_has_role(CURRENT_USER, role::name, 'member'::text); - - Table "ai.vectorizer" - Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description ----------------+---------+-----------+----------+----------------------------------+----------+-------------+--------------+------------- - id | integer | | not null | generated by default as identity | plain | | | - source_schema | name | | not null | | plain | | | - source_table | name | | not null | | plain | | | - source_pk | jsonb | | not null | | extended | | | - target_schema | name | | not null | | plain | | | - target_table | name | | not null | | plain | | | - view_schema | name | | not null | | plain | | | - view_name | name | | not null | | plain | | | - trigger_name | name | | not null | | plain | | | - queue_schema | name | | | | plain | | | - queue_table | name | | | | plain | | | - config | jsonb | | not null | | extended | | | -Indexes: - "vectorizer_pkey" PRIMARY KEY, btree (id) - "vectorizer_target_schema_target_table_key" UNIQUE CONSTRAINT, btree (target_schema, target_table) -Referenced by: - TABLE "ai.vectorizer_errors" CONSTRAINT "vectorizer_errors_id_fkey" FOREIGN KEY (id) REFERENCES ai.vectorizer(id) ON DELETE CASCADE -Access method: heap - - Table "ai.vectorizer_errors" - Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description -----------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- - id | integer | | not null | | plain | | | - message | text | | | | extended | | | - details | jsonb | | | | extended | | | - recorded | timestamp with time zone | | not null | now() | plain | | | -Indexes: - "vectorizer_errors_id_recorded_idx" btree (id, recorded) -Foreign-key constraints: - "vectorizer_errors_id_fkey" FOREIGN KEY (id) REFERENCES ai.vectorizer(id) ON DELETE CASCADE -Access method: heap - - Index "ai.vectorizer_errors_id_recorded_idx" - Column | Type | Key? | Definition | Storage | Stats target -----------+--------------------------+------+------------+---------+-------------- - id | integer | yes | id | plain | - recorded | timestamp with time zone | yes | recorded | plain | -btree, for table "ai.vectorizer_errors" - - Sequence "ai.vectorizer_id_seq" - Type | Start | Minimum | Maximum | Increment | Cycles? | Cache ----------+-------+---------+------------+-----------+---------+------- - integer | 1 | 1 | 2147483647 | 1 | no | 1 -Sequence for identity column: ai.vectorizer.id - - Index "ai.vectorizer_pkey" - Column | Type | Key? | Definition | Storage | Stats target ---------+---------+------+------------+---------+-------------- - id | integer | yes | id | plain | -primary key, btree, for table "ai.vectorizer" - - View "ai.vectorizer_status" - Column | Type | Collation | Nullable | Default | Storage | Description ----------------+---------+-----------+----------+---------+----------+------------- - id | integer | | | | plain | - source_table | text | C | | | extended | - target_table | text | C | | | extended | - view | text | C | | | extended | - pending_items | bigint | | | | plain | -View definition: - SELECT id, - format('%I.%I'::text, source_schema, source_table) AS source_table, - format('%I.%I'::text, target_schema, target_table) AS target_table, - format('%I.%I'::text, view_schema, view_name) AS view, - CASE - WHEN queue_table IS NOT NULL AND has_table_privilege(CURRENT_USER, format('%I.%I'::text, queue_schema, queue_table), 'select'::text) THEN ai.vectorizer_queue_pending(id) - ELSE NULL::bigint - END AS pending_items - FROM ai.vectorizer v; - - Index "ai.vectorizer_target_schema_target_table_key" - Column | Type | Key? | Definition | Storage | Stats target ----------------+---------+------+---------------+---------+-------------- - target_schema | cstring | yes | target_schema | plain | - target_table | cstring | yes | target_table | plain | -unique, btree, for table "ai.vectorizer" - diff --git a/projects/extension/tests/contents/test_contents.py b/projects/extension/tests/contents/test_contents.py index 13dc50dd..f77b0694 100644 --- a/projects/extension/tests/contents/test_contents.py +++ b/projects/extension/tests/contents/test_contents.py @@ -36,17 +36,23 @@ def init() -> None: f'''-d "{db_url("postgres", "postgres")}"''', "-v ON_ERROR_STOP=1", "-X", - f"-o {docker_dir()}/output.actual", f"-f {docker_dir()}/init.sql", ] ) if where_am_i() != "docker": cmd = f"docker exec -w {docker_dir()} pgai-ext {cmd}" - subprocess.run(cmd, check=True, shell=True, env=os.environ, cwd=str(host_dir())) + result = subprocess.run( + cmd, + check=True, + shell=True, + env=os.environ, + cwd=str(host_dir()), + text=True, + capture_output=True, + ) + return result.stdout -def test_contents() -> None: - init() - actual = host_dir().joinpath("output.actual").read_text() - expected = host_dir().joinpath("output.expected").read_text() - assert actual == expected +def test_contents(snapshot) -> None: + output = init() + assert output == snapshot diff --git a/projects/extension/tests/privileges/__snapshots__/test_privileges.ambr b/projects/extension/tests/privileges/__snapshots__/test_privileges.ambr new file mode 100644 index 00000000..f7572cc3 --- /dev/null +++ b/projects/extension/tests/privileges/__snapshots__/test_privileges.ambr @@ -0,0 +1,510 @@ +# serializer version: 1 +# name: test_privileges[function] + ''' + prokind | user | privilege | granted | schema | func + ---------+-------+-----------+---------+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + f | alice | execute | YES | ai | _resolve_indexing_default() + f | bob | execute | no | ai | _resolve_indexing_default() + f | fred | execute | no | ai | _resolve_indexing_default() + f | jill | execute | YES | ai | _resolve_indexing_default() + f | alice | execute | YES | ai | _resolve_scheduling_default() + f | bob | execute | no | ai | _resolve_scheduling_default() + f | fred | execute | no | ai | _resolve_scheduling_default() + f | jill | execute | YES | ai | _resolve_scheduling_default() + f | alice | execute | YES | ai | _validate_chunking(config jsonb, source_schema name, source_table name) + f | bob | execute | no | ai | _validate_chunking(config jsonb, source_schema name, source_table name) + f | fred | execute | no | ai | _validate_chunking(config jsonb, source_schema name, source_table name) + f | jill | execute | YES | ai | _validate_chunking(config jsonb, source_schema name, source_table name) + f | alice | execute | YES | ai | _validate_embedding(config jsonb) + f | bob | execute | no | ai | _validate_embedding(config jsonb) + f | fred | execute | no | ai | _validate_embedding(config jsonb) + f | jill | execute | YES | ai | _validate_embedding(config jsonb) + f | alice | execute | YES | ai | _validate_formatting(config jsonb, source_schema name, source_table name) + f | bob | execute | no | ai | _validate_formatting(config jsonb, source_schema name, source_table name) + f | fred | execute | no | ai | _validate_formatting(config jsonb, source_schema name, source_table name) + f | jill | execute | YES | ai | _validate_formatting(config jsonb, source_schema name, source_table name) + f | alice | execute | YES | ai | _validate_formatting_python_template(config jsonb, source_schema name, source_table name) + f | bob | execute | no | ai | _validate_formatting_python_template(config jsonb, source_schema name, source_table name) + f | fred | execute | no | ai | _validate_formatting_python_template(config jsonb, source_schema name, source_table name) + f | jill | execute | YES | ai | _validate_formatting_python_template(config jsonb, source_schema name, source_table name) + f | alice | execute | YES | ai | _validate_indexing(config jsonb) + f | bob | execute | no | ai | _validate_indexing(config jsonb) + f | fred | execute | no | ai | _validate_indexing(config jsonb) + f | jill | execute | YES | ai | _validate_indexing(config jsonb) + f | alice | execute | YES | ai | _validate_indexing_diskann(config jsonb) + f | bob | execute | no | ai | _validate_indexing_diskann(config jsonb) + f | fred | execute | no | ai | _validate_indexing_diskann(config jsonb) + f | jill | execute | YES | ai | _validate_indexing_diskann(config jsonb) + f | alice | execute | YES | ai | _validate_indexing_hnsw(config jsonb) + f | bob | execute | no | ai | _validate_indexing_hnsw(config jsonb) + f | fred | execute | no | ai | _validate_indexing_hnsw(config jsonb) + f | jill | execute | YES | ai | _validate_indexing_hnsw(config jsonb) + f | alice | execute | YES | ai | _validate_processing(config jsonb) + f | bob | execute | no | ai | _validate_processing(config jsonb) + f | fred | execute | no | ai | _validate_processing(config jsonb) + f | jill | execute | YES | ai | _validate_processing(config jsonb) + f | alice | execute | YES | ai | _validate_scheduling(config jsonb) + f | bob | execute | no | ai | _validate_scheduling(config jsonb) + f | fred | execute | no | ai | _validate_scheduling(config jsonb) + f | jill | execute | YES | ai | _validate_scheduling(config jsonb) + f | alice | execute | YES | ai | _vectorizer_create_queue_table(queue_schema name, queue_table name, source_pk jsonb, grant_to name[]) + f | bob | execute | no | ai | _vectorizer_create_queue_table(queue_schema name, queue_table name, source_pk jsonb, grant_to name[]) + f | fred | execute | no | ai | _vectorizer_create_queue_table(queue_schema name, queue_table name, source_pk jsonb, grant_to name[]) + f | jill | execute | YES | ai | _vectorizer_create_queue_table(queue_schema name, queue_table name, source_pk jsonb, grant_to name[]) + f | alice | execute | YES | ai | _vectorizer_create_source_trigger(trigger_name name, queue_schema name, queue_table name, source_schema name, source_table name, source_pk jsonb) + f | bob | execute | no | ai | _vectorizer_create_source_trigger(trigger_name name, queue_schema name, queue_table name, source_schema name, source_table name, source_pk jsonb) + f | fred | execute | no | ai | _vectorizer_create_source_trigger(trigger_name name, queue_schema name, queue_table name, source_schema name, source_table name, source_pk jsonb) + f | jill | execute | YES | ai | _vectorizer_create_source_trigger(trigger_name name, queue_schema name, queue_table name, source_schema name, source_table name, source_pk jsonb) + f | alice | execute | YES | ai | _vectorizer_create_target_table(source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, dimensions integer, grant_to name[]) + f | bob | execute | no | ai | _vectorizer_create_target_table(source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, dimensions integer, grant_to name[]) + f | fred | execute | no | ai | _vectorizer_create_target_table(source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, dimensions integer, grant_to name[]) + f | jill | execute | YES | ai | _vectorizer_create_target_table(source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, dimensions integer, grant_to name[]) + f | alice | execute | YES | ai | _vectorizer_create_vector_index(target_schema name, target_table name, indexing jsonb) + f | bob | execute | no | ai | _vectorizer_create_vector_index(target_schema name, target_table name, indexing jsonb) + f | fred | execute | no | ai | _vectorizer_create_vector_index(target_schema name, target_table name, indexing jsonb) + f | jill | execute | YES | ai | _vectorizer_create_vector_index(target_schema name, target_table name, indexing jsonb) + f | alice | execute | YES | ai | _vectorizer_create_view(view_schema name, view_name name, source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, grant_to name[]) + f | bob | execute | no | ai | _vectorizer_create_view(view_schema name, view_name name, source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, grant_to name[]) + f | fred | execute | no | ai | _vectorizer_create_view(view_schema name, view_name name, source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, grant_to name[]) + f | jill | execute | YES | ai | _vectorizer_create_view(view_schema name, view_name name, source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, grant_to name[]) + f | alice | execute | YES | ai | _vectorizer_grant_to_source(source_schema name, source_table name, grant_to name[]) + f | bob | execute | no | ai | _vectorizer_grant_to_source(source_schema name, source_table name, grant_to name[]) + f | fred | execute | no | ai | _vectorizer_grant_to_source(source_schema name, source_table name, grant_to name[]) + f | jill | execute | YES | ai | _vectorizer_grant_to_source(source_schema name, source_table name, grant_to name[]) + f | alice | execute | YES | ai | _vectorizer_grant_to_vectorizer(grant_to name[]) + f | bob | execute | no | ai | _vectorizer_grant_to_vectorizer(grant_to name[]) + f | fred | execute | no | ai | _vectorizer_grant_to_vectorizer(grant_to name[]) + f | jill | execute | YES | ai | _vectorizer_grant_to_vectorizer(grant_to name[]) + f | alice | execute | YES | ai | _vectorizer_handle_drops() + f | bob | execute | no | ai | _vectorizer_handle_drops() + f | fred | execute | no | ai | _vectorizer_handle_drops() + f | jill | execute | YES | ai | _vectorizer_handle_drops() + p | alice | execute | YES | ai | _vectorizer_job(IN job_id integer, IN config jsonb) + p | bob | execute | no | ai | _vectorizer_job(IN job_id integer, IN config jsonb) + p | fred | execute | no | ai | _vectorizer_job(IN job_id integer, IN config jsonb) + p | jill | execute | YES | ai | _vectorizer_job(IN job_id integer, IN config jsonb) + f | alice | execute | YES | ai | _vectorizer_schedule_job(vectorizer_id integer, scheduling jsonb) + f | bob | execute | no | ai | _vectorizer_schedule_job(vectorizer_id integer, scheduling jsonb) + f | fred | execute | no | ai | _vectorizer_schedule_job(vectorizer_id integer, scheduling jsonb) + f | jill | execute | YES | ai | _vectorizer_schedule_job(vectorizer_id integer, scheduling jsonb) + f | alice | execute | YES | ai | _vectorizer_should_create_vector_index(vectorizer ai.vectorizer) + f | bob | execute | no | ai | _vectorizer_should_create_vector_index(vectorizer ai.vectorizer) + f | fred | execute | no | ai | _vectorizer_should_create_vector_index(vectorizer ai.vectorizer) + f | jill | execute | YES | ai | _vectorizer_should_create_vector_index(vectorizer ai.vectorizer) + f | alice | execute | YES | ai | _vectorizer_source_pk(source_table regclass) + f | bob | execute | no | ai | _vectorizer_source_pk(source_table regclass) + f | fred | execute | no | ai | _vectorizer_source_pk(source_table regclass) + f | jill | execute | YES | ai | _vectorizer_source_pk(source_table regclass) + f | alice | execute | YES | ai | _vectorizer_src_trg_1() + f | bob | execute | no | ai | _vectorizer_src_trg_1() + f | fred | execute | no | ai | _vectorizer_src_trg_1() + f | jill | execute | no | ai | _vectorizer_src_trg_1() + f | alice | execute | YES | ai | _vectorizer_vector_index_exists(target_schema name, target_table name, indexing jsonb) + f | bob | execute | no | ai | _vectorizer_vector_index_exists(target_schema name, target_table name, indexing jsonb) + f | fred | execute | no | ai | _vectorizer_vector_index_exists(target_schema name, target_table name, indexing jsonb) + f | jill | execute | YES | ai | _vectorizer_vector_index_exists(target_schema name, target_table name, indexing jsonb) + f | alice | execute | YES | ai | anthropic_generate(model text, messages jsonb, max_tokens integer, api_key text, api_key_name text, base_url text, timeout double precision, max_retries integer, system_prompt text, user_id text, stop_sequences text[], temperature double precision, tool_choice jsonb, tools jsonb, top_k integer, top_p double precision) + f | bob | execute | no | ai | anthropic_generate(model text, messages jsonb, max_tokens integer, api_key text, api_key_name text, base_url text, timeout double precision, max_retries integer, system_prompt text, user_id text, stop_sequences text[], temperature double precision, tool_choice jsonb, tools jsonb, top_k integer, top_p double precision) + f | fred | execute | no | ai | anthropic_generate(model text, messages jsonb, max_tokens integer, api_key text, api_key_name text, base_url text, timeout double precision, max_retries integer, system_prompt text, user_id text, stop_sequences text[], temperature double precision, tool_choice jsonb, tools jsonb, top_k integer, top_p double precision) + f | jill | execute | YES | ai | anthropic_generate(model text, messages jsonb, max_tokens integer, api_key text, api_key_name text, base_url text, timeout double precision, max_retries integer, system_prompt text, user_id text, stop_sequences text[], temperature double precision, tool_choice jsonb, tools jsonb, top_k integer, top_p double precision) + f | alice | execute | YES | ai | chunking_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separator text, is_separator_regex boolean) + f | bob | execute | no | ai | chunking_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separator text, is_separator_regex boolean) + f | fred | execute | no | ai | chunking_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separator text, is_separator_regex boolean) + f | jill | execute | YES | ai | chunking_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separator text, is_separator_regex boolean) + f | alice | execute | YES | ai | chunking_recursive_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separators text[], is_separator_regex boolean) + f | bob | execute | no | ai | chunking_recursive_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separators text[], is_separator_regex boolean) + f | fred | execute | no | ai | chunking_recursive_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separators text[], is_separator_regex boolean) + f | jill | execute | YES | ai | chunking_recursive_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separators text[], is_separator_regex boolean) + f | alice | execute | YES | ai | cohere_chat_complete(model text, message text, api_key text, api_key_name text, preamble text, chat_history jsonb, conversation_id text, prompt_truncation text, connectors jsonb, search_queries_only boolean, documents jsonb, citation_quality text, temperature double precision, max_tokens integer, max_input_tokens integer, k integer, p double precision, seed integer, stop_sequences text[], frequency_penalty double precision, presence_penalty double precision, tools jsonb, tool_results jsonb, force_single_step boolean) + f | bob | execute | no | ai | cohere_chat_complete(model text, message text, api_key text, api_key_name text, preamble text, chat_history jsonb, conversation_id text, prompt_truncation text, connectors jsonb, search_queries_only boolean, documents jsonb, citation_quality text, temperature double precision, max_tokens integer, max_input_tokens integer, k integer, p double precision, seed integer, stop_sequences text[], frequency_penalty double precision, presence_penalty double precision, tools jsonb, tool_results jsonb, force_single_step boolean) + f | fred | execute | no | ai | cohere_chat_complete(model text, message text, api_key text, api_key_name text, preamble text, chat_history jsonb, conversation_id text, prompt_truncation text, connectors jsonb, search_queries_only boolean, documents jsonb, citation_quality text, temperature double precision, max_tokens integer, max_input_tokens integer, k integer, p double precision, seed integer, stop_sequences text[], frequency_penalty double precision, presence_penalty double precision, tools jsonb, tool_results jsonb, force_single_step boolean) + f | jill | execute | YES | ai | cohere_chat_complete(model text, message text, api_key text, api_key_name text, preamble text, chat_history jsonb, conversation_id text, prompt_truncation text, connectors jsonb, search_queries_only boolean, documents jsonb, citation_quality text, temperature double precision, max_tokens integer, max_input_tokens integer, k integer, p double precision, seed integer, stop_sequences text[], frequency_penalty double precision, presence_penalty double precision, tools jsonb, tool_results jsonb, force_single_step boolean) + f | alice | execute | YES | ai | cohere_classify(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) + f | bob | execute | no | ai | cohere_classify(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) + f | fred | execute | no | ai | cohere_classify(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) + f | jill | execute | YES | ai | cohere_classify(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) + f | alice | execute | YES | ai | cohere_classify_simple(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) + f | bob | execute | no | ai | cohere_classify_simple(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) + f | fred | execute | no | ai | cohere_classify_simple(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) + f | jill | execute | YES | ai | cohere_classify_simple(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) + f | alice | execute | YES | ai | cohere_detokenize(model text, tokens integer[], api_key text, api_key_name text) + f | bob | execute | no | ai | cohere_detokenize(model text, tokens integer[], api_key text, api_key_name text) + f | fred | execute | no | ai | cohere_detokenize(model text, tokens integer[], api_key text, api_key_name text) + f | jill | execute | YES | ai | cohere_detokenize(model text, tokens integer[], api_key text, api_key_name text) + f | alice | execute | YES | ai | cohere_embed(model text, input_text text, api_key text, api_key_name text, input_type text, truncate_long_inputs text) + f | bob | execute | no | ai | cohere_embed(model text, input_text text, api_key text, api_key_name text, input_type text, truncate_long_inputs text) + f | fred | execute | no | ai | cohere_embed(model text, input_text text, api_key text, api_key_name text, input_type text, truncate_long_inputs text) + f | jill | execute | YES | ai | cohere_embed(model text, input_text text, api_key text, api_key_name text, input_type text, truncate_long_inputs text) + f | alice | execute | YES | ai | cohere_list_models(api_key text, api_key_name text, endpoint text, default_only boolean) + f | bob | execute | no | ai | cohere_list_models(api_key text, api_key_name text, endpoint text, default_only boolean) + f | fred | execute | no | ai | cohere_list_models(api_key text, api_key_name text, endpoint text, default_only boolean) + f | jill | execute | YES | ai | cohere_list_models(api_key text, api_key_name text, endpoint text, default_only boolean) + f | alice | execute | YES | ai | cohere_rerank(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, rank_fields text[], return_documents boolean, max_chunks_per_doc integer) + f | bob | execute | no | ai | cohere_rerank(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, rank_fields text[], return_documents boolean, max_chunks_per_doc integer) + f | fred | execute | no | ai | cohere_rerank(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, rank_fields text[], return_documents boolean, max_chunks_per_doc integer) + f | jill | execute | YES | ai | cohere_rerank(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, rank_fields text[], return_documents boolean, max_chunks_per_doc integer) + f | alice | execute | YES | ai | cohere_rerank_simple(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, max_chunks_per_doc integer) + f | bob | execute | no | ai | cohere_rerank_simple(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, max_chunks_per_doc integer) + f | fred | execute | no | ai | cohere_rerank_simple(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, max_chunks_per_doc integer) + f | jill | execute | YES | ai | cohere_rerank_simple(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, max_chunks_per_doc integer) + f | alice | execute | YES | ai | cohere_tokenize(model text, text_input text, api_key text, api_key_name text) + f | bob | execute | no | ai | cohere_tokenize(model text, text_input text, api_key text, api_key_name text) + f | fred | execute | no | ai | cohere_tokenize(model text, text_input text, api_key text, api_key_name text) + f | jill | execute | YES | ai | cohere_tokenize(model text, text_input text, api_key text, api_key_name text) + f | alice | execute | YES | ai | create_vectorizer(source regclass, destination name, embedding jsonb, chunking jsonb, indexing jsonb, formatting jsonb, scheduling jsonb, processing jsonb, target_schema name, target_table name, view_schema name, view_name name, queue_schema name, queue_table name, grant_to name[], enqueue_existing boolean) + f | bob | execute | no | ai | create_vectorizer(source regclass, destination name, embedding jsonb, chunking jsonb, indexing jsonb, formatting jsonb, scheduling jsonb, processing jsonb, target_schema name, target_table name, view_schema name, view_name name, queue_schema name, queue_table name, grant_to name[], enqueue_existing boolean) + f | fred | execute | no | ai | create_vectorizer(source regclass, destination name, embedding jsonb, chunking jsonb, indexing jsonb, formatting jsonb, scheduling jsonb, processing jsonb, target_schema name, target_table name, view_schema name, view_name name, queue_schema name, queue_table name, grant_to name[], enqueue_existing boolean) + f | jill | execute | YES | ai | create_vectorizer(source regclass, destination name, embedding jsonb, chunking jsonb, indexing jsonb, formatting jsonb, scheduling jsonb, processing jsonb, target_schema name, target_table name, view_schema name, view_name name, queue_schema name, queue_table name, grant_to name[], enqueue_existing boolean) + f | alice | execute | YES | ai | disable_vectorizer_schedule(vectorizer_id integer) + f | bob | execute | no | ai | disable_vectorizer_schedule(vectorizer_id integer) + f | fred | execute | no | ai | disable_vectorizer_schedule(vectorizer_id integer) + f | jill | execute | YES | ai | disable_vectorizer_schedule(vectorizer_id integer) + f | alice | execute | YES | ai | drop_vectorizer(vectorizer_id integer, drop_all boolean) + f | bob | execute | no | ai | drop_vectorizer(vectorizer_id integer, drop_all boolean) + f | fred | execute | no | ai | drop_vectorizer(vectorizer_id integer, drop_all boolean) + f | jill | execute | YES | ai | drop_vectorizer(vectorizer_id integer, drop_all boolean) + f | alice | execute | YES | ai | embedding_openai(model text, dimensions integer, chat_user text, api_key_name text) + f | bob | execute | no | ai | embedding_openai(model text, dimensions integer, chat_user text, api_key_name text) + f | fred | execute | no | ai | embedding_openai(model text, dimensions integer, chat_user text, api_key_name text) + f | jill | execute | YES | ai | embedding_openai(model text, dimensions integer, chat_user text, api_key_name text) + f | alice | execute | YES | ai | enable_vectorizer_schedule(vectorizer_id integer) + f | bob | execute | no | ai | enable_vectorizer_schedule(vectorizer_id integer) + f | fred | execute | no | ai | enable_vectorizer_schedule(vectorizer_id integer) + f | jill | execute | YES | ai | enable_vectorizer_schedule(vectorizer_id integer) + f | alice | execute | YES | ai | execute_vectorizer(vectorizer_id integer) + f | bob | execute | no | ai | execute_vectorizer(vectorizer_id integer) + f | fred | execute | no | ai | execute_vectorizer(vectorizer_id integer) + f | jill | execute | YES | ai | execute_vectorizer(vectorizer_id integer) + f | alice | execute | YES | ai | formatting_python_template(template text) + f | bob | execute | no | ai | formatting_python_template(template text) + f | fred | execute | no | ai | formatting_python_template(template text) + f | jill | execute | YES | ai | formatting_python_template(template text) + f | alice | execute | YES | ai | grant_ai_usage(to_user name, admin boolean) + f | bob | execute | no | ai | grant_ai_usage(to_user name, admin boolean) + f | fred | execute | no | ai | grant_ai_usage(to_user name, admin boolean) + f | jill | execute | no | ai | grant_ai_usage(to_user name, admin boolean) + f | alice | execute | YES | ai | grant_secret(secret_name text, grant_to_role text) + f | bob | execute | no | ai | grant_secret(secret_name text, grant_to_role text) + f | fred | execute | no | ai | grant_secret(secret_name text, grant_to_role text) + f | jill | execute | no | ai | grant_secret(secret_name text, grant_to_role text) + f | alice | execute | YES | ai | grant_to() + f | bob | execute | no | ai | grant_to() + f | fred | execute | no | ai | grant_to() + f | jill | execute | YES | ai | grant_to() + f | alice | execute | YES | ai | grant_to(VARIADIC grantees name[]) + f | bob | execute | no | ai | grant_to(VARIADIC grantees name[]) + f | fred | execute | no | ai | grant_to(VARIADIC grantees name[]) + f | jill | execute | YES | ai | grant_to(VARIADIC grantees name[]) + f | alice | execute | YES | ai | indexing_default() + f | bob | execute | no | ai | indexing_default() + f | fred | execute | no | ai | indexing_default() + f | jill | execute | YES | ai | indexing_default() + f | alice | execute | YES | ai | indexing_diskann(min_rows integer, storage_layout text, num_neighbors integer, search_list_size integer, max_alpha double precision, num_dimensions integer, num_bits_per_dimension integer, create_when_queue_empty boolean) + f | bob | execute | no | ai | indexing_diskann(min_rows integer, storage_layout text, num_neighbors integer, search_list_size integer, max_alpha double precision, num_dimensions integer, num_bits_per_dimension integer, create_when_queue_empty boolean) + f | fred | execute | no | ai | indexing_diskann(min_rows integer, storage_layout text, num_neighbors integer, search_list_size integer, max_alpha double precision, num_dimensions integer, num_bits_per_dimension integer, create_when_queue_empty boolean) + f | jill | execute | YES | ai | indexing_diskann(min_rows integer, storage_layout text, num_neighbors integer, search_list_size integer, max_alpha double precision, num_dimensions integer, num_bits_per_dimension integer, create_when_queue_empty boolean) + f | alice | execute | YES | ai | indexing_hnsw(min_rows integer, opclass text, m integer, ef_construction integer, create_when_queue_empty boolean) + f | bob | execute | no | ai | indexing_hnsw(min_rows integer, opclass text, m integer, ef_construction integer, create_when_queue_empty boolean) + f | fred | execute | no | ai | indexing_hnsw(min_rows integer, opclass text, m integer, ef_construction integer, create_when_queue_empty boolean) + f | jill | execute | YES | ai | indexing_hnsw(min_rows integer, opclass text, m integer, ef_construction integer, create_when_queue_empty boolean) + f | alice | execute | YES | ai | indexing_none() + f | bob | execute | no | ai | indexing_none() + f | fred | execute | no | ai | indexing_none() + f | jill | execute | YES | ai | indexing_none() + f | alice | execute | YES | ai | ollama_chat_complete(model text, messages jsonb, host text, keep_alive double precision, chat_options jsonb) + f | bob | execute | no | ai | ollama_chat_complete(model text, messages jsonb, host text, keep_alive double precision, chat_options jsonb) + f | fred | execute | no | ai | ollama_chat_complete(model text, messages jsonb, host text, keep_alive double precision, chat_options jsonb) + f | jill | execute | YES | ai | ollama_chat_complete(model text, messages jsonb, host text, keep_alive double precision, chat_options jsonb) + f | alice | execute | YES | ai | ollama_embed(model text, input_text text, host text, keep_alive double precision, embedding_options jsonb) + f | bob | execute | no | ai | ollama_embed(model text, input_text text, host text, keep_alive double precision, embedding_options jsonb) + f | fred | execute | no | ai | ollama_embed(model text, input_text text, host text, keep_alive double precision, embedding_options jsonb) + f | jill | execute | YES | ai | ollama_embed(model text, input_text text, host text, keep_alive double precision, embedding_options jsonb) + f | alice | execute | YES | ai | ollama_generate(model text, prompt text, host text, images bytea[], keep_alive double precision, embedding_options jsonb, system_prompt text, template text, context integer[]) + f | bob | execute | no | ai | ollama_generate(model text, prompt text, host text, images bytea[], keep_alive double precision, embedding_options jsonb, system_prompt text, template text, context integer[]) + f | fred | execute | no | ai | ollama_generate(model text, prompt text, host text, images bytea[], keep_alive double precision, embedding_options jsonb, system_prompt text, template text, context integer[]) + f | jill | execute | YES | ai | ollama_generate(model text, prompt text, host text, images bytea[], keep_alive double precision, embedding_options jsonb, system_prompt text, template text, context integer[]) + f | alice | execute | YES | ai | ollama_list_models(host text) + f | bob | execute | no | ai | ollama_list_models(host text) + f | fred | execute | no | ai | ollama_list_models(host text) + f | jill | execute | YES | ai | ollama_list_models(host text) + f | alice | execute | YES | ai | ollama_ps(host text) + f | bob | execute | no | ai | ollama_ps(host text) + f | fred | execute | no | ai | ollama_ps(host text) + f | jill | execute | YES | ai | ollama_ps(host text) + f | alice | execute | YES | ai | openai_chat_complete(model text, messages jsonb, api_key text, api_key_name text, base_url text, frequency_penalty double precision, logit_bias jsonb, logprobs boolean, top_logprobs integer, max_tokens integer, n integer, presence_penalty double precision, response_format jsonb, seed integer, stop text, temperature double precision, top_p double precision, tools jsonb, tool_choice jsonb, openai_user text) + f | bob | execute | no | ai | openai_chat_complete(model text, messages jsonb, api_key text, api_key_name text, base_url text, frequency_penalty double precision, logit_bias jsonb, logprobs boolean, top_logprobs integer, max_tokens integer, n integer, presence_penalty double precision, response_format jsonb, seed integer, stop text, temperature double precision, top_p double precision, tools jsonb, tool_choice jsonb, openai_user text) + f | fred | execute | no | ai | openai_chat_complete(model text, messages jsonb, api_key text, api_key_name text, base_url text, frequency_penalty double precision, logit_bias jsonb, logprobs boolean, top_logprobs integer, max_tokens integer, n integer, presence_penalty double precision, response_format jsonb, seed integer, stop text, temperature double precision, top_p double precision, tools jsonb, tool_choice jsonb, openai_user text) + f | jill | execute | YES | ai | openai_chat_complete(model text, messages jsonb, api_key text, api_key_name text, base_url text, frequency_penalty double precision, logit_bias jsonb, logprobs boolean, top_logprobs integer, max_tokens integer, n integer, presence_penalty double precision, response_format jsonb, seed integer, stop text, temperature double precision, top_p double precision, tools jsonb, tool_choice jsonb, openai_user text) + f | alice | execute | YES | ai | openai_chat_complete_simple(message text, api_key text, api_key_name text) + f | bob | execute | no | ai | openai_chat_complete_simple(message text, api_key text, api_key_name text) + f | fred | execute | no | ai | openai_chat_complete_simple(message text, api_key text, api_key_name text) + f | jill | execute | YES | ai | openai_chat_complete_simple(message text, api_key text, api_key_name text) + f | alice | execute | YES | ai | openai_detokenize(model text, tokens integer[]) + f | bob | execute | no | ai | openai_detokenize(model text, tokens integer[]) + f | fred | execute | no | ai | openai_detokenize(model text, tokens integer[]) + f | jill | execute | YES | ai | openai_detokenize(model text, tokens integer[]) + f | alice | execute | YES | ai | openai_embed(model text, input_text text, api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | bob | execute | no | ai | openai_embed(model text, input_text text, api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | fred | execute | no | ai | openai_embed(model text, input_text text, api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | jill | execute | YES | ai | openai_embed(model text, input_text text, api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | alice | execute | YES | ai | openai_embed(model text, input_texts text[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | bob | execute | no | ai | openai_embed(model text, input_texts text[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | fred | execute | no | ai | openai_embed(model text, input_texts text[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | jill | execute | YES | ai | openai_embed(model text, input_texts text[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | alice | execute | YES | ai | openai_embed(model text, input_tokens integer[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | bob | execute | no | ai | openai_embed(model text, input_tokens integer[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | fred | execute | no | ai | openai_embed(model text, input_tokens integer[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | jill | execute | YES | ai | openai_embed(model text, input_tokens integer[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) + f | alice | execute | YES | ai | openai_list_models(api_key text, api_key_name text, base_url text) + f | bob | execute | no | ai | openai_list_models(api_key text, api_key_name text, base_url text) + f | fred | execute | no | ai | openai_list_models(api_key text, api_key_name text, base_url text) + f | jill | execute | YES | ai | openai_list_models(api_key text, api_key_name text, base_url text) + f | alice | execute | YES | ai | openai_moderate(model text, input_text text, api_key text, api_key_name text, base_url text) + f | bob | execute | no | ai | openai_moderate(model text, input_text text, api_key text, api_key_name text, base_url text) + f | fred | execute | no | ai | openai_moderate(model text, input_text text, api_key text, api_key_name text, base_url text) + f | jill | execute | YES | ai | openai_moderate(model text, input_text text, api_key text, api_key_name text, base_url text) + f | alice | execute | YES | ai | openai_tokenize(model text, text_input text) + f | bob | execute | no | ai | openai_tokenize(model text, text_input text) + f | fred | execute | no | ai | openai_tokenize(model text, text_input text) + f | jill | execute | YES | ai | openai_tokenize(model text, text_input text) + f | alice | execute | YES | ai | processing_default(batch_size integer, concurrency integer) + f | bob | execute | no | ai | processing_default(batch_size integer, concurrency integer) + f | fred | execute | no | ai | processing_default(batch_size integer, concurrency integer) + f | jill | execute | YES | ai | processing_default(batch_size integer, concurrency integer) + f | alice | execute | YES | ai | reveal_secret(secret_name text, use_cache boolean) + f | bob | execute | no | ai | reveal_secret(secret_name text, use_cache boolean) + f | fred | execute | no | ai | reveal_secret(secret_name text, use_cache boolean) + f | jill | execute | YES | ai | reveal_secret(secret_name text, use_cache boolean) + f | alice | execute | YES | ai | revoke_secret(secret_name text, revoke_from_role text) + f | bob | execute | no | ai | revoke_secret(secret_name text, revoke_from_role text) + f | fred | execute | no | ai | revoke_secret(secret_name text, revoke_from_role text) + f | jill | execute | no | ai | revoke_secret(secret_name text, revoke_from_role text) + f | alice | execute | YES | ai | scheduling_default() + f | bob | execute | no | ai | scheduling_default() + f | fred | execute | no | ai | scheduling_default() + f | jill | execute | YES | ai | scheduling_default() + f | alice | execute | YES | ai | scheduling_none() + f | bob | execute | no | ai | scheduling_none() + f | fred | execute | no | ai | scheduling_none() + f | jill | execute | YES | ai | scheduling_none() + f | alice | execute | YES | ai | scheduling_timescaledb(schedule_interval interval, initial_start timestamp with time zone, fixed_schedule boolean, timezone text) + f | bob | execute | no | ai | scheduling_timescaledb(schedule_interval interval, initial_start timestamp with time zone, fixed_schedule boolean, timezone text) + f | fred | execute | no | ai | scheduling_timescaledb(schedule_interval interval, initial_start timestamp with time zone, fixed_schedule boolean, timezone text) + f | jill | execute | YES | ai | scheduling_timescaledb(schedule_interval interval, initial_start timestamp with time zone, fixed_schedule boolean, timezone text) + f | alice | execute | YES | ai | vectorizer_queue_pending(vectorizer_id integer, exact_count boolean) + f | bob | execute | no | ai | vectorizer_queue_pending(vectorizer_id integer, exact_count boolean) + f | fred | execute | no | ai | vectorizer_queue_pending(vectorizer_id integer, exact_count boolean) + f | jill | execute | YES | ai | vectorizer_queue_pending(vectorizer_id integer, exact_count boolean) + (292 rows) + + + ''' +# --- +# name: test_privileges[schema] + ''' + schema | user | privilege | granted + --------+-------+-----------+--------- + ai | alice | create | YES + ai | bob | create | no + ai | fred | create | no + ai | jill | create | YES + ai | alice | usage | YES + ai | bob | usage | no + ai | fred | usage | YES + ai | jill | usage | YES + wiki | alice | create | YES + wiki | bob | create | no + wiki | fred | create | no + wiki | jill | create | no + wiki | alice | usage | YES + wiki | bob | usage | no + wiki | fred | usage | YES + wiki | jill | usage | YES + (16 rows) + + + ''' +# --- +# name: test_privileges[sequence] + ''' + schema | table | user | privilege | granted + --------+-------------------+-------+-----------+--------- + ai | vectorizer_id_seq | alice | select | YES + ai | vectorizer_id_seq | alice | update | YES + ai | vectorizer_id_seq | bob | select | no + ai | vectorizer_id_seq | bob | update | no + ai | vectorizer_id_seq | fred | select | no + ai | vectorizer_id_seq | fred | update | no + ai | vectorizer_id_seq | jill | select | YES + ai | vectorizer_id_seq | jill | update | YES + wiki | post_id_seq | alice | select | YES + wiki | post_id_seq | alice | update | YES + wiki | post_id_seq | bob | select | no + wiki | post_id_seq | bob | update | no + wiki | post_id_seq | fred | select | no + wiki | post_id_seq | fred | update | no + wiki | post_id_seq | jill | select | no + wiki | post_id_seq | jill | update | no + (16 rows) + + + ''' +# --- +# name: test_privileges[table] + ''' + schema | table | user | privilege | granted + --------+----------------------+-------+-----------+--------- + ai | _secret_permissions | alice | delete | YES + ai | _secret_permissions | alice | insert | YES + ai | _secret_permissions | alice | select | YES + ai | _secret_permissions | alice | update | YES + ai | _secret_permissions | bob | delete | no + ai | _secret_permissions | bob | insert | no + ai | _secret_permissions | bob | select | no + ai | _secret_permissions | bob | update | no + ai | _secret_permissions | fred | delete | no + ai | _secret_permissions | fred | insert | no + ai | _secret_permissions | fred | select | no + ai | _secret_permissions | fred | update | no + ai | _secret_permissions | jill | delete | no + ai | _secret_permissions | jill | insert | no + ai | _secret_permissions | jill | select | no + ai | _secret_permissions | jill | update | no + ai | _vectorizer_q_1 | alice | delete | YES + ai | _vectorizer_q_1 | alice | insert | YES + ai | _vectorizer_q_1 | alice | select | YES + ai | _vectorizer_q_1 | alice | update | YES + ai | _vectorizer_q_1 | bob | delete | no + ai | _vectorizer_q_1 | bob | insert | no + ai | _vectorizer_q_1 | bob | select | no + ai | _vectorizer_q_1 | bob | update | no + ai | _vectorizer_q_1 | fred | delete | YES + ai | _vectorizer_q_1 | fred | insert | YES + ai | _vectorizer_q_1 | fred | select | YES + ai | _vectorizer_q_1 | fred | update | YES + ai | _vectorizer_q_1 | jill | delete | YES + ai | _vectorizer_q_1 | jill | insert | YES + ai | _vectorizer_q_1 | jill | select | YES + ai | _vectorizer_q_1 | jill | update | YES + ai | feature_flag | alice | delete | YES + ai | feature_flag | alice | insert | YES + ai | feature_flag | alice | select | YES + ai | feature_flag | alice | update | YES + ai | feature_flag | bob | delete | no + ai | feature_flag | bob | insert | no + ai | feature_flag | bob | select | no + ai | feature_flag | bob | update | no + ai | feature_flag | fred | delete | no + ai | feature_flag | fred | insert | no + ai | feature_flag | fred | select | no + ai | feature_flag | fred | update | no + ai | feature_flag | jill | delete | no + ai | feature_flag | jill | insert | no + ai | feature_flag | jill | select | no + ai | feature_flag | jill | update | no + ai | migration | alice | delete | YES + ai | migration | alice | insert | YES + ai | migration | alice | select | YES + ai | migration | alice | update | YES + ai | migration | bob | delete | no + ai | migration | bob | insert | no + ai | migration | bob | select | no + ai | migration | bob | update | no + ai | migration | fred | delete | no + ai | migration | fred | insert | no + ai | migration | fred | select | no + ai | migration | fred | update | no + ai | migration | jill | delete | no + ai | migration | jill | insert | no + ai | migration | jill | select | no + ai | migration | jill | update | no + ai | vectorizer | alice | delete | YES + ai | vectorizer | alice | insert | YES + ai | vectorizer | alice | select | YES + ai | vectorizer | alice | update | YES + ai | vectorizer | bob | delete | no + ai | vectorizer | bob | insert | no + ai | vectorizer | bob | select | no + ai | vectorizer | bob | update | no + ai | vectorizer | fred | delete | no + ai | vectorizer | fred | insert | no + ai | vectorizer | fred | select | YES + ai | vectorizer | fred | update | no + ai | vectorizer | jill | delete | YES + ai | vectorizer | jill | insert | YES + ai | vectorizer | jill | select | YES + ai | vectorizer | jill | update | YES + ai | vectorizer_errors | alice | delete | YES + ai | vectorizer_errors | alice | insert | YES + ai | vectorizer_errors | alice | select | YES + ai | vectorizer_errors | alice | update | YES + ai | vectorizer_errors | bob | delete | no + ai | vectorizer_errors | bob | insert | no + ai | vectorizer_errors | bob | select | no + ai | vectorizer_errors | bob | update | no + ai | vectorizer_errors | fred | delete | no + ai | vectorizer_errors | fred | insert | no + ai | vectorizer_errors | fred | select | no + ai | vectorizer_errors | fred | update | no + ai | vectorizer_errors | jill | delete | YES + ai | vectorizer_errors | jill | insert | YES + ai | vectorizer_errors | jill | select | YES + ai | vectorizer_errors | jill | update | YES + wiki | post | alice | delete | YES + wiki | post | alice | insert | YES + wiki | post | alice | select | YES + wiki | post | alice | update | YES + wiki | post | bob | delete | no + wiki | post | bob | insert | no + wiki | post | bob | select | no + wiki | post | bob | update | no + wiki | post | fred | delete | no + wiki | post | fred | insert | no + wiki | post | fred | select | YES + wiki | post | fred | update | no + wiki | post | jill | delete | no + wiki | post | jill | insert | no + wiki | post | jill | select | YES + wiki | post | jill | update | no + wiki | post_embedding_store | alice | delete | YES + wiki | post_embedding_store | alice | insert | YES + wiki | post_embedding_store | alice | select | YES + wiki | post_embedding_store | alice | update | YES + wiki | post_embedding_store | bob | delete | no + wiki | post_embedding_store | bob | insert | no + wiki | post_embedding_store | bob | select | no + wiki | post_embedding_store | bob | update | no + wiki | post_embedding_store | fred | delete | no + wiki | post_embedding_store | fred | insert | YES + wiki | post_embedding_store | fred | select | YES + wiki | post_embedding_store | fred | update | YES + wiki | post_embedding_store | jill | delete | no + wiki | post_embedding_store | jill | insert | YES + wiki | post_embedding_store | jill | select | YES + wiki | post_embedding_store | jill | update | YES + (128 rows) + + + ''' +# --- +# name: test_privileges[view] + ''' + schema | view | user | privilege | granted + --------+--------------------+-------+-----------+--------- + ai | secret_permissions | alice | select | YES + ai | secret_permissions | bob | select | no + ai | secret_permissions | fred | select | no + ai | secret_permissions | jill | select | YES + ai | vectorizer_status | alice | select | YES + ai | vectorizer_status | bob | select | no + ai | vectorizer_status | fred | select | no + ai | vectorizer_status | jill | select | YES + wiki | post_embedding | alice | select | YES + wiki | post_embedding | bob | select | no + wiki | post_embedding | fred | select | YES + wiki | post_embedding | jill | select | YES + (12 rows) + + + ''' +# --- diff --git a/projects/extension/tests/privileges/function.expected b/projects/extension/tests/privileges/function.expected deleted file mode 100644 index 084b1224..00000000 --- a/projects/extension/tests/privileges/function.expected +++ /dev/null @@ -1,296 +0,0 @@ - prokind | user | privilege | granted | schema | func ----------+-------+-----------+---------+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - f | alice | execute | YES | ai | _resolve_indexing_default() - f | bob | execute | no | ai | _resolve_indexing_default() - f | fred | execute | no | ai | _resolve_indexing_default() - f | jill | execute | YES | ai | _resolve_indexing_default() - f | alice | execute | YES | ai | _resolve_scheduling_default() - f | bob | execute | no | ai | _resolve_scheduling_default() - f | fred | execute | no | ai | _resolve_scheduling_default() - f | jill | execute | YES | ai | _resolve_scheduling_default() - f | alice | execute | YES | ai | _validate_chunking(config jsonb, source_schema name, source_table name) - f | bob | execute | no | ai | _validate_chunking(config jsonb, source_schema name, source_table name) - f | fred | execute | no | ai | _validate_chunking(config jsonb, source_schema name, source_table name) - f | jill | execute | YES | ai | _validate_chunking(config jsonb, source_schema name, source_table name) - f | alice | execute | YES | ai | _validate_embedding(config jsonb) - f | bob | execute | no | ai | _validate_embedding(config jsonb) - f | fred | execute | no | ai | _validate_embedding(config jsonb) - f | jill | execute | YES | ai | _validate_embedding(config jsonb) - f | alice | execute | YES | ai | _validate_formatting(config jsonb, source_schema name, source_table name) - f | bob | execute | no | ai | _validate_formatting(config jsonb, source_schema name, source_table name) - f | fred | execute | no | ai | _validate_formatting(config jsonb, source_schema name, source_table name) - f | jill | execute | YES | ai | _validate_formatting(config jsonb, source_schema name, source_table name) - f | alice | execute | YES | ai | _validate_formatting_python_template(config jsonb, source_schema name, source_table name) - f | bob | execute | no | ai | _validate_formatting_python_template(config jsonb, source_schema name, source_table name) - f | fred | execute | no | ai | _validate_formatting_python_template(config jsonb, source_schema name, source_table name) - f | jill | execute | YES | ai | _validate_formatting_python_template(config jsonb, source_schema name, source_table name) - f | alice | execute | YES | ai | _validate_indexing(config jsonb) - f | bob | execute | no | ai | _validate_indexing(config jsonb) - f | fred | execute | no | ai | _validate_indexing(config jsonb) - f | jill | execute | YES | ai | _validate_indexing(config jsonb) - f | alice | execute | YES | ai | _validate_indexing_diskann(config jsonb) - f | bob | execute | no | ai | _validate_indexing_diskann(config jsonb) - f | fred | execute | no | ai | _validate_indexing_diskann(config jsonb) - f | jill | execute | YES | ai | _validate_indexing_diskann(config jsonb) - f | alice | execute | YES | ai | _validate_indexing_hnsw(config jsonb) - f | bob | execute | no | ai | _validate_indexing_hnsw(config jsonb) - f | fred | execute | no | ai | _validate_indexing_hnsw(config jsonb) - f | jill | execute | YES | ai | _validate_indexing_hnsw(config jsonb) - f | alice | execute | YES | ai | _validate_processing(config jsonb) - f | bob | execute | no | ai | _validate_processing(config jsonb) - f | fred | execute | no | ai | _validate_processing(config jsonb) - f | jill | execute | YES | ai | _validate_processing(config jsonb) - f | alice | execute | YES | ai | _validate_scheduling(config jsonb) - f | bob | execute | no | ai | _validate_scheduling(config jsonb) - f | fred | execute | no | ai | _validate_scheduling(config jsonb) - f | jill | execute | YES | ai | _validate_scheduling(config jsonb) - f | alice | execute | YES | ai | _vectorizer_create_queue_table(queue_schema name, queue_table name, source_pk jsonb, grant_to name[]) - f | bob | execute | no | ai | _vectorizer_create_queue_table(queue_schema name, queue_table name, source_pk jsonb, grant_to name[]) - f | fred | execute | no | ai | _vectorizer_create_queue_table(queue_schema name, queue_table name, source_pk jsonb, grant_to name[]) - f | jill | execute | YES | ai | _vectorizer_create_queue_table(queue_schema name, queue_table name, source_pk jsonb, grant_to name[]) - f | alice | execute | YES | ai | _vectorizer_create_source_trigger(trigger_name name, queue_schema name, queue_table name, source_schema name, source_table name, source_pk jsonb) - f | bob | execute | no | ai | _vectorizer_create_source_trigger(trigger_name name, queue_schema name, queue_table name, source_schema name, source_table name, source_pk jsonb) - f | fred | execute | no | ai | _vectorizer_create_source_trigger(trigger_name name, queue_schema name, queue_table name, source_schema name, source_table name, source_pk jsonb) - f | jill | execute | YES | ai | _vectorizer_create_source_trigger(trigger_name name, queue_schema name, queue_table name, source_schema name, source_table name, source_pk jsonb) - f | alice | execute | YES | ai | _vectorizer_create_target_table(source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, dimensions integer, grant_to name[]) - f | bob | execute | no | ai | _vectorizer_create_target_table(source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, dimensions integer, grant_to name[]) - f | fred | execute | no | ai | _vectorizer_create_target_table(source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, dimensions integer, grant_to name[]) - f | jill | execute | YES | ai | _vectorizer_create_target_table(source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, dimensions integer, grant_to name[]) - f | alice | execute | YES | ai | _vectorizer_create_vector_index(target_schema name, target_table name, indexing jsonb) - f | bob | execute | no | ai | _vectorizer_create_vector_index(target_schema name, target_table name, indexing jsonb) - f | fred | execute | no | ai | _vectorizer_create_vector_index(target_schema name, target_table name, indexing jsonb) - f | jill | execute | YES | ai | _vectorizer_create_vector_index(target_schema name, target_table name, indexing jsonb) - f | alice | execute | YES | ai | _vectorizer_create_view(view_schema name, view_name name, source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, grant_to name[]) - f | bob | execute | no | ai | _vectorizer_create_view(view_schema name, view_name name, source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, grant_to name[]) - f | fred | execute | no | ai | _vectorizer_create_view(view_schema name, view_name name, source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, grant_to name[]) - f | jill | execute | YES | ai | _vectorizer_create_view(view_schema name, view_name name, source_schema name, source_table name, source_pk jsonb, target_schema name, target_table name, grant_to name[]) - f | alice | execute | YES | ai | _vectorizer_grant_to_source(source_schema name, source_table name, grant_to name[]) - f | bob | execute | no | ai | _vectorizer_grant_to_source(source_schema name, source_table name, grant_to name[]) - f | fred | execute | no | ai | _vectorizer_grant_to_source(source_schema name, source_table name, grant_to name[]) - f | jill | execute | YES | ai | _vectorizer_grant_to_source(source_schema name, source_table name, grant_to name[]) - f | alice | execute | YES | ai | _vectorizer_grant_to_vectorizer(grant_to name[]) - f | bob | execute | no | ai | _vectorizer_grant_to_vectorizer(grant_to name[]) - f | fred | execute | no | ai | _vectorizer_grant_to_vectorizer(grant_to name[]) - f | jill | execute | YES | ai | _vectorizer_grant_to_vectorizer(grant_to name[]) - f | alice | execute | YES | ai | _vectorizer_handle_drops() - f | bob | execute | no | ai | _vectorizer_handle_drops() - f | fred | execute | no | ai | _vectorizer_handle_drops() - f | jill | execute | YES | ai | _vectorizer_handle_drops() - p | alice | execute | YES | ai | _vectorizer_job(IN job_id integer, IN config jsonb) - p | bob | execute | no | ai | _vectorizer_job(IN job_id integer, IN config jsonb) - p | fred | execute | no | ai | _vectorizer_job(IN job_id integer, IN config jsonb) - p | jill | execute | YES | ai | _vectorizer_job(IN job_id integer, IN config jsonb) - f | alice | execute | YES | ai | _vectorizer_schedule_job(vectorizer_id integer, scheduling jsonb) - f | bob | execute | no | ai | _vectorizer_schedule_job(vectorizer_id integer, scheduling jsonb) - f | fred | execute | no | ai | _vectorizer_schedule_job(vectorizer_id integer, scheduling jsonb) - f | jill | execute | YES | ai | _vectorizer_schedule_job(vectorizer_id integer, scheduling jsonb) - f | alice | execute | YES | ai | _vectorizer_should_create_vector_index(vectorizer ai.vectorizer) - f | bob | execute | no | ai | _vectorizer_should_create_vector_index(vectorizer ai.vectorizer) - f | fred | execute | no | ai | _vectorizer_should_create_vector_index(vectorizer ai.vectorizer) - f | jill | execute | YES | ai | _vectorizer_should_create_vector_index(vectorizer ai.vectorizer) - f | alice | execute | YES | ai | _vectorizer_source_pk(source_table regclass) - f | bob | execute | no | ai | _vectorizer_source_pk(source_table regclass) - f | fred | execute | no | ai | _vectorizer_source_pk(source_table regclass) - f | jill | execute | YES | ai | _vectorizer_source_pk(source_table regclass) - f | alice | execute | YES | ai | _vectorizer_src_trg_1() - f | bob | execute | no | ai | _vectorizer_src_trg_1() - f | fred | execute | no | ai | _vectorizer_src_trg_1() - f | jill | execute | no | ai | _vectorizer_src_trg_1() - f | alice | execute | YES | ai | _vectorizer_vector_index_exists(target_schema name, target_table name, indexing jsonb) - f | bob | execute | no | ai | _vectorizer_vector_index_exists(target_schema name, target_table name, indexing jsonb) - f | fred | execute | no | ai | _vectorizer_vector_index_exists(target_schema name, target_table name, indexing jsonb) - f | jill | execute | YES | ai | _vectorizer_vector_index_exists(target_schema name, target_table name, indexing jsonb) - f | alice | execute | YES | ai | anthropic_generate(model text, messages jsonb, max_tokens integer, api_key text, api_key_name text, base_url text, timeout double precision, max_retries integer, system_prompt text, user_id text, stop_sequences text[], temperature double precision, tool_choice jsonb, tools jsonb, top_k integer, top_p double precision) - f | bob | execute | no | ai | anthropic_generate(model text, messages jsonb, max_tokens integer, api_key text, api_key_name text, base_url text, timeout double precision, max_retries integer, system_prompt text, user_id text, stop_sequences text[], temperature double precision, tool_choice jsonb, tools jsonb, top_k integer, top_p double precision) - f | fred | execute | no | ai | anthropic_generate(model text, messages jsonb, max_tokens integer, api_key text, api_key_name text, base_url text, timeout double precision, max_retries integer, system_prompt text, user_id text, stop_sequences text[], temperature double precision, tool_choice jsonb, tools jsonb, top_k integer, top_p double precision) - f | jill | execute | YES | ai | anthropic_generate(model text, messages jsonb, max_tokens integer, api_key text, api_key_name text, base_url text, timeout double precision, max_retries integer, system_prompt text, user_id text, stop_sequences text[], temperature double precision, tool_choice jsonb, tools jsonb, top_k integer, top_p double precision) - f | alice | execute | YES | ai | chunking_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separator text, is_separator_regex boolean) - f | bob | execute | no | ai | chunking_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separator text, is_separator_regex boolean) - f | fred | execute | no | ai | chunking_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separator text, is_separator_regex boolean) - f | jill | execute | YES | ai | chunking_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separator text, is_separator_regex boolean) - f | alice | execute | YES | ai | chunking_recursive_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separators text[], is_separator_regex boolean) - f | bob | execute | no | ai | chunking_recursive_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separators text[], is_separator_regex boolean) - f | fred | execute | no | ai | chunking_recursive_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separators text[], is_separator_regex boolean) - f | jill | execute | YES | ai | chunking_recursive_character_text_splitter(chunk_column name, chunk_size integer, chunk_overlap integer, separators text[], is_separator_regex boolean) - f | alice | execute | YES | ai | cohere_chat_complete(model text, message text, api_key text, api_key_name text, preamble text, chat_history jsonb, conversation_id text, prompt_truncation text, connectors jsonb, search_queries_only boolean, documents jsonb, citation_quality text, temperature double precision, max_tokens integer, max_input_tokens integer, k integer, p double precision, seed integer, stop_sequences text[], frequency_penalty double precision, presence_penalty double precision, tools jsonb, tool_results jsonb, force_single_step boolean) - f | bob | execute | no | ai | cohere_chat_complete(model text, message text, api_key text, api_key_name text, preamble text, chat_history jsonb, conversation_id text, prompt_truncation text, connectors jsonb, search_queries_only boolean, documents jsonb, citation_quality text, temperature double precision, max_tokens integer, max_input_tokens integer, k integer, p double precision, seed integer, stop_sequences text[], frequency_penalty double precision, presence_penalty double precision, tools jsonb, tool_results jsonb, force_single_step boolean) - f | fred | execute | no | ai | cohere_chat_complete(model text, message text, api_key text, api_key_name text, preamble text, chat_history jsonb, conversation_id text, prompt_truncation text, connectors jsonb, search_queries_only boolean, documents jsonb, citation_quality text, temperature double precision, max_tokens integer, max_input_tokens integer, k integer, p double precision, seed integer, stop_sequences text[], frequency_penalty double precision, presence_penalty double precision, tools jsonb, tool_results jsonb, force_single_step boolean) - f | jill | execute | YES | ai | cohere_chat_complete(model text, message text, api_key text, api_key_name text, preamble text, chat_history jsonb, conversation_id text, prompt_truncation text, connectors jsonb, search_queries_only boolean, documents jsonb, citation_quality text, temperature double precision, max_tokens integer, max_input_tokens integer, k integer, p double precision, seed integer, stop_sequences text[], frequency_penalty double precision, presence_penalty double precision, tools jsonb, tool_results jsonb, force_single_step boolean) - f | alice | execute | YES | ai | cohere_classify(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) - f | bob | execute | no | ai | cohere_classify(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) - f | fred | execute | no | ai | cohere_classify(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) - f | jill | execute | YES | ai | cohere_classify(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) - f | alice | execute | YES | ai | cohere_classify_simple(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) - f | bob | execute | no | ai | cohere_classify_simple(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) - f | fred | execute | no | ai | cohere_classify_simple(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) - f | jill | execute | YES | ai | cohere_classify_simple(model text, inputs text[], api_key text, api_key_name text, examples jsonb, truncate_long_inputs text) - f | alice | execute | YES | ai | cohere_detokenize(model text, tokens integer[], api_key text, api_key_name text) - f | bob | execute | no | ai | cohere_detokenize(model text, tokens integer[], api_key text, api_key_name text) - f | fred | execute | no | ai | cohere_detokenize(model text, tokens integer[], api_key text, api_key_name text) - f | jill | execute | YES | ai | cohere_detokenize(model text, tokens integer[], api_key text, api_key_name text) - f | alice | execute | YES | ai | cohere_embed(model text, input_text text, api_key text, api_key_name text, input_type text, truncate_long_inputs text) - f | bob | execute | no | ai | cohere_embed(model text, input_text text, api_key text, api_key_name text, input_type text, truncate_long_inputs text) - f | fred | execute | no | ai | cohere_embed(model text, input_text text, api_key text, api_key_name text, input_type text, truncate_long_inputs text) - f | jill | execute | YES | ai | cohere_embed(model text, input_text text, api_key text, api_key_name text, input_type text, truncate_long_inputs text) - f | alice | execute | YES | ai | cohere_list_models(api_key text, api_key_name text, endpoint text, default_only boolean) - f | bob | execute | no | ai | cohere_list_models(api_key text, api_key_name text, endpoint text, default_only boolean) - f | fred | execute | no | ai | cohere_list_models(api_key text, api_key_name text, endpoint text, default_only boolean) - f | jill | execute | YES | ai | cohere_list_models(api_key text, api_key_name text, endpoint text, default_only boolean) - f | alice | execute | YES | ai | cohere_rerank(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, rank_fields text[], return_documents boolean, max_chunks_per_doc integer) - f | bob | execute | no | ai | cohere_rerank(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, rank_fields text[], return_documents boolean, max_chunks_per_doc integer) - f | fred | execute | no | ai | cohere_rerank(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, rank_fields text[], return_documents boolean, max_chunks_per_doc integer) - f | jill | execute | YES | ai | cohere_rerank(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, rank_fields text[], return_documents boolean, max_chunks_per_doc integer) - f | alice | execute | YES | ai | cohere_rerank_simple(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, max_chunks_per_doc integer) - f | bob | execute | no | ai | cohere_rerank_simple(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, max_chunks_per_doc integer) - f | fred | execute | no | ai | cohere_rerank_simple(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, max_chunks_per_doc integer) - f | jill | execute | YES | ai | cohere_rerank_simple(model text, query text, documents jsonb, api_key text, api_key_name text, top_n integer, max_chunks_per_doc integer) - f | alice | execute | YES | ai | cohere_tokenize(model text, text_input text, api_key text, api_key_name text) - f | bob | execute | no | ai | cohere_tokenize(model text, text_input text, api_key text, api_key_name text) - f | fred | execute | no | ai | cohere_tokenize(model text, text_input text, api_key text, api_key_name text) - f | jill | execute | YES | ai | cohere_tokenize(model text, text_input text, api_key text, api_key_name text) - f | alice | execute | YES | ai | create_vectorizer(source regclass, destination name, embedding jsonb, chunking jsonb, indexing jsonb, formatting jsonb, scheduling jsonb, processing jsonb, target_schema name, target_table name, view_schema name, view_name name, queue_schema name, queue_table name, grant_to name[], enqueue_existing boolean) - f | bob | execute | no | ai | create_vectorizer(source regclass, destination name, embedding jsonb, chunking jsonb, indexing jsonb, formatting jsonb, scheduling jsonb, processing jsonb, target_schema name, target_table name, view_schema name, view_name name, queue_schema name, queue_table name, grant_to name[], enqueue_existing boolean) - f | fred | execute | no | ai | create_vectorizer(source regclass, destination name, embedding jsonb, chunking jsonb, indexing jsonb, formatting jsonb, scheduling jsonb, processing jsonb, target_schema name, target_table name, view_schema name, view_name name, queue_schema name, queue_table name, grant_to name[], enqueue_existing boolean) - f | jill | execute | YES | ai | create_vectorizer(source regclass, destination name, embedding jsonb, chunking jsonb, indexing jsonb, formatting jsonb, scheduling jsonb, processing jsonb, target_schema name, target_table name, view_schema name, view_name name, queue_schema name, queue_table name, grant_to name[], enqueue_existing boolean) - f | alice | execute | YES | ai | disable_vectorizer_schedule(vectorizer_id integer) - f | bob | execute | no | ai | disable_vectorizer_schedule(vectorizer_id integer) - f | fred | execute | no | ai | disable_vectorizer_schedule(vectorizer_id integer) - f | jill | execute | YES | ai | disable_vectorizer_schedule(vectorizer_id integer) - f | alice | execute | YES | ai | drop_vectorizer(vectorizer_id integer, drop_all boolean) - f | bob | execute | no | ai | drop_vectorizer(vectorizer_id integer, drop_all boolean) - f | fred | execute | no | ai | drop_vectorizer(vectorizer_id integer, drop_all boolean) - f | jill | execute | YES | ai | drop_vectorizer(vectorizer_id integer, drop_all boolean) - f | alice | execute | YES | ai | embedding_openai(model text, dimensions integer, chat_user text, api_key_name text) - f | bob | execute | no | ai | embedding_openai(model text, dimensions integer, chat_user text, api_key_name text) - f | fred | execute | no | ai | embedding_openai(model text, dimensions integer, chat_user text, api_key_name text) - f | jill | execute | YES | ai | embedding_openai(model text, dimensions integer, chat_user text, api_key_name text) - f | alice | execute | YES | ai | enable_vectorizer_schedule(vectorizer_id integer) - f | bob | execute | no | ai | enable_vectorizer_schedule(vectorizer_id integer) - f | fred | execute | no | ai | enable_vectorizer_schedule(vectorizer_id integer) - f | jill | execute | YES | ai | enable_vectorizer_schedule(vectorizer_id integer) - f | alice | execute | YES | ai | execute_vectorizer(vectorizer_id integer) - f | bob | execute | no | ai | execute_vectorizer(vectorizer_id integer) - f | fred | execute | no | ai | execute_vectorizer(vectorizer_id integer) - f | jill | execute | YES | ai | execute_vectorizer(vectorizer_id integer) - f | alice | execute | YES | ai | formatting_python_template(template text) - f | bob | execute | no | ai | formatting_python_template(template text) - f | fred | execute | no | ai | formatting_python_template(template text) - f | jill | execute | YES | ai | formatting_python_template(template text) - f | alice | execute | YES | ai | grant_ai_usage(to_user name, admin boolean) - f | bob | execute | no | ai | grant_ai_usage(to_user name, admin boolean) - f | fred | execute | no | ai | grant_ai_usage(to_user name, admin boolean) - f | jill | execute | no | ai | grant_ai_usage(to_user name, admin boolean) - f | alice | execute | YES | ai | grant_secret(secret_name text, grant_to_role text) - f | bob | execute | no | ai | grant_secret(secret_name text, grant_to_role text) - f | fred | execute | no | ai | grant_secret(secret_name text, grant_to_role text) - f | jill | execute | no | ai | grant_secret(secret_name text, grant_to_role text) - f | alice | execute | YES | ai | grant_to() - f | bob | execute | no | ai | grant_to() - f | fred | execute | no | ai | grant_to() - f | jill | execute | YES | ai | grant_to() - f | alice | execute | YES | ai | grant_to(VARIADIC grantees name[]) - f | bob | execute | no | ai | grant_to(VARIADIC grantees name[]) - f | fred | execute | no | ai | grant_to(VARIADIC grantees name[]) - f | jill | execute | YES | ai | grant_to(VARIADIC grantees name[]) - f | alice | execute | YES | ai | indexing_default() - f | bob | execute | no | ai | indexing_default() - f | fred | execute | no | ai | indexing_default() - f | jill | execute | YES | ai | indexing_default() - f | alice | execute | YES | ai | indexing_diskann(min_rows integer, storage_layout text, num_neighbors integer, search_list_size integer, max_alpha double precision, num_dimensions integer, num_bits_per_dimension integer, create_when_queue_empty boolean) - f | bob | execute | no | ai | indexing_diskann(min_rows integer, storage_layout text, num_neighbors integer, search_list_size integer, max_alpha double precision, num_dimensions integer, num_bits_per_dimension integer, create_when_queue_empty boolean) - f | fred | execute | no | ai | indexing_diskann(min_rows integer, storage_layout text, num_neighbors integer, search_list_size integer, max_alpha double precision, num_dimensions integer, num_bits_per_dimension integer, create_when_queue_empty boolean) - f | jill | execute | YES | ai | indexing_diskann(min_rows integer, storage_layout text, num_neighbors integer, search_list_size integer, max_alpha double precision, num_dimensions integer, num_bits_per_dimension integer, create_when_queue_empty boolean) - f | alice | execute | YES | ai | indexing_hnsw(min_rows integer, opclass text, m integer, ef_construction integer, create_when_queue_empty boolean) - f | bob | execute | no | ai | indexing_hnsw(min_rows integer, opclass text, m integer, ef_construction integer, create_when_queue_empty boolean) - f | fred | execute | no | ai | indexing_hnsw(min_rows integer, opclass text, m integer, ef_construction integer, create_when_queue_empty boolean) - f | jill | execute | YES | ai | indexing_hnsw(min_rows integer, opclass text, m integer, ef_construction integer, create_when_queue_empty boolean) - f | alice | execute | YES | ai | indexing_none() - f | bob | execute | no | ai | indexing_none() - f | fred | execute | no | ai | indexing_none() - f | jill | execute | YES | ai | indexing_none() - f | alice | execute | YES | ai | ollama_chat_complete(model text, messages jsonb, host text, keep_alive double precision, chat_options jsonb) - f | bob | execute | no | ai | ollama_chat_complete(model text, messages jsonb, host text, keep_alive double precision, chat_options jsonb) - f | fred | execute | no | ai | ollama_chat_complete(model text, messages jsonb, host text, keep_alive double precision, chat_options jsonb) - f | jill | execute | YES | ai | ollama_chat_complete(model text, messages jsonb, host text, keep_alive double precision, chat_options jsonb) - f | alice | execute | YES | ai | ollama_embed(model text, input_text text, host text, keep_alive double precision, embedding_options jsonb) - f | bob | execute | no | ai | ollama_embed(model text, input_text text, host text, keep_alive double precision, embedding_options jsonb) - f | fred | execute | no | ai | ollama_embed(model text, input_text text, host text, keep_alive double precision, embedding_options jsonb) - f | jill | execute | YES | ai | ollama_embed(model text, input_text text, host text, keep_alive double precision, embedding_options jsonb) - f | alice | execute | YES | ai | ollama_generate(model text, prompt text, host text, images bytea[], keep_alive double precision, embedding_options jsonb, system_prompt text, template text, context integer[]) - f | bob | execute | no | ai | ollama_generate(model text, prompt text, host text, images bytea[], keep_alive double precision, embedding_options jsonb, system_prompt text, template text, context integer[]) - f | fred | execute | no | ai | ollama_generate(model text, prompt text, host text, images bytea[], keep_alive double precision, embedding_options jsonb, system_prompt text, template text, context integer[]) - f | jill | execute | YES | ai | ollama_generate(model text, prompt text, host text, images bytea[], keep_alive double precision, embedding_options jsonb, system_prompt text, template text, context integer[]) - f | alice | execute | YES | ai | ollama_list_models(host text) - f | bob | execute | no | ai | ollama_list_models(host text) - f | fred | execute | no | ai | ollama_list_models(host text) - f | jill | execute | YES | ai | ollama_list_models(host text) - f | alice | execute | YES | ai | ollama_ps(host text) - f | bob | execute | no | ai | ollama_ps(host text) - f | fred | execute | no | ai | ollama_ps(host text) - f | jill | execute | YES | ai | ollama_ps(host text) - f | alice | execute | YES | ai | openai_chat_complete(model text, messages jsonb, api_key text, api_key_name text, base_url text, frequency_penalty double precision, logit_bias jsonb, logprobs boolean, top_logprobs integer, max_tokens integer, n integer, presence_penalty double precision, response_format jsonb, seed integer, stop text, temperature double precision, top_p double precision, tools jsonb, tool_choice jsonb, openai_user text) - f | bob | execute | no | ai | openai_chat_complete(model text, messages jsonb, api_key text, api_key_name text, base_url text, frequency_penalty double precision, logit_bias jsonb, logprobs boolean, top_logprobs integer, max_tokens integer, n integer, presence_penalty double precision, response_format jsonb, seed integer, stop text, temperature double precision, top_p double precision, tools jsonb, tool_choice jsonb, openai_user text) - f | fred | execute | no | ai | openai_chat_complete(model text, messages jsonb, api_key text, api_key_name text, base_url text, frequency_penalty double precision, logit_bias jsonb, logprobs boolean, top_logprobs integer, max_tokens integer, n integer, presence_penalty double precision, response_format jsonb, seed integer, stop text, temperature double precision, top_p double precision, tools jsonb, tool_choice jsonb, openai_user text) - f | jill | execute | YES | ai | openai_chat_complete(model text, messages jsonb, api_key text, api_key_name text, base_url text, frequency_penalty double precision, logit_bias jsonb, logprobs boolean, top_logprobs integer, max_tokens integer, n integer, presence_penalty double precision, response_format jsonb, seed integer, stop text, temperature double precision, top_p double precision, tools jsonb, tool_choice jsonb, openai_user text) - f | alice | execute | YES | ai | openai_chat_complete_simple(message text, api_key text, api_key_name text) - f | bob | execute | no | ai | openai_chat_complete_simple(message text, api_key text, api_key_name text) - f | fred | execute | no | ai | openai_chat_complete_simple(message text, api_key text, api_key_name text) - f | jill | execute | YES | ai | openai_chat_complete_simple(message text, api_key text, api_key_name text) - f | alice | execute | YES | ai | openai_detokenize(model text, tokens integer[]) - f | bob | execute | no | ai | openai_detokenize(model text, tokens integer[]) - f | fred | execute | no | ai | openai_detokenize(model text, tokens integer[]) - f | jill | execute | YES | ai | openai_detokenize(model text, tokens integer[]) - f | alice | execute | YES | ai | openai_embed(model text, input_text text, api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | bob | execute | no | ai | openai_embed(model text, input_text text, api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | fred | execute | no | ai | openai_embed(model text, input_text text, api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | jill | execute | YES | ai | openai_embed(model text, input_text text, api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | alice | execute | YES | ai | openai_embed(model text, input_texts text[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | bob | execute | no | ai | openai_embed(model text, input_texts text[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | fred | execute | no | ai | openai_embed(model text, input_texts text[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | jill | execute | YES | ai | openai_embed(model text, input_texts text[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | alice | execute | YES | ai | openai_embed(model text, input_tokens integer[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | bob | execute | no | ai | openai_embed(model text, input_tokens integer[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | fred | execute | no | ai | openai_embed(model text, input_tokens integer[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | jill | execute | YES | ai | openai_embed(model text, input_tokens integer[], api_key text, api_key_name text, base_url text, dimensions integer, openai_user text) - f | alice | execute | YES | ai | openai_list_models(api_key text, api_key_name text, base_url text) - f | bob | execute | no | ai | openai_list_models(api_key text, api_key_name text, base_url text) - f | fred | execute | no | ai | openai_list_models(api_key text, api_key_name text, base_url text) - f | jill | execute | YES | ai | openai_list_models(api_key text, api_key_name text, base_url text) - f | alice | execute | YES | ai | openai_moderate(model text, input_text text, api_key text, api_key_name text, base_url text) - f | bob | execute | no | ai | openai_moderate(model text, input_text text, api_key text, api_key_name text, base_url text) - f | fred | execute | no | ai | openai_moderate(model text, input_text text, api_key text, api_key_name text, base_url text) - f | jill | execute | YES | ai | openai_moderate(model text, input_text text, api_key text, api_key_name text, base_url text) - f | alice | execute | YES | ai | openai_tokenize(model text, text_input text) - f | bob | execute | no | ai | openai_tokenize(model text, text_input text) - f | fred | execute | no | ai | openai_tokenize(model text, text_input text) - f | jill | execute | YES | ai | openai_tokenize(model text, text_input text) - f | alice | execute | YES | ai | processing_default(batch_size integer, concurrency integer) - f | bob | execute | no | ai | processing_default(batch_size integer, concurrency integer) - f | fred | execute | no | ai | processing_default(batch_size integer, concurrency integer) - f | jill | execute | YES | ai | processing_default(batch_size integer, concurrency integer) - f | alice | execute | YES | ai | reveal_secret(secret_name text, use_cache boolean) - f | bob | execute | no | ai | reveal_secret(secret_name text, use_cache boolean) - f | fred | execute | no | ai | reveal_secret(secret_name text, use_cache boolean) - f | jill | execute | YES | ai | reveal_secret(secret_name text, use_cache boolean) - f | alice | execute | YES | ai | revoke_secret(secret_name text, revoke_from_role text) - f | bob | execute | no | ai | revoke_secret(secret_name text, revoke_from_role text) - f | fred | execute | no | ai | revoke_secret(secret_name text, revoke_from_role text) - f | jill | execute | no | ai | revoke_secret(secret_name text, revoke_from_role text) - f | alice | execute | YES | ai | scheduling_default() - f | bob | execute | no | ai | scheduling_default() - f | fred | execute | no | ai | scheduling_default() - f | jill | execute | YES | ai | scheduling_default() - f | alice | execute | YES | ai | scheduling_none() - f | bob | execute | no | ai | scheduling_none() - f | fred | execute | no | ai | scheduling_none() - f | jill | execute | YES | ai | scheduling_none() - f | alice | execute | YES | ai | scheduling_timescaledb(schedule_interval interval, initial_start timestamp with time zone, fixed_schedule boolean, timezone text) - f | bob | execute | no | ai | scheduling_timescaledb(schedule_interval interval, initial_start timestamp with time zone, fixed_schedule boolean, timezone text) - f | fred | execute | no | ai | scheduling_timescaledb(schedule_interval interval, initial_start timestamp with time zone, fixed_schedule boolean, timezone text) - f | jill | execute | YES | ai | scheduling_timescaledb(schedule_interval interval, initial_start timestamp with time zone, fixed_schedule boolean, timezone text) - f | alice | execute | YES | ai | vectorizer_queue_pending(vectorizer_id integer, exact_count boolean) - f | bob | execute | no | ai | vectorizer_queue_pending(vectorizer_id integer, exact_count boolean) - f | fred | execute | no | ai | vectorizer_queue_pending(vectorizer_id integer, exact_count boolean) - f | jill | execute | YES | ai | vectorizer_queue_pending(vectorizer_id integer, exact_count boolean) -(292 rows) - diff --git a/projects/extension/tests/privileges/function.sql b/projects/extension/tests/privileges/function.sql index 1cd332aa..b6238eb5 100644 --- a/projects/extension/tests/privileges/function.sql +++ b/projects/extension/tests/privileges/function.sql @@ -1,7 +1,6 @@ \set users {bob,fred,alice,jill} -- check function privileges -\! rm -f function.actual select f.prokind , u as "user" @@ -14,4 +13,3 @@ inner join pg_namespace n on (n.nspname = any(array['ai'])) inner join pg_proc f on (n.oid = f.pronamespace) cross join unnest(array['execute']) p order by n.nspname, 6, p, u -\g (format=aligned) function.actual diff --git a/projects/extension/tests/privileges/schema.expected b/projects/extension/tests/privileges/schema.expected deleted file mode 100644 index c018574d..00000000 --- a/projects/extension/tests/privileges/schema.expected +++ /dev/null @@ -1,20 +0,0 @@ - schema | user | privilege | granted ---------+-------+-----------+--------- - ai | alice | create | YES - ai | bob | create | no - ai | fred | create | no - ai | jill | create | YES - ai | alice | usage | YES - ai | bob | usage | no - ai | fred | usage | YES - ai | jill | usage | YES - wiki | alice | create | YES - wiki | bob | create | no - wiki | fred | create | no - wiki | jill | create | no - wiki | alice | usage | YES - wiki | bob | usage | no - wiki | fred | usage | YES - wiki | jill | usage | YES -(16 rows) - diff --git a/projects/extension/tests/privileges/schema.sql b/projects/extension/tests/privileges/schema.sql index 1d471d18..631246e9 100644 --- a/projects/extension/tests/privileges/schema.sql +++ b/projects/extension/tests/privileges/schema.sql @@ -1,7 +1,6 @@ \set users {bob,fred,alice,jill} -- check schema privileges -\! rm -f schema.actual select n as "schema" , u as "user" @@ -11,4 +10,3 @@ from unnest(:'users'::text[]) u cross join unnest(array['ai', 'wiki']) n cross join unnest(array['create', 'usage']) p order by n, p, u -\g (format=aligned) schema.actual diff --git a/projects/extension/tests/privileges/sequence.expected b/projects/extension/tests/privileges/sequence.expected deleted file mode 100644 index cf80e5ab..00000000 --- a/projects/extension/tests/privileges/sequence.expected +++ /dev/null @@ -1,20 +0,0 @@ - schema | table | user | privilege | granted ---------+-------------------+-------+-----------+--------- - ai | vectorizer_id_seq | alice | select | YES - ai | vectorizer_id_seq | alice | update | YES - ai | vectorizer_id_seq | bob | select | no - ai | vectorizer_id_seq | bob | update | no - ai | vectorizer_id_seq | fred | select | no - ai | vectorizer_id_seq | fred | update | no - ai | vectorizer_id_seq | jill | select | YES - ai | vectorizer_id_seq | jill | update | YES - wiki | post_id_seq | alice | select | YES - wiki | post_id_seq | alice | update | YES - wiki | post_id_seq | bob | select | no - wiki | post_id_seq | bob | update | no - wiki | post_id_seq | fred | select | no - wiki | post_id_seq | fred | update | no - wiki | post_id_seq | jill | select | no - wiki | post_id_seq | jill | update | no -(16 rows) - diff --git a/projects/extension/tests/privileges/sequence.sql b/projects/extension/tests/privileges/sequence.sql index bb4691b5..d2fc8c00 100644 --- a/projects/extension/tests/privileges/sequence.sql +++ b/projects/extension/tests/privileges/sequence.sql @@ -1,7 +1,6 @@ \set users {bob,fred,alice,jill} -- check sequence privileges -\! rm -f sequence.actual select n.nspname as "schema" , k.relname as "table" @@ -13,4 +12,3 @@ inner join pg_namespace n on (n.nspname = any(array['ai', 'wiki'])) inner join pg_class k on (n.oid = k.relnamespace and k.relkind in ('S')) cross join unnest(array['select', 'update']) p order by n.nspname, k.relname, u, p -\g (format=aligned) sequence.actual diff --git a/projects/extension/tests/privileges/table.expected b/projects/extension/tests/privileges/table.expected deleted file mode 100644 index 663c3daf..00000000 --- a/projects/extension/tests/privileges/table.expected +++ /dev/null @@ -1,132 +0,0 @@ - schema | table | user | privilege | granted ---------+----------------------+-------+-----------+--------- - ai | _secret_permissions | alice | delete | YES - ai | _secret_permissions | alice | insert | YES - ai | _secret_permissions | alice | select | YES - ai | _secret_permissions | alice | update | YES - ai | _secret_permissions | bob | delete | no - ai | _secret_permissions | bob | insert | no - ai | _secret_permissions | bob | select | no - ai | _secret_permissions | bob | update | no - ai | _secret_permissions | fred | delete | no - ai | _secret_permissions | fred | insert | no - ai | _secret_permissions | fred | select | no - ai | _secret_permissions | fred | update | no - ai | _secret_permissions | jill | delete | no - ai | _secret_permissions | jill | insert | no - ai | _secret_permissions | jill | select | no - ai | _secret_permissions | jill | update | no - ai | _vectorizer_q_1 | alice | delete | YES - ai | _vectorizer_q_1 | alice | insert | YES - ai | _vectorizer_q_1 | alice | select | YES - ai | _vectorizer_q_1 | alice | update | YES - ai | _vectorizer_q_1 | bob | delete | no - ai | _vectorizer_q_1 | bob | insert | no - ai | _vectorizer_q_1 | bob | select | no - ai | _vectorizer_q_1 | bob | update | no - ai | _vectorizer_q_1 | fred | delete | YES - ai | _vectorizer_q_1 | fred | insert | YES - ai | _vectorizer_q_1 | fred | select | YES - ai | _vectorizer_q_1 | fred | update | YES - ai | _vectorizer_q_1 | jill | delete | YES - ai | _vectorizer_q_1 | jill | insert | YES - ai | _vectorizer_q_1 | jill | select | YES - ai | _vectorizer_q_1 | jill | update | YES - ai | feature_flag | alice | delete | YES - ai | feature_flag | alice | insert | YES - ai | feature_flag | alice | select | YES - ai | feature_flag | alice | update | YES - ai | feature_flag | bob | delete | no - ai | feature_flag | bob | insert | no - ai | feature_flag | bob | select | no - ai | feature_flag | bob | update | no - ai | feature_flag | fred | delete | no - ai | feature_flag | fred | insert | no - ai | feature_flag | fred | select | no - ai | feature_flag | fred | update | no - ai | feature_flag | jill | delete | no - ai | feature_flag | jill | insert | no - ai | feature_flag | jill | select | no - ai | feature_flag | jill | update | no - ai | migration | alice | delete | YES - ai | migration | alice | insert | YES - ai | migration | alice | select | YES - ai | migration | alice | update | YES - ai | migration | bob | delete | no - ai | migration | bob | insert | no - ai | migration | bob | select | no - ai | migration | bob | update | no - ai | migration | fred | delete | no - ai | migration | fred | insert | no - ai | migration | fred | select | no - ai | migration | fred | update | no - ai | migration | jill | delete | no - ai | migration | jill | insert | no - ai | migration | jill | select | no - ai | migration | jill | update | no - ai | vectorizer | alice | delete | YES - ai | vectorizer | alice | insert | YES - ai | vectorizer | alice | select | YES - ai | vectorizer | alice | update | YES - ai | vectorizer | bob | delete | no - ai | vectorizer | bob | insert | no - ai | vectorizer | bob | select | no - ai | vectorizer | bob | update | no - ai | vectorizer | fred | delete | no - ai | vectorizer | fred | insert | no - ai | vectorizer | fred | select | YES - ai | vectorizer | fred | update | no - ai | vectorizer | jill | delete | YES - ai | vectorizer | jill | insert | YES - ai | vectorizer | jill | select | YES - ai | vectorizer | jill | update | YES - ai | vectorizer_errors | alice | delete | YES - ai | vectorizer_errors | alice | insert | YES - ai | vectorizer_errors | alice | select | YES - ai | vectorizer_errors | alice | update | YES - ai | vectorizer_errors | bob | delete | no - ai | vectorizer_errors | bob | insert | no - ai | vectorizer_errors | bob | select | no - ai | vectorizer_errors | bob | update | no - ai | vectorizer_errors | fred | delete | no - ai | vectorizer_errors | fred | insert | no - ai | vectorizer_errors | fred | select | no - ai | vectorizer_errors | fred | update | no - ai | vectorizer_errors | jill | delete | YES - ai | vectorizer_errors | jill | insert | YES - ai | vectorizer_errors | jill | select | YES - ai | vectorizer_errors | jill | update | YES - wiki | post | alice | delete | YES - wiki | post | alice | insert | YES - wiki | post | alice | select | YES - wiki | post | alice | update | YES - wiki | post | bob | delete | no - wiki | post | bob | insert | no - wiki | post | bob | select | no - wiki | post | bob | update | no - wiki | post | fred | delete | no - wiki | post | fred | insert | no - wiki | post | fred | select | YES - wiki | post | fred | update | no - wiki | post | jill | delete | no - wiki | post | jill | insert | no - wiki | post | jill | select | YES - wiki | post | jill | update | no - wiki | post_embedding_store | alice | delete | YES - wiki | post_embedding_store | alice | insert | YES - wiki | post_embedding_store | alice | select | YES - wiki | post_embedding_store | alice | update | YES - wiki | post_embedding_store | bob | delete | no - wiki | post_embedding_store | bob | insert | no - wiki | post_embedding_store | bob | select | no - wiki | post_embedding_store | bob | update | no - wiki | post_embedding_store | fred | delete | no - wiki | post_embedding_store | fred | insert | YES - wiki | post_embedding_store | fred | select | YES - wiki | post_embedding_store | fred | update | YES - wiki | post_embedding_store | jill | delete | no - wiki | post_embedding_store | jill | insert | YES - wiki | post_embedding_store | jill | select | YES - wiki | post_embedding_store | jill | update | YES -(128 rows) - diff --git a/projects/extension/tests/privileges/table.sql b/projects/extension/tests/privileges/table.sql index 33195967..29ad1052 100644 --- a/projects/extension/tests/privileges/table.sql +++ b/projects/extension/tests/privileges/table.sql @@ -1,7 +1,6 @@ \set users {bob,fred,alice,jill} -- check table privileges -\! rm -f schema.actual select n.nspname as "schema" , k.relname as "table" @@ -13,4 +12,3 @@ inner join pg_namespace n on (n.nspname = any(array['ai', 'wiki'])) inner join pg_class k on (n.oid = k.relnamespace and k.relkind in ('r', 'p')) cross join unnest(array['select', 'insert', 'update', 'delete']) p order by n.nspname, k.relname, u, p -\g (format=aligned) table.actual diff --git a/projects/extension/tests/privileges/test_privileges.py b/projects/extension/tests/privileges/test_privileges.py index 40b67b00..5070e7db 100644 --- a/projects/extension/tests/privileges/test_privileges.py +++ b/projects/extension/tests/privileges/test_privileges.py @@ -39,7 +39,7 @@ def psql_file(user, dbname, file: str) -> None: cmd = " ".join( [ "psql", - f'''-d "{db_url(user, dbname)}"''', + f'-d "{db_url(user, dbname)}"', "-v ON_ERROR_STOP=1", "-X", f"-f {docker_dir()}/{file}", @@ -47,7 +47,16 @@ def psql_file(user, dbname, file: str) -> None: ) if where_am_i() != "docker": cmd = f"docker exec -w {docker_dir()} pgai-ext {cmd}" - subprocess.run(cmd, check=True, shell=True, env=os.environ, cwd=str(host_dir())) + result = subprocess.run( + cmd, + check=True, + shell=True, + env=os.environ, + cwd=str(host_dir()), + text=True, + capture_output=True, + ) + return result.stdout @pytest.fixture(scope="module", autouse=True) @@ -56,31 +65,9 @@ def init(): psql_file("alice", "privs", "init1.sql") -def run_test(kind: str) -> None: - psql_file("postgres", "privs", f"{kind}.sql") - expected = read_file(f"{kind}.expected") - actual = read_file(f"{kind}.actual") - assert actual == expected - - -def test_schema_privileges(): - run_test("schema") - - -def test_table_privileges(): - run_test("table") - - -def test_sequence_privileges(): - run_test("sequence") - - -def test_view_privileges(): - run_test("view") - - -def test_function_privileges(): - run_test("function") +@pytest.mark.parametrize("type", ["schema", "table", "sequence", "view", "function"]) +def test_privileges(snapshot, type): + assert psql_file("postgres", "privs", f"{type}.sql") == snapshot def test_jill_privileges(): diff --git a/projects/extension/tests/privileges/view.expected b/projects/extension/tests/privileges/view.expected deleted file mode 100644 index d2445e24..00000000 --- a/projects/extension/tests/privileges/view.expected +++ /dev/null @@ -1,16 +0,0 @@ - schema | view | user | privilege | granted ---------+--------------------+-------+-----------+--------- - ai | secret_permissions | alice | select | YES - ai | secret_permissions | bob | select | no - ai | secret_permissions | fred | select | no - ai | secret_permissions | jill | select | YES - ai | vectorizer_status | alice | select | YES - ai | vectorizer_status | bob | select | no - ai | vectorizer_status | fred | select | no - ai | vectorizer_status | jill | select | YES - wiki | post_embedding | alice | select | YES - wiki | post_embedding | bob | select | no - wiki | post_embedding | fred | select | YES - wiki | post_embedding | jill | select | YES -(12 rows) - diff --git a/projects/extension/tests/privileges/view.sql b/projects/extension/tests/privileges/view.sql index 332e2def..4aaad8b1 100644 --- a/projects/extension/tests/privileges/view.sql +++ b/projects/extension/tests/privileges/view.sql @@ -1,7 +1,6 @@ \set users {bob,fred,alice,jill} -- check view privileges -\! rm -f view.actual select n.nspname as "schema" , k.relname as "view" @@ -13,4 +12,3 @@ inner join pg_namespace n on (n.nspname = any(array['ai', 'wiki'])) inner join pg_class k on (n.oid = k.relnamespace and k.relkind in ('v')) cross join unnest(array['select']) p order by n.nspname, k.relname, u, p -\g (format=aligned) view.actual diff --git a/projects/extension/tests/vectorizer/__snapshots__/test_vectorizer.ambr b/projects/extension/tests/vectorizer/__snapshots__/test_vectorizer.ambr new file mode 100644 index 00000000..e1b6864b --- /dev/null +++ b/projects/extension/tests/vectorizer/__snapshots__/test_vectorizer.ambr @@ -0,0 +1,161 @@ +# serializer version: 1 +# name: test_vectorizer_timescaledb + ''' + { + "config": { + "chunking": { + "chunk_column": "body", + "chunk_overlap": 10, + "chunk_size": 128, + "config_type": "chunking", + "implementation": "character_text_splitter", + "is_separator_regex": false, + "separator": "\n\n" + }, + "embedding": { + "api_key_name": "OPENAI_API_KEY", + "config_type": "embedding", + "dimensions": 768, + "implementation": "openai", + "model": "text-embedding-3-small" + }, + "formatting": { + "config_type": "formatting", + "implementation": "python_template", + "template": "title: $title published: $published $chunk" + }, + "indexing": { + "config_type": "indexing", + "implementation": "none" + }, + "processing": { + "config_type": "processing", + "implementation": "default" + }, + "scheduling": { + "config_type": "scheduling", + "implementation": "timescaledb", + "initial_start": "2050-01-06T00:00:00+00:00", + "job_id": 1000, + "schedule_interval": "00:05:00", + "timezone": "America/Chicago" + } + }, + "id": 1, + "queue_schema": "ai", + "queue_table": "_vectorizer_q_1", + "source_pk": [ + { + "attname": "title", + "attnum": 2, + "pknum": 1, + "typname": "text" + }, + { + "attname": "published", + "attnum": 3, + "pknum": 2, + "typname": "timestamptz" + } + ], + "source_schema": "website", + "source_table": "blog", + "target_schema": "website", + "target_table": "blog_embedding_store", + "trigger_name": "_vectorizer_src_trg_1", + "view_name": "blog_embedding", + "view_schema": "website" + } + ''' +# --- +# name: test_vectorizer_timescaledb.1 + ''' + Table "website.blog" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description + -----------+--------------------------+-----------+----------+------------------------------+----------+-------------+--------------+------------- + id | integer | | not null | generated always as identity | plain | | | + title | text | | not null | | extended | | | + published | timestamp with time zone | | not null | | plain | | | + body | text | | not null | | extended | | | + Indexes: + "blog_pkey" PRIMARY KEY, btree (title, published) + Referenced by: + TABLE "website.blog_embedding_store" CONSTRAINT "blog_embedding_store_title_published_fkey" FOREIGN KEY (title, published) REFERENCES website.blog(title, published) ON DELETE CASCADE + Triggers: + _vectorizer_src_trg_1 AFTER INSERT OR UPDATE ON website.blog FOR EACH ROW EXECUTE FUNCTION ai._vectorizer_src_trg_1() + Access method: heap + ''' +# --- +# name: test_vectorizer_timescaledb.2 + ''' + List of functions + Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Access privileges | Language | Source code | Description + --------+-----------------------+------------------+---------------------+------+------------+----------+-------+----------+-------------------+----------+-----------------------------------------------------------+------------- + ai | _vectorizer_src_trg_1 | trigger | | func | volatile | safe | test | definer | test=X/test | plpgsql | +| + | | | | | | | | | | | begin +| + | | | | | | | | | | | insert into ai._vectorizer_q_1 (title, published)+| + | | | | | | | | | | | values (new.title, new.published); +| + | | | | | | | | | | | return null; +| + | | | | | | | | | | | end; +| + | | | | | | | | | | | | + (1 row) + ''' +# --- +# name: test_vectorizer_timescaledb.3 + ''' + Table "website.blog_embedding_store" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description + ----------------+--------------------------+-----------+----------+-------------------+----------+-------------+--------------+------------- + embedding_uuid | uuid | | not null | gen_random_uuid() | plain | | | + title | text | | not null | | extended | | | + published | timestamp with time zone | | not null | | plain | | | + chunk_seq | integer | | not null | | plain | | | + chunk | text | | not null | | extended | | | + embedding | vector(768) | | not null | | main | | | + Indexes: + "blog_embedding_store_pkey" PRIMARY KEY, btree (embedding_uuid) + "blog_embedding_store_title_published_chunk_seq_key" UNIQUE CONSTRAINT, btree (title, published, chunk_seq) + Foreign-key constraints: + "blog_embedding_store_title_published_fkey" FOREIGN KEY (title, published) REFERENCES website.blog(title, published) ON DELETE CASCADE + Access method: heap + ''' +# --- +# name: test_vectorizer_timescaledb.4 + ''' + Table "ai._vectorizer_q_1" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description + -----------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- + title | text | | not null | | extended | | | + published | timestamp with time zone | | not null | | plain | | | + queued_at | timestamp with time zone | | not null | now() | plain | | | + Indexes: + "_vectorizer_q_1_title_published_idx" btree (title, published) + Access method: heap + ''' +# --- +# name: test_vectorizer_timescaledb.5 + ''' + View "website.blog_embedding" + Column | Type | Collation | Nullable | Default | Storage | Description + ----------------+--------------------------+-----------+----------+---------+----------+------------- + embedding_uuid | uuid | | | | plain | + chunk_seq | integer | | | | plain | + chunk | text | | | | extended | + embedding | vector(768) | | | | external | + id | integer | | | | plain | + title | text | | | | extended | + published | timestamp with time zone | | | | plain | + body | text | | | | extended | + View definition: + SELECT t.embedding_uuid, + t.chunk_seq, + t.chunk, + t.embedding, + s.id, + t.title, + t.published, + s.body + FROM website.blog_embedding_store t + LEFT JOIN website.blog s ON t.title = s.title AND t.published = s.published; + ''' +# --- diff --git a/projects/extension/tests/vectorizer/test_vectorizer.py b/projects/extension/tests/vectorizer/test_vectorizer.py index 87823fe9..5ce666b5 100644 --- a/projects/extension/tests/vectorizer/test_vectorizer.py +++ b/projects/extension/tests/vectorizer/test_vectorizer.py @@ -12,160 +12,6 @@ pytest.skip(allow_module_level=True) -VECTORIZER_ROW = r""" -{ - "id": 1, - "config": { - "chunking": { - "separator": "\n\n", - "chunk_size": 128, - "config_type": "chunking", - "chunk_column": "body", - "chunk_overlap": 10, - "implementation": "character_text_splitter", - "is_separator_regex": false - }, - "indexing": { - "config_type": "indexing", - "implementation": "none" - }, - "embedding": { - "model": "text-embedding-3-small", - "dimensions": 768, - "config_type": "embedding", - "api_key_name": "OPENAI_API_KEY", - "implementation": "openai" - }, - "formatting": { - "template": "title: $title published: $published $chunk", - "config_type": "formatting", - "implementation": "python_template" - }, - "processing": { - "config_type": "processing", - "implementation": "default" - }, - "scheduling": { - "job_id": 1000, - "timezone": "America/Chicago", - "config_type": "scheduling", - "initial_start": "2050-01-06T00:00:00+00:00", - "implementation": "timescaledb", - "schedule_interval": "00:05:00" - } - }, - "source_pk": [ - { - "pknum": 1, - "attnum": 2, - "attname": "title", - "typname": "text" - }, - { - "pknum": 2, - "attnum": 3, - "attname": "published", - "typname": "timestamptz" - } - ], - "view_name": "blog_embedding", - "queue_table": "_vectorizer_q_1", - "view_schema": "website", - "queue_schema": "ai", - "source_table": "blog", - "target_table": "blog_embedding_store", - "trigger_name": "_vectorizer_src_trg_1", - "source_schema": "website", - "target_schema": "website" -} -""" - - -SOURCE_TABLE = """ - Table "website.blog" - Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description ------------+--------------------------+-----------+----------+------------------------------+----------+-------------+--------------+------------- - id | integer | | not null | generated always as identity | plain | | | - title | text | | not null | | extended | | | - published | timestamp with time zone | | not null | | plain | | | - body | text | | not null | | extended | | | -Indexes: - "blog_pkey" PRIMARY KEY, btree (title, published) -Referenced by: - TABLE "website.blog_embedding_store" CONSTRAINT "blog_embedding_store_title_published_fkey" FOREIGN KEY (title, published) REFERENCES website.blog(title, published) ON DELETE CASCADE -Triggers: - _vectorizer_src_trg_1 AFTER INSERT OR UPDATE ON website.blog FOR EACH ROW EXECUTE FUNCTION ai._vectorizer_src_trg_1() -Access method: heap -""".strip() - - -SOURCE_TRIGGER_FUNC = """ - List of functions - Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Access privileges | Language | Internal name | Description ---------+-----------------------+------------------+---------------------+------+------------+----------+-------+----------+-------------------+----------+---------------+------------- - ai | _vectorizer_src_trg_1 | trigger | | func | volatile | safe | test | definer | test=X/test | plpgsql | | -(1 row) -""".strip() - - -TARGET_TABLE = """ - Table "website.blog_embedding_store" - Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description -----------------+--------------------------+-----------+----------+-------------------+----------+-------------+--------------+------------- - embedding_uuid | uuid | | not null | gen_random_uuid() | plain | | | - title | text | | not null | | extended | | | - published | timestamp with time zone | | not null | | plain | | | - chunk_seq | integer | | not null | | plain | | | - chunk | text | | not null | | extended | | | - embedding | vector(768) | | not null | | main | | | -Indexes: - "blog_embedding_store_pkey" PRIMARY KEY, btree (embedding_uuid) - "blog_embedding_store_title_published_chunk_seq_key" UNIQUE CONSTRAINT, btree (title, published, chunk_seq) -Foreign-key constraints: - "blog_embedding_store_title_published_fkey" FOREIGN KEY (title, published) REFERENCES website.blog(title, published) ON DELETE CASCADE -Access method: heap -""".strip() - - -QUEUE_TABLE = """ - Table "ai._vectorizer_q_1" - Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description ------------+--------------------------+-----------+----------+---------+----------+-------------+--------------+------------- - title | text | | not null | | extended | | | - published | timestamp with time zone | | not null | | plain | | | - queued_at | timestamp with time zone | | not null | now() | plain | | | -Indexes: - "_vectorizer_q_1_title_published_idx" btree (title, published) -Access method: heap -""".strip() - - -VIEW = """ - View "website.blog_embedding" - Column | Type | Collation | Nullable | Default | Storage | Description -----------------+--------------------------+-----------+----------+---------+----------+------------- - embedding_uuid | uuid | | | | plain | - chunk_seq | integer | | | | plain | - chunk | text | | | | extended | - embedding | vector(768) | | | | external | - id | integer | | | | plain | - title | text | | | | extended | - published | timestamp with time zone | | | | plain | - body | text | | | | extended | -View definition: - SELECT t.embedding_uuid, - t.chunk_seq, - t.chunk, - t.embedding, - s.id, - t.title, - t.published, - s.body - FROM website.blog_embedding_store t - LEFT JOIN website.blog s ON t.title = s.title AND t.published = s.published; -""".strip() - - def db_url(user: str) -> str: return f"postgres://{user}@127.0.0.1:5432/test" @@ -176,7 +22,7 @@ def psql_cmd(cmd: str) -> str: return str(proc.stdout).strip() -def test_vectorizer_timescaledb(): +def test_vectorizer_timescaledb(snapshot): with psycopg.connect( db_url("postgres"), autocommit=True, row_factory=namedtuple_row ) as con: @@ -248,8 +94,7 @@ def test_vectorizer_timescaledb(): (vectorizer_id,), ) actual = json.dumps(json.loads(cur.fetchone()[0]), sort_keys=True, indent=2) - expected = json.dumps(json.loads(VECTORIZER_ROW), sort_keys=True, indent=2) - assert actual == expected + assert actual == snapshot cur.execute("select * from ai.vectorizer where id = %s", (vectorizer_id,)) vec = cur.fetchone() @@ -449,23 +294,23 @@ def test_vectorizer_timescaledb(): # does the source table look right? actual = psql_cmd(r"\d+ website.blog") - assert actual == SOURCE_TABLE + assert actual == snapshot # does the source trigger function look right? actual = psql_cmd(r"\df+ ai._vectorizer_src_trg_1()") - assert actual == SOURCE_TRIGGER_FUNC + assert actual == snapshot # does the target table look right? actual = psql_cmd(r"\d+ website.blog_embedding_store") - assert actual == TARGET_TABLE + assert actual == snapshot # does the queue table look right? actual = psql_cmd(r"\d+ ai._vectorizer_q_1") - assert actual == QUEUE_TABLE + assert actual == snapshot # does the view look right? actual = psql_cmd(r"\d+ website.blog_embedding") - assert actual == VIEW + assert actual == snapshot def test_drop_vectorizer():