13618fb8d5
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / build (pull_request) Successful in 15s
CI / quality (pull_request) Successful in 17s
CI / security (pull_request) Successful in 33s
CI / typecheck (pull_request) Successful in 47s
CI / unit_tests (pull_request) Successful in 2m35s
CI / integration_tests (pull_request) Successful in 3m13s
CI / docker (pull_request) Successful in 39s
CI / coverage (pull_request) Successful in 4m26s
CI / benchmark-regression (pull_request) Has been cancelled
- F1/F2 [P1]: Split postgresql_analyzer.py (695→310 lines) by
extracting regex patterns, URI builders, and parsing functions
into _postgresql_helpers.py (440 lines). Split
domain_analyzers.feature (605→217 lines) into separate
postgresql_analyzer.feature (201) and
docker_compose_analyzer.feature (199).
- F3 [P1]: Fix _extract_body and _split_entries to track
single-quoted SQL string literals so parentheses inside
DEFAULT/CHECK values (e.g. 'func(x)') do not corrupt depth
counting. Added regression scenarios.
- F4 [P2]: Remove prohibited `# type: ignore[arg-type]` by
adding a static protocol assertion for _DuplicatePyAnalyzer.
- F5 [P2]: Add 1 MiB size guard before yaml.safe_load in
DockerComposeAnalyzer to mitigate billion-laughs alias
expansion attacks.
- F6 [P2]: Fix quoted-keyword column names (e.g. "primary")
being silently dropped by checking raw_first.startswith('"')
before keyword filtering. Added regression scenario.
- F7 [P2]: Out-of-scope file changes resolved by rebase onto
master (changes already merged via other PRs).
All nox gates pass: lint (0 errors), typecheck (0 errors),
security_scan, behave (57 scenarios, 211 steps, 0 failures).
202 lines
7.7 KiB
Gherkin
202 lines
7.7 KiB
Gherkin
@phase2 @acms @analyzer @postgresql_analyzer
|
|
Feature: PostgreSQLAnalyzer
|
|
As a CleverAgents developer
|
|
I want a PostgreSQL DDL analyzer that produces UKO triples from SQL files
|
|
So that the ACMS can index database schemas into the UKO knowledge graph
|
|
|
|
Scenario: Analyze CREATE TABLE
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE TABLE users (
|
|
id SERIAL,
|
|
name VARCHAR(100)
|
|
);
|
|
"""
|
|
Then the triples should include predicate "rdf:type" with object_uri "uko-data:Table"
|
|
And the triples should include predicate "rdf:type" with object_uri "uko-data:Column"
|
|
And the triples should include predicate "uko-data:dataType"
|
|
|
|
Scenario: Analyze table with NOT NULL and PRIMARY KEY
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE TABLE accounts (
|
|
id SERIAL PRIMARY KEY,
|
|
email VARCHAR(255) NOT NULL
|
|
);
|
|
"""
|
|
Then the triples should include predicate "uko-data:isPrimaryKey" with object_value "true"
|
|
And the triples should include predicate "uko-data:isNullable" with object_value "false"
|
|
|
|
Scenario: Analyze FOREIGN KEY
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE TABLE orders (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER NOT NULL,
|
|
FOREIGN KEY (user_id) REFERENCES users(id)
|
|
);
|
|
"""
|
|
Then the triples should include predicate "rdf:type" with object_uri "uko-data:ForeignKey"
|
|
And the triples should include predicate "uko-data:foreignKeyTo"
|
|
|
|
Scenario: Analyze CREATE VIEW
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE VIEW active_users AS
|
|
SELECT * FROM users WHERE active = true;
|
|
"""
|
|
Then the triples should include predicate "rdf:type" with object_uri "uko-data:View"
|
|
And the triples should include predicate "rdfs:label" with object_value "active_users"
|
|
|
|
Scenario: Analyze CREATE SCHEMA
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE SCHEMA IF NOT EXISTS app;
|
|
CREATE TABLE app.users (
|
|
id SERIAL PRIMARY KEY
|
|
);
|
|
"""
|
|
Then the triples should include predicate "rdf:type" with object_uri "uko-data:Schema"
|
|
And the triples should include predicate "rdfs:label" with object_value "app"
|
|
And the triples should include predicate "uko:contains" linking subject "schema" to object "users"
|
|
|
|
Scenario: Analyze schema-qualified table includes schema in column URIs
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE TABLE myschema.items (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(100)
|
|
);
|
|
"""
|
|
Then the triples should include predicate "rdf:type" with object_uri "uko-data:Table"
|
|
And the triples should include predicate "rdf:type" with object_uri "uko-data:Column"
|
|
And the triples should include predicate "uko:contains" linking subject "myschema" to object "items"
|
|
|
|
Scenario: Analyze table with composite PRIMARY KEY
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE TABLE user_roles (
|
|
user_id INTEGER NOT NULL,
|
|
role_id INTEGER NOT NULL,
|
|
PRIMARY KEY (user_id, role_id)
|
|
);
|
|
"""
|
|
Then the triples should include predicate "uko-data:isPrimaryKey" with object_value "true"
|
|
|
|
Scenario: Analyze empty SQL content raises ValueError
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
Then analyzing empty content with this analyzer should raise ValueError
|
|
|
|
Scenario: Analyze whitespace-only SQL content raises ValueError
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
Then analyzing whitespace-only content with this analyzer should raise ValueError
|
|
|
|
Scenario: Analyze SQL with empty resource_uri raises ValueError
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
Then analyzing content with empty resource_uri should raise ValueError
|
|
|
|
Scenario: Analyze SQL with comments does not produce phantom triples
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
-- CREATE TABLE phantom (id INT);
|
|
/* CREATE VIEW ghost AS SELECT 1; */
|
|
CREATE TABLE real_table (id SERIAL PRIMARY KEY);
|
|
"""
|
|
Then the triples should include predicate "rdfs:label" with object_value "real_table"
|
|
And the triples should not include predicate "rdfs:label" with object_value "phantom"
|
|
And the triples should not include predicate "rdfs:label" with object_value "ghost"
|
|
|
|
Scenario: Analyze multi-column FOREIGN KEY
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE TABLE user_roles (
|
|
user_id INTEGER NOT NULL,
|
|
role_id INTEGER NOT NULL,
|
|
PRIMARY KEY (user_id, role_id),
|
|
FOREIGN KEY (user_id, role_id) REFERENCES lookup(uid, rid)
|
|
);
|
|
"""
|
|
Then the triples should include predicate "rdf:type" with object_uri "uko-data:ForeignKey"
|
|
And the triples should include predicate "uko-data:foreignKeyTo" with object_uri containing "uid"
|
|
And the triples should include predicate "uko-data:foreignKeyTo" with object_uri containing "rid"
|
|
|
|
Scenario: Analyze CREATE VIEW captures viewDefinition
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE VIEW active_users AS
|
|
SELECT id, name FROM users WHERE active = true;
|
|
"""
|
|
Then the triples should include predicate "rdf:type" with object_uri "uko-data:View"
|
|
And the triples should include predicate "uko-data:viewDefinition"
|
|
|
|
Scenario: Duplicate CREATE TABLE is deduplicated
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE TABLE items (id SERIAL);
|
|
CREATE TABLE items (id SERIAL, name TEXT);
|
|
"""
|
|
Then the triples should include predicate "rdf:type" with object_uri "uko-data:Table"
|
|
And the number of Table type triples should be 1
|
|
|
|
Scenario: Analyze invalid SQL returns empty list
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
THIS IS NOT VALID SQL AT ALL;
|
|
JUST RANDOM TEXT HERE;
|
|
"""
|
|
Then no triples should be returned
|
|
|
|
# -- Regression tests for F3 (string-literal parentheses) --
|
|
|
|
Scenario: DEFAULT with parentheses in string literal does not truncate columns
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE TABLE config (
|
|
col1 TEXT DEFAULT 'hello(world)',
|
|
col2 INTEGER
|
|
);
|
|
"""
|
|
Then the triples should include predicate "rdfs:label" with object_value "col1"
|
|
And the triples should include predicate "rdfs:label" with object_value "col2"
|
|
|
|
Scenario: CHECK constraint with string containing parentheses
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE TABLE validated (
|
|
status TEXT CHECK (status IN ('active(1)', 'inactive(0)')),
|
|
amount INTEGER
|
|
);
|
|
"""
|
|
Then the triples should include predicate "rdfs:label" with object_value "status"
|
|
And the triples should include predicate "rdfs:label" with object_value "amount"
|
|
|
|
# -- Regression test for F6 (quoted keyword column names) --
|
|
|
|
Scenario: Quoted keyword column names are not silently dropped
|
|
Given a PostgreSQLAnalyzer analyzer
|
|
When I analyze the SQL content:
|
|
"""
|
|
CREATE TABLE reserved_words (
|
|
"primary" INTEGER,
|
|
"check" VARCHAR(50),
|
|
normal_col TEXT
|
|
);
|
|
"""
|
|
Then the triples should include predicate "rdfs:label" with object_value "primary"
|
|
And the triples should include predicate "rdfs:label" with object_value "check"
|
|
And the triples should include predicate "rdfs:label" with object_value "normal_col"
|