Skip to content

Add DuckDB::TableDescription and DuckDB::ColumnDescription#1287

Merged
suketa merged 3 commits intomainfrom
table_column_description
Apr 13, 2026
Merged

Add DuckDB::TableDescription and DuckDB::ColumnDescription#1287
suketa merged 3 commits intomainfrom
table_column_description

Conversation

@suketa
Copy link
Copy Markdown
Owner

@suketa suketa commented Apr 13, 2026

Summary

  • Add DuckDB::TableDescription to retrieve metadata about a table (column count, names, logical types, and default presence)
  • Add DuckDB::ColumnDescription as an immutable value object describing a column's name, logical type, and whether it has a default value
  • Add document comments to both classes with usage examples
  • Add tests for both classes

Usage

require 'duckdb'
db = DuckDB::Database.open
con = db.connect
con.query("CREATE TABLE users (id INTEGER, name VARCHAR DEFAULT 'anon')")

td = DuckDB::TableDescription.new(con, 'users')
td.column_descriptions.each do |cd|
  puts "\#{cd.name}: \#{cd.logical_type.type}, default=\#{cd.has_default?}"
end
# id: integer, default=false
# name: varchar, default=true

Summary by CodeRabbit

  • New Features
    • Retrieve table metadata with DuckDB::TableDescription—access column names, logical types, and default-value information for any table
    • Access column details via DuckDB::ColumnDescription—an immutable structure containing name, type, and default presence for each column

- Add DuckDB::TableDescription to retrieve metadata about a table
- Add DuckDB::ColumnDescription to describe a column's name, logical type,
  and whether it has a default value
- Add document comments to both classes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

Warning

Rate limit exceeded

@suketa has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 18 minutes and 52 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 18 minutes and 52 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 982b83ce-0c91-4bb9-8b32-61439d76f5de

📥 Commits

Reviewing files that changed from the base of the PR and between 4039d68 and b0ab96a.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • ext/duckdb/duckdb.c
  • ext/duckdb/table_description.c
  • ext/duckdb/table_description.h
  • lib/duckdb/column_description.rb
  • lib/duckdb/table_description.rb
  • test/duckdb_test/column_description_test.rb
  • test/duckdb_test/table_description_test.rb
📝 Walkthrough

Walkthrough

The pull request introduces DuckDB::TableDescription and DuckDB::ColumnDescription classes to retrieve table metadata including column names, logical types, and default value information. Implementation includes C extension bindings, Ruby wrapper classes, initialization hooks, and comprehensive test coverage.

Changes

Cohort / File(s) Summary
Changelog Documentation
CHANGELOG.md
Added entries documenting new DuckDB::TableDescription and DuckDB::ColumnDescription features.
C Extension Header & Init
ext/duckdb/ruby-duckdb.h, ext/duckdb/duckdb.c
Added include directive for table_description header and initialization call to register TableDescription bindings.
C Extension Implementation
ext/duckdb/table_description.h, ext/duckdb/table_description.c
Implemented TableDescription Ruby data type with custom allocation/deallocation, initialization from connection and table identifiers, and private methods for column inspection (name, logical type, default status).
Ruby Wrapper Classes
lib/duckdb.rb, lib/duckdb/table_description.rb, lib/duckdb/column_description.rb
Added library dependencies and implemented Ruby-layer classes: TableDescription validates construction and provides column_descriptions array, ColumnDescription immutable value object with name, logical_type, and has_default attributes.
Test Suite
test/duckdb_test/table_description_test.rb, test/duckdb_test/column_description_test.rb
Comprehensive tests validating table metadata retrieval with various schema/catalog combinations, error handling for invalid inputs, and column description correctness including type and default detection.

Sequence Diagram

sequenceDiagram
    actor User
    participant Ruby as Ruby Layer
    participant C as C Extension
    participant DuckDB as DuckDB Library

    User->>Ruby: TableDescription.new(connection, "table_name")
    Ruby->>Ruby: Validate connection & table name
    Ruby->>C: _initialize(conn, catalog, schema, table)
    C->>DuckDB: duckdb_create_table_description() or variant
    DuckDB-->>C: duckdb_table_description handle
    C-->>Ruby: true (success)
    Ruby-->>User: TableDescription instance

    User->>Ruby: column_descriptions
    loop For each column (0 to column_count-1)
        Ruby->>C: _column_name(idx)
        C->>DuckDB: duckdb_table_description_column_name()
        DuckDB-->>C: C string
        C-->>Ruby: Ruby UTF-8 string
        Ruby->>C: _column_logical_type(idx)
        C->>DuckDB: duckdb_table_description_column_logical_type()
        DuckDB-->>C: duckdb_logical_type
        C-->>Ruby: LogicalType wrapper
        Ruby->>C: _column_has_default(idx)
        C->>DuckDB: duckdb_table_description_column_has_default()
        DuckDB-->>C: boolean result
        C-->>Ruby: boolean
        Ruby->>Ruby: Create ColumnDescription object
    end
    Ruby-->>User: Array of ColumnDescription objects
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hops through table rows with glee,
Metadata dance—column by column spree!
Names and types in harmony align,
Defaults peek from each design,
Table descriptions, now so fine!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main changes: adding two new classes DuckDB::TableDescription and DuckDB::ColumnDescription.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch table_column_description

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
test/duckdb_test/table_description_test.rb (1)

13-15: Make teardown nil-safe to avoid masking setup failures.

If setup fails early, teardown can raise NoMethodError on nil, which can hide the root cause.

🧩 Small resiliency tweak
-    def teardown
-      `@con.close`
-      `@db.close`
-    end
+    def teardown
+      `@con`&.close
+      `@db`&.close
+    end
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/duckdb_test/table_description_test.rb` around lines 13 - 15, The
teardown method may raise NoMethodError if `@con` or `@db` is nil (masking setup
failures); update teardown to be nil-safe by checking/using safe navigation on
the instance variables (e.g., replace direct calls to `@con.close` and `@db.close`
with conditional calls like `@con`&.close and `@db`&.close or explicit if `@con` then
`@con.close` end) so teardown skips closing when those objects weren't created and
does not swallow other exceptions.
lib/duckdb/column_description.rb (1)

15-24: Use block form in the usage example to model safe resource cleanup.

The example currently leaves database/connection lifecycle implicit. Prefer block style in docs to match library best practices.

♻️ Suggested doc example adjustment
-  #   db = DuckDB::Database.open
-  #   con = db.connect
-  #   con.query("CREATE TABLE t (id INTEGER, name VARCHAR DEFAULT 'anon')")
-  #
-  #   td = DuckDB::TableDescription.new(con, 't')
-  #   cd = td.column_descriptions.last
+  #   DuckDB::Database.open do |db|
+  #     db.connect do |con|
+  #       con.query("CREATE TABLE t (id INTEGER, name VARCHAR DEFAULT 'anon')")
+  #       td = DuckDB::TableDescription.new(con, 't')
+  #       cd = td.column_descriptions.last
+  #     end
+  #   end

As per coding guidelines: Use block form (e.g., db.connect { |con| ... }) for automatic resource cleanup.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/duckdb/column_description.rb` around lines 15 - 24, Update the usage
example to use the block form for opening/connecting so resources are cleaned
automatically: replace the implicit open/connect sequence with block-style calls
(e.g., Database.open { |db| db.connect { |con| ... } } or at minimum db.connect
{ |con| ... }) around the CREATE TABLE and TableDescription/ColumnDescription
inspection (references: DuckDB::Database.open, db.connect,
DuckDB::TableDescription.new, ColumnDescription methods like name,
logical_type.type, has_default?) so the example demonstrates safe automatic
resource cleanup.
lib/duckdb/table_description.rb (1)

9-19: Use block-form examples for Database.open / #connect.

These snippets are likely to be copy-pasted, and they currently demonstrate leaving native Database / Connection objects open. Please switch the examples to block form or show explicit cleanup.

As per coding guidelines, "C objects (Database, Connection, PreparedStatement, Appender, Config) must be explicitly destroyed or use block form for automatic cleanup" and "Use block form (e.g., db.connect { |con| ... }) for automatic resource cleanup".

Also applies to: 29-35

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/duckdb/table_description.rb` around lines 9 - 19, Update the README-style
examples to use block form (or explicit destroy) for the C objects so they are
not left open: replace usages of Database.open and db.connect that yield
persistent Database/Connection objects with block forms (e.g., Database.open {
|db| db.connect { |con| ... } } or ensure explicit cleanup) in the examples
around the DuckDB::TableDescription demonstration and the similar snippet later
(the code creating DuckDB::Database, .connect, and passing con into
DuckDB::TableDescription.new). Ensure every Database.open, db.connect, and any
temporary Connection/PreparedStatement/Appender/Config in those examples uses
block form or shows explicit destruction to guarantee automatic resource
cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ext/duckdb/table_description.c`:
- Around line 89-114: The build CI fails because
duckdb_table_description_get_column_count and
duckdb_table_description_get_column_type require a newer DuckDB than the
extconf.rb minimum; update DUCKDB_REQUIRED_VERSION in ext/duckdb/extconf.rb to
"1.5.0" (or the exact patch where those APIs were introduced) so the native
calls in duckdb_table_description__column_count and
duckdb_table_description__column_logical_type are supported, then re-run CI to
confirm the version bump resolves the missing-symbol errors.

In `@ext/duckdb/table_description.h`:
- Line 5: The unguarded use of duckdb_table_description can break builds on
older DuckDB headers; verify which DuckDB version introduced
duckdb_table_description (per your checks it aligns with minimum 1.3.0) and then
either add a compile-time guard around usages of duckdb_table_description (e.g.,
wrap references in `#if/`#endif tied to a new configure-time macro like
HAVE_DUCKDB_TABLE_DESCRIPTION or version check using detected DuckDB version) or
bump the minimum DuckDB version enforced in extconf.rb to the version that first
provides duckdb_table_description and remove/adjust the unguarded usage
accordingly; update extconf.rb to detect the symbol (or version) and define the
macro used in the source so builds fail cleanly on unsupported DuckDB versions.

---

Nitpick comments:
In `@lib/duckdb/column_description.rb`:
- Around line 15-24: Update the usage example to use the block form for
opening/connecting so resources are cleaned automatically: replace the implicit
open/connect sequence with block-style calls (e.g., Database.open { |db|
db.connect { |con| ... } } or at minimum db.connect { |con| ... }) around the
CREATE TABLE and TableDescription/ColumnDescription inspection (references:
DuckDB::Database.open, db.connect, DuckDB::TableDescription.new,
ColumnDescription methods like name, logical_type.type, has_default?) so the
example demonstrates safe automatic resource cleanup.

In `@lib/duckdb/table_description.rb`:
- Around line 9-19: Update the README-style examples to use block form (or
explicit destroy) for the C objects so they are not left open: replace usages of
Database.open and db.connect that yield persistent Database/Connection objects
with block forms (e.g., Database.open { |db| db.connect { |con| ... } } or
ensure explicit cleanup) in the examples around the DuckDB::TableDescription
demonstration and the similar snippet later (the code creating DuckDB::Database,
.connect, and passing con into DuckDB::TableDescription.new). Ensure every
Database.open, db.connect, and any temporary
Connection/PreparedStatement/Appender/Config in those examples uses block form
or shows explicit destruction to guarantee automatic resource cleanup.

In `@test/duckdb_test/table_description_test.rb`:
- Around line 13-15: The teardown method may raise NoMethodError if `@con` or `@db`
is nil (masking setup failures); update teardown to be nil-safe by
checking/using safe navigation on the instance variables (e.g., replace direct
calls to `@con.close` and `@db.close` with conditional calls like `@con`&.close and
`@db`&.close or explicit if `@con` then `@con.close` end) so teardown skips closing
when those objects weren't created and does not swallow other exceptions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 36043d03-c549-4eab-b9b1-51cb53b9afeb

📥 Commits

Reviewing files that changed from the base of the PR and between d72b911 and 4039d68.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • ext/duckdb/duckdb.c
  • ext/duckdb/ruby-duckdb.h
  • ext/duckdb/table_description.c
  • ext/duckdb/table_description.h
  • lib/duckdb.rb
  • lib/duckdb/column_description.rb
  • lib/duckdb/table_description.rb
  • test/duckdb_test/column_description_test.rb
  • test/duckdb_test/table_description_test.rb

suketa and others added 2 commits April 13, 2026 21:39
- Move #include "ruby-duckdb.h" before #ifdef in table_description.c so
  HAVE_DUCKDB_H_GE_V1_5_0 is defined before the guard is evaluated
- Wrap struct/typedef/declaration in table_description.h with
  #ifdef HAVE_DUCKDB_H_GE_V1_5_0
- Wrap Ruby class bodies in `if defined?(DuckDB::TableDescription)` so
  they are only opened when the C extension registered them

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@suketa suketa merged commit 0c5d641 into main Apr 13, 2026
41 checks passed
@suketa suketa deleted the table_column_description branch April 13, 2026 12:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant