Inflector DuckDB Extension

The Inflector extension, developed by Query.Farm, brings powerful string case transformation and inflection capabilities directly to your SQL queries in DuckDB. Transform column names, validate naming conventions, handle pluralization, and moreโ€”all without leaving your database environment.

Whether youโ€™re normalizing API responses, migrating schemas between naming conventions, or ensuring consistent data formatting, Inflector makes string manipulation in SQL simple and efficient.

Use Cases

The Inflector extension is perfect for:

  • Data normalization: Standardize column names and values to a consistent case style
  • ETL pipelines: Transform and clean data during ingestion or export
  • API and report generation: Match naming conventions for downstream systems
  • Schema migration: Convert between naming conventions (snake_case, camelCase, etc.)
  • Data validation: Check if strings conform to required case or format
  • Pluralization/Singularization: Automatically convert between singular and plural forms
  • Foreign key and module name handling: Generate or validate foreign key names and Ruby-style module paths

Installation

inflector is a DuckDB Community Extension.

You can install and load it with:

INSTALL inflector FROM community;
LOAD inflector;

Quick Start

-- Install and load the extension
INSTALL inflector FROM community;
LOAD inflector;

-- Transform a single string
SELECT inflector_to_camel_case('hello_world');  -- helloWorld

-- Transform all column names in a struct
SELECT inflect('snake', {'firstName': 'John', 'lastName': 'Doe'});
-- {'first_name': John, 'last_name': Doe}

-- Transform all column names from a table or query
SELECT * FROM inflect('kebab', read_csv('data.csv'));

Functions

Case Transformation Functions

Transform a string to a specific case style:

  • inflector_to_class_case(str) โ†’ ClassCase
  • inflector_to_camel_case(str) โ†’ camelCase
  • inflector_to_pascal_case(str) โ†’ PascalCase
  • inflector_to_screamingsnake_case(str) โ†’ SCREAMING_SNAKE_CASE
  • inflector_to_snake_case(str) โ†’ snake_case
  • inflector_to_kebab_case(str) โ†’ kebab-case
  • inflector_to_train_case(str) โ†’ Train-Case
  • inflector_to_sentence_case(str) โ†’ Sentence case
  • inflector_to_title_case(str) โ†’ Title Case
  • inflector_to_table_case(str) โ†’ table_names
  • inflector_to_upper_case(str) โ†’ UPPERCASE
  • inflector_to_lower_case(str) โ†’ lowercase

Examples:

SELECT inflector_to_camel_case('hello_world') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚     v      โ”‚
โ”‚  varchar   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ helloWorld โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

SELECT inflector_to_snake_case('HelloWorld') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚      v      โ”‚
โ”‚   varchar   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ hello_world โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

SELECT inflector_to_title_case('hello_world') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚      v      โ”‚
โ”‚   varchar   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Hello World โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Pluralization and Singularization

  • inflector_to_plural(str) โ†’ plural form
  • inflector_to_singular(str) โ†’ singular form
SELECT inflector_to_plural('person') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    v    โ”‚
โ”‚ varchar โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ people  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

SELECT inflector_to_singular('ducks') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    v    โ”‚
โ”‚ varchar โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ duck    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Ordinalization

  • inflector_ordinalize(str) โ†’ ordinal string (e.g., 1st, 2nd)
  • inflector_deordinalize(str) โ†’ number string (e.g., 1st โ†’ 1)
SELECT inflector_ordinalize('5') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    v    โ”‚
โ”‚ varchar โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 5th     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

SELECT inflector_deordinalize('21st') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    v    โ”‚
โ”‚ varchar โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 21      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Foreign Key and Module Functions

  • inflector_to_foreign_key(str) โ†’ foreign key name (e.g., User โ†’ user_id)
  • inflector_demodulize(str) โ†’ last module/class name (e.g., A::B::C โ†’ C)
  • inflector_deconstantize(str) โ†’ parent module path (e.g., A::B::C โ†’ A::B)
SELECT inflector_to_foreign_key('User') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    v    โ”‚
โ”‚ varchar โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ user_id โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

SELECT inflector_demodulize('ActiveRecord::CoreExtensions::String::Inflections') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚     v      โ”‚
โ”‚  varchar   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Inflection โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

SELECT inflector_deconstantize('ActiveRecord::CoreExtensions::String::Inflections') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    v    โ”‚
โ”‚ varchar โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ String  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Predicate Functions

Check if a string matches a specific case or format:

  • inflector_is_class_case(str)
  • inflector_is_camel_case(str)
  • inflector_is_pascal_case(str)
  • inflector_is_screamingsnake_case(str)
  • inflector_is_snake_case(str)
  • inflector_is_kebab_case(str)
  • inflector_is_train_case(str)
  • inflector_is_sentence_case(str)
  • inflector_is_title_case(str)
  • inflector_is_table_case(str)
  • inflector_is_foreign_key(str)

Returns true or false.

Examples:

SELECT inflector_is_snake_case('hello_world') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    v    โ”‚
โ”‚ boolean โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ true    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

SELECT inflector_is_camel_case('HelloWorld') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    v    โ”‚
โ”‚ boolean โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ false   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

SELECT inflector_is_foreign_key('user_id') as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    v    โ”‚
โ”‚ boolean โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ true    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Struct and Table Column Inflection

The inflect() function is the most powerful feature, allowing you to transform all column names in a struct or table result at once.

Inflect the keys of a STRUCT or tableโ€™s column names to a target case style:

Syntax:

inflect('case_style', struct_or_table)

Supported case styles:

  • 'camel' / 'camel_case' โ†’ camelCase
  • 'class' / 'class_case' โ†’ ClassCase
  • 'snake' / 'snake_case' โ†’ snake_case
  • 'kebab' / 'kebab_case' โ†’ kebab-case
  • 'train' / 'train_case' โ†’ Train-Case
  • 'title' / 'title_case' โ†’ Title Case
  • 'table' / 'table_case' โ†’ table_names (pluralized snake_case)
  • 'sentence' / 'sentence_case' โ†’ Sentence case
  • 'upper' / 'upper_case' โ†’ UPPERCASE
  • 'lower' / 'lower_case' โ†’ lowercase

Examples:

SELECT inflect('snake', {'firstName': 1, 'lastName': 2}) as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                       v                       โ”‚
โ”‚ struct(first_name integer, last_name integer) โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ {'first_name': 1, 'last_name': 2}             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

SELECT inflect('class', {'first_name': 1, 'last_name': 2}) as v;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                      v                      โ”‚
โ”‚ struct(firstname integer, lastname integer) โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ {'FirstName': 1, 'LastName': 2}             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

-- Table returning function.
SELECT n FROM inflect('camel', (SELECT 1 AS counterValue, 't' AS first_name)) AS n;
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                        n                        โ”‚
โ”‚ struct(countervalue integer, firstname varchar) โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ {'counterValue': 1, 'firstName': t}             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Real-World Examples

Normalize CSV Column Names

-- Convert PascalCase CSV headers to snake_case
SELECT * FROM inflect('snake', read_csv('UserData.csv'));
-- FirstName, LastName, EmailAddress โ†’ first_name, last_name, email_address

Transform API Response Data

-- Convert camelCase JSON keys to snake_case for database storage
CREATE TABLE users AS
SELECT * FROM inflect('snake',
  read_json('api_response.json')
);

Validate Naming Conventions

-- Check if all column names follow snake_case convention
SELECT
  column_name,
  inflector_is_snake_case(column_name) as is_valid
FROM information_schema.columns
WHERE table_name = 'my_table';

Schema Migration Between Conventions

-- Convert a Ruby on Rails style table to JavaScript convention
CREATE TABLE users_camel AS
SELECT * FROM inflect('camel', users);

Generate Foreign Key Names

-- Create foreign key column names from table names
SELECT
  table_name,
  inflector_to_foreign_key(table_name) as fk_column
FROM information_schema.tables;

Pluralize Table Names

-- Ensure all table names are plural
SELECT
  table_name,
  inflector_to_plural(table_name) as plural_name
FROM information_schema.tables;

Clean and Standardize Text Data

-- Standardize mixed-case product categories
UPDATE products
SET category = inflector_to_title_case(category);

Generate Display Labels

-- Convert snake_case column names to human-readable titles
SELECT
  'first_name' as column,
  inflector_to_title_case('first_name') as label;  -- First Name

Advanced Usage

Nested Struct Transformation

-- Inflect nested struct keys recursively
SELECT inflect('camel', {
  'user_info': {
    'first_name': 'John',
    'last_name': 'Doe'
  }
}) as result;

Bulk Column Validation

-- Find all columns that don't follow snake_case
WITH column_check AS (
  SELECT
    table_name,
    column_name,
    inflector_is_snake_case(column_name) as is_snake_case
  FROM information_schema.columns
)
SELECT * FROM column_check WHERE NOT is_snake_case;

Data Pipeline Transformation

SELECT * FROM inflect('snake', read_csv('example.csv'));

Performance Considerations

  • Transformation functions are highly optimized and work efficiently on large datasets
  • The inflect() function operates on column metadata, not data, making it very fast
  • Predicate functions can be used in WHERE clauses and are optimized for filtering

Tips and Best Practices

  1. Use the right case for your project: Consistent naming improves maintainability and reduces errors
  2. Validate data early: Use predicate functions in data quality checks during ETL
  3. Automate schema migrations: Use inflect() to convert column names in bulk rather than manual renaming
  4. Combine with DuckDBโ€™s JSON/struct features: Inflect nested data structures from APIs and config files
  5. Standardize imports: Apply inflection when reading external data (CSV, JSON, Parquet)
  6. Use table_case for database tables: Automatically pluralizes and converts to snake_case
  7. Document your conventions: Choose a case style and stick with it across your project

Error Handling

The extension provides clear error messages for common issues:

-- Unknown case style
SELECT inflect('unknown', {'foo': 1});
-- Error: Unknown inflection 'unknown'. Supported: camel, class, snake, kebab, train, title, table, sentence, upper, lower

-- Invalid arguments
SELECT inflect('snake');
-- Error: inflect() requires exactly two arguments: function name and value to inflect

Frequently Asked Questions

Q: Whatโ€™s the difference between class_case and pascal_case?

A: Theyโ€™re the same! Both produce PascalCase output.

Q: Can I use inflect() on a table with millions of rows?

A: Yes! The inflect() function only transforms column names, not the data itself, so itโ€™s extremely fast regardless of table size.

Q: Does table_case always pluralize?

A: Yes, table_case converts to snake_case and pluralizes the name (e.g., User โ†’ users).

Q: Can I chain transformations?

A: Yes! You can nest inflect() calls or pipe results through multiple transformations.

Contributing

The Inflector extension is open source and developed by Query.Farm.

License

MIT License

Love โค๏ธ this DuckDB extension? Youโ€™ll Love This.

Get the best from Query.Farm โ€” smart tips, powerful tools, and project updates sent directly to your inbox, but only when weโ€™ve got something great to share.