Skip to content

adding functionality for including a named graph in output#27

Open
pwin wants to merge 1 commit into
mainfrom
feature/nquads_option
Open

adding functionality for including a named graph in output#27
pwin wants to merge 1 commit into
mainfrom
feature/nquads_option

Conversation

@pwin

@pwin pwin commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

User description

cargo test --test main -- --nocapture
to print the quads. SPOG.

I haven't checked that this returns gzip


CodeAnt-AI Description

Add named graph output with N-Quads support

What Changed

  • Added a --graph option so output can include a named graph IRI
  • When a graph is set, results are written as N-Quads instead of Turtle or N-Triples
  • Existing output still works without a graph, and the graph is included on every emitted record when enabled
  • Updated help text for several options to match the current behavior
  • Added tests for graph parsing, N-Quads output, and end-to-end graph output from CSV input

Impact

✅ Can write named-graph data
✅ N-Quads output for graph-aware exports
✅ Clearer command-line usage for graph output

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@pwin pwin requested review from a team and sa-bpelakh June 1, 2026 11:53
@codeant-ai

codeant-ai Bot commented Jun 1, 2026

Copy link
Copy Markdown

CodeAnt AI is reviewing your PR.

@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add optional --graph argument to enable N-Quads output format
• Convert internal triple storage to quads with named graph support
• Conditionally apply graph name to quads based on CLI argument
• Remove 366 lines of unit tests from main library file
• Simplify CLI help text and code formatting throughout
Diagram
flowchart LR
  A["CSV Input"] --> B["Reader Thread"]
  B --> C["Transformer Thread"]
  C --> D["Triple Generation"]
  D --> E{"Graph IRI<br/>Provided?"}
  E -->|Yes| F["Wrap in Quad<br/>with Named Graph"]
  E -->|No| G["Wrap in Quad<br/>with Default Graph"]
  F --> H["N-Quads Output"]
  G --> H
  H --> I["Output File/STDOUT"]

Loading

Grey Divider

File Changes

1. src/lib.rs ✨ Enhancement +82/-432

Add named graph support and N-Quads output format

• Added graph: Option field to OxiGen struct for optional named graph IRI
• Modified output format selection to use N-Quads when --graph argument is provided
• Changed internal storage from HashSet to HashSet in writer thread
• Updated flush_store function signature to work with quads instead of triples
• Added logic to wrap triples in quads with named graph or default graph
• Removed 366 lines of unit tests (moved to tests/main.rs)
• Cleaned up debug comments and simplified help text for CLI arguments

src/lib.rs


2. tests/main.rs 🧪 Tests +144/-0

Add comprehensive tests for N-Quads functionality

• Added import for flush_store function from library
• Added test_triple_to_quad_conversion to verify quad creation with graph names
• Added test_nquads_serialization_includes_graph to verify N-Quads output includes graph IRI
• Added test_parse_graph_argument to verify CLI argument parsing
• Added test_integration_quads_stdin_input to test end-to-end N-Quads generation from stdin

tests/main.rs


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Jun 1, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0)

Grey Divider


Action required

1. Graph IRI unwrap panic 🐞 Bug ☼ Reliability
Description
When --graph is provided, the writer thread calls NamedNode::new(graph_iri).unwrap() for every
produced triple; an invalid/empty graph IRI will panic the writer thread and abort the transform.
The CLI/config layer stores --graph as an unvalidated Option<String>, so this panic is reachable
via normal user input.
Code

src/lib.rs[R167-170]

Evidence
The --graph argument is parsed as an arbitrary string and stored without validation, then the
writer thread unconditionally unwraps NamedNode::new(...), which panics on invalid IRIs. This
unwrap is executed in the output loop, so a bad --graph value crashes the run.

src/lib.rs[549-565]
src/lib.rs[585-604]
src/lib.rs[165-171]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`--graph` is accepted as a raw string and later converted to a `NamedNode` using `.unwrap()` inside the writer loop. If the user provides an invalid IRI (including `--graph=`), the writer thread panics and the whole transformation fails with a thread panic instead of a clean error.

### Issue Context
- `parse_args()` defines `--graph` as a free-form string.
- `configure_transform()` stores it as `Option<String>` without validation.
- `transform()` converts it to `NamedNode` with `unwrap()` inside the per-triple loop.

### Fix
- Validate and parse `--graph` once (during `configure_transform()` or at the start of `transform()`), returning a normal `Err` with a helpful message if invalid.
- Store the parsed value as `Option<NamedNode>` or `Option<GraphName>` (or precomputed `GraphName`) so the writer loop does not repeatedly parse/clone.
- Replace `unwrap()` in the writer loop with precomputed value usage (or proper error propagation if you keep parsing there).

### Fix Focus Areas
- src/lib.rs[144-190]
- src/lib.rs[549-605]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@qodo-code-review

Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Test Suite

Failed stage: Check formatting [❌]

Failed test name: ""

Failure summary:

The action failed due to a formatting check (likely rustfmt) detecting uncommitted formatting
changes in the PR.
The log shows diffs that rustfmt would apply, and the job exits with code 1:
-
src/lib.rs:183 formatting change to the flush_store(...) call (reformatted multi-line call)
-
tests/main.rs:1059 added a trailing comma after "http://example.org/graph",
- tests/main.rs:1099
indicates additional whitespace/newline formatting changes
Because the formatted output differed
from the committed code, the CI step reported the diff and failed (Process completed with exit code
1).

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

168:  env:
169:  CARGO_TERM_COLOR: always
170:  targets: 
171:  components: rustfmt, clippy
172:  ##[endgroup]
173:  ##[group]Run : set $CARGO_HOME
174:  �[36;1m: set $CARGO_HOME�[0m
175:  �[36;1mecho CARGO_HOME=${CARGO_HOME:-"$HOME/.cargo"} >> $GITHUB_ENV�[0m
176:  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
177:  env:
178:  CARGO_TERM_COLOR: always
179:  ##[endgroup]
180:  ##[group]Run : install rustup if needed
181:  �[36;1m: install rustup if needed�[0m
182:  �[36;1mif ! command -v rustup &>/dev/null; then�[0m
183:  �[36;1m  curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused --location --silent --show-error --fail https://sh.rustup.rs | sh -s -- --default-toolchain none -y�[0m
184:  �[36;1m  echo "$CARGO_HOME/bin" >> $GITHUB_PATH�[0m
...

252:  �[36;1mif [ -z "${CARGO_REGISTRIES_CRATES_IO_PROTOCOL+set}" -o -f "/home/runner/work/_temp"/.implicit_cargo_registries_crates_io_protocol ]; then�[0m
253:  �[36;1m  if rustc +stable --version --verbose | grep -q '^release: 1\.6[89]\.'; then�[0m
254:  �[36;1m    touch "/home/runner/work/_temp"/.implicit_cargo_registries_crates_io_protocol || true�[0m
255:  �[36;1m    echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse >> $GITHUB_ENV�[0m
256:  �[36;1m  elif rustc +stable --version --verbose | grep -q '^release: 1\.6[67]\.'; then�[0m
257:  �[36;1m    touch "/home/runner/work/_temp"/.implicit_cargo_registries_crates_io_protocol || true�[0m
258:  �[36;1m    echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=git >> $GITHUB_ENV�[0m
259:  �[36;1m  fi�[0m
260:  �[36;1mfi�[0m
261:  shell: /usr/bin/bash --noprofile --norc -e -o pipefail {0}
262:  env:
263:  CARGO_TERM_COLOR: always
264:  CARGO_HOME: /home/runner/.cargo
265:  CARGO_INCREMENTAL: 0
266:  ##[endgroup]
267:  ##[group]Run : work around spurious network errors in curl 8.0
268:  �[36;1m: work around spurious network errors in curl 8.0�[0m
269:  �[36;1m# https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/timeout.20investigation�[0m
...

291:  host: x86_64-unknown-linux-gnu
292:  release: 1.96.0
293:  LLVM version: 22.1.2
294:  ##[group]Run taiki-e/install-action@cargo-llvm-cov
295:  with:
296:  tool: cargo-llvm-cov
297:  checksum: true
298:  fallback: cargo-binstall
299:  env:
300:  CARGO_TERM_COLOR: always
301:  CARGO_HOME: /home/runner/.cargo
302:  CARGO_INCREMENTAL: 0
303:  ##[endgroup]
304:  ##[group]Run bail() {
305:  �[36;1mbail() {�[0m
306:  �[36;1m  printf '::error::install-action: %s\n' "$*"�[0m
307:  �[36;1m  exit 1�[0m
...

415:  }
416:  }
417:  Diff in /home/runner/work/oxi-gen/oxi-gen/src/lib.rs:183:
418:  if dedup > 0 && !store.is_empty() {
419:  -                flush_store(&mut store, &mut out_writer, output_format, &prefixes, first_time)
420:  -                    .unwrap();
421:  +                flush_store(
422:  +                    &mut store,
423:  +                    &mut out_writer,
424:  +                    output_format,
425:  +                    &prefixes,
426:  +                    first_time,
427:  +                )
428:  +                .unwrap();
429:  }
430:  out_writer.flush().expect("Error flushing output");
431:  Diff in /home/runner/work/oxi-gen/oxi-gen/src/lib.rs:305:
...

508:  let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
509:  Diff in /home/runner/work/oxi-gen/oxi-gen/tests/main.rs:1059:
510:  "--output",
511:  "STDOUT",
512:  "--graph",
513:  -            "http://example.org/graph"
514:  +            "http://example.org/graph",
515:  ])
516:  .stdin(Stdio::piped())
517:  .stdout(Stdio::piped())
518:  Diff in /home/runner/work/oxi-gen/oxi-gen/tests/main.rs:1099:
519:  triple_count
520:  );
521:  }
522:  +
523:  ##[error]Process completed with exit code 1.
524:  Post job cleanup.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Jun 1, 2026
Comment thread src/lib.rs
Comment on lines +167 to +170
let g = if let Some(ref iri) = graph_name {
NamedNode::new(iri.clone()).unwrap().into()
} else {
GraphName::DefaultGraph

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Graph iri unwrap panic 🐞 Bug ☼ Reliability

When --graph is provided, the writer thread calls NamedNode::new(graph_iri).unwrap() for every
produced triple; an invalid/empty graph IRI will panic the writer thread and abort the transform.
The CLI/config layer stores --graph as an unvalidated Option<String>, so this panic is reachable
via normal user input.
Agent Prompt
### Issue description
`--graph` is accepted as a raw string and later converted to a `NamedNode` using `.unwrap()` inside the writer loop. If the user provides an invalid IRI (including `--graph=`), the writer thread panics and the whole transformation fails with a thread panic instead of a clean error.

### Issue Context
- `parse_args()` defines `--graph` as a free-form string.
- `configure_transform()` stores it as `Option<String>` without validation.
- `transform()` converts it to `NamedNode` with `unwrap()` inside the per-triple loop.

### Fix
- Validate and parse `--graph` once (during `configure_transform()` or at the start of `transform()`), returning a normal `Err` with a helpful message if invalid.
- Store the parsed value as `Option<NamedNode>` or `Option<GraphName>` (or precomputed `GraphName`) so the writer loop does not repeatedly parse/clone.
- Replace `unwrap()` in the writer loop with precomputed value usage (or proper error propagation if you keep parsing there).

### Fix Focus Areas
- src/lib.rs[144-190]
- src/lib.rs[549-605]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread src/lib.rs
.unwrap();
for t in row_triples {
let g = if let Some(ref iri) = graph_name {
NamedNode::new(iri.clone()).unwrap().into()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The graph IRI is parsed with unwrap() inside the writer thread, so an invalid --graph value will panic at runtime instead of returning a normal error. Validate/parse the graph IRI once before spawning workers and propagate a proper Result error instead of panicking. [possible bug]

Severity Level: Major ⚠️
- ❌ Invalid --graph input crashes program instead of failing gracefully.
- ⚠️ Harder to diagnose user errors in graph IRI.
Steps of Reproduction ✅
1. Run the compiled `oxi_gen` binary (`src/main.rs:4-14`) with a `--graph` argument that
is not a valid absolute IRI, for example: `oxi_gen --query
tests/fixtures/optional_field.rq --input tests/fixtures/optional_field.csv --output STDOUT
--graph not-a-valid-iri`.

2. `parse_args` in `src/lib.rs:37-166` defines the `graph` option (lines 158-163) as a
free-form string with no validation, and `configure_transform` (`src/lib.rs:168-205`)
assigns `graph: matches.get_one::<String>("graph").cloned()`, so `OxiGen.graph` becomes
`Some("not-a-valid-iri".to_string())`.

3. Inside `OxiGen::transform` (`src/lib.rs:47-274`), the value is cloned into `graph_name`
at line 140 and moved into the writer thread (spawned at line 144); when triples arrive on
`triple_rx`, the writer computes a graph name with `let g = if let Some(ref iri) =
graph_name { NamedNode::new(iri.clone()).unwrap().into() } else { GraphName::DefaultGraph
};` (`src/lib.rs:167-170`).

4. For the invalid `iri` string, `NamedNode::new(iri.clone())` returns `Err`, and the
`.unwrap()` at line 168 panics inside the writer thread; `transform` later detects this
via `writer_task.join()` and returns `Err("Writer thread panicked".into())`
(`src/lib.rs:258-261`), which causes `main` to panic on
`transform.transform().expect("Transformation failed")` (`src/main.rs:11`), terminating
the process instead of returning a normal, descriptive error about the bad `--graph`
value.

Fix in Cursor | Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/lib.rs
**Line:** 168:168
**Comment:**
	*Possible Bug: The graph IRI is parsed with `unwrap()` inside the writer thread, so an invalid `--graph` value will panic at runtime instead of returning a normal error. Validate/parse the graph IRI once before spawning workers and propagate a proper `Result` error instead of panicking.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@codeant-ai

codeant-ai Bot commented Jun 1, 2026

Copy link
Copy Markdown

CodeAnt AI finished reviewing your PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant