Skip to content

feat: add non-secure variant nanoid_non_secure() #21#25

Closed
nik-sta wants to merge 5 commits into
feat/18-nanoid-prefixfrom
feat/21-nanoid-non-secure
Closed

feat: add non-secure variant nanoid_non_secure() #21#25
nik-sta wants to merge 5 commits into
feat/18-nanoid-prefixfrom
feat/21-nanoid-non-secure

Conversation

@nik-sta

@nik-sta nik-sta commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary

Ports the nanoid/non-secure module of the original JavaScript library. nanoid_non_secure(size, alphabet) generates ids from PostgreSQL's built-in random(), so it works without the pgcrypto extension and benchmarks about 2.4 times faster than nanoid() (100k default ids on PostgreSQL 17: 0.63s vs 1.49s). The ids are predictable; the README section documents the variant with a clear warning against security-relevant use.

The function is declared PARALLEL UNSAFE for the same reason as nanoid() (#16). PARALLEL RESTRICTED is not sufficient: the added regression test (the #16 CTAS shape over nanoid_non_secure()) fails with "cannot start commands during a parallel operation" under a RESTRICTED declaration and passes with UNSAFE.

Verification

Closes #21

Summary by CodeRabbit

  • New Features

    • Added nanoid_non_secure() to generate IDs using a non-cryptographic random source.
    • Supports configurable length and character alphabet, with validation for invalid inputs.
  • Documentation

    • Documented the nanoid_non_secure() “non-secure variant,” including performance notes, predictability considerations, and recommended/non-recommended use cases and examples.
  • Tests

    • Added unit tests covering defaults, custom lengths/alphabets (including multi-byte characters), edge cases, and input validation.
    • Added a regression test that generates and validates 50,000 non-secure IDs end-to-end.

@nik-sta nik-sta added enhancement New feature or request performance Improves speed or resource usage upstream-parity Tracks feature parity with the original ai/nanoid library labels Jul 13, 2026
@nik-sta
nik-sta force-pushed the feat/21-nanoid-non-secure branch from 3a6d759 to 1825b39 Compare July 13, 2026 20:08
@nik-sta
nik-sta changed the base branch from main to feat/18-nanoid-prefix July 13, 2026 20:08
@nik-sta
nik-sta force-pushed the feat/21-nanoid-non-secure branch from 1825b39 to 4a15c8d Compare July 13, 2026 20:35
@nik-sta
nik-sta force-pushed the feat/18-nanoid-prefix branch from 23364e1 to 080212a Compare July 13, 2026 20:35
@nik-sta

nik-sta commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • main

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bbcd71dd-92e5-4b96-9bc0-a839facb7ea5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds nanoid_non_secure() using PostgreSQL random(), documents its non-secure behavior and signature, and adds unit and regression tests for default, custom, and CTAS-generated identifiers.

Changes

Non-secure Nano ID

Layer / File(s) Summary
Generator implementation and public documentation
nanoid.sql, README.md
Defines nanoid_non_secure() with size and alphabet validation, random character generation, default parameters, usage examples, and security warnings.
Generator regression and unit coverage
dev/test/unit_tests.sql, dev/test/regression_tests.sql
Validates default, custom, multibyte, single-symbol, and invalid inputs, plus 50,000-row CTAS generation, identifier length, and cleanup.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding the non-secure nanoid_non_secure() variant.
Linked Issues check ✅ Passed The PR appears to meet #21: it adds nanoid_non_secure(), uses random(), avoids pgcrypto, is PARALLEL UNSAFE, warns in the README, and adds the requested tests.
Out of Scope Changes check ✅ Passed The changes stay focused on the requested non-secure nanoid variant, its documentation, and its tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/21-nanoid-non-secure

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
dev/test/unit_tests.sql (1)

144-161: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add negative-path coverage for nanoid_non_secure's validation.

The happy-path tests look correct, but the new size/alphabet validation in nanoid.sql (lines 151-157) has no test exercising the rejection branches, unlike the analogous exception coverage that exists for nanoid() elsewhere in this file.

✅ Suggested addition
-- Non-secure variant: invalid size and alphabet are rejected
BEGIN
    PERFORM nanoid_non_secure(0);
    ASSERT FALSE, 'Size 0 was not rejected for nanoid_non_secure';
EXCEPTION
    WHEN assert_failure THEN RAISE;
    WHEN raise_exception THEN NULL; -- expected rejection
END;

BEGIN
    PERFORM nanoid_non_secure(21, '');
    ASSERT FALSE, 'Empty alphabet was not rejected for nanoid_non_secure';
EXCEPTION
    WHEN assert_failure THEN RAISE;
    WHEN raise_exception THEN NULL; -- expected rejection
END;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dev/test/unit_tests.sql` around lines 144 - 161, Add negative-path tests
alongside the existing nanoid_non_secure cases to verify its validation rejects
size 0 and an empty alphabet. Use separate exception-handling blocks around
nanoid_non_secure calls, fail the test if no exception occurs, and re-raise
assertion failures while accepting the expected validation exception.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@dev/test/unit_tests.sql`:
- Around line 144-161: Add negative-path tests alongside the existing
nanoid_non_secure cases to verify its validation rejects size 0 and an empty
alphabet. Use separate exception-handling blocks around nanoid_non_secure calls,
fail the test if no exception occurs, and re-raise assertion failures while
accepting the expected validation exception.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1597b7d5-835e-4bb7-aac9-52cf4a5b0ec2

📥 Commits

Reviewing files that changed from the base of the PR and between 080212a and 4a15c8d.

📒 Files selected for processing (4)
  • README.md
  • dev/test/regression_tests.sql
  • dev/test/unit_tests.sql
  • nanoid.sql

@nik-sta

nik-sta commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai Added the negative-path tests in dev/test/unit_tests.sql: size 0 and an empty alphabet are now asserted to be rejected by nanoid_non_secure(), using the same exception-block pattern as the existing over-256-symbol rejection test for nanoid(). Verified green on all supported PostgreSQL versions (9.6 through 18).

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd unit_tests.sql
echo "---"
rg -n "nanoid_non_secure" dev/test/unit_tests.sql -A5 -B2

Length of output: 1993


The negative-path tests look correct — matching the existing exception-block pattern used for the over-256-symbol rejection test on nanoid(), and covering both the size-0 and empty-alphabet rejection cases for nanoid_non_secure(). Thanks for confirming green runs across PostgreSQL 9.6 through 18.

nik-sta added 3 commits July 14, 2026 00:32
Port the nanoid/non-secure module of the original JavaScript library.
nanoid_non_secure() uses PostgreSQL's built-in random() generator, so it
works without the pgcrypto extension and generates IDs about 2.4 times
faster than nanoid() (benchmark: 100k default IDs on PostgreSQL 17,
0.63s vs 1.49s). The generated IDs are predictable; the README documents
that it must not be used for security-relevant identifiers.

The function is declared PARALLEL UNSAFE like nanoid() and
nanoid_optimized(): PL/pgSQL advances the command counter and takes new
snapshots when evaluating volatile expressions, which is forbidden in
parallel mode (issue #16). PARALLEL RESTRICTED is not enough, verified
by the added regression test that runs the issue #16 CTAS shape over
nanoid_non_secure().
The full nanoid.sql still creates the pgcrypto extension for nanoid(), so
the README now explains how to get nanoid_non_secure() on a host without
pgcrypto. Adds unit tests for multi-byte and single-symbol alphabets on the
non-secure variant.
@nik-sta
nik-sta force-pushed the feat/18-nanoid-prefix branch from 080212a to b9c3b58 Compare July 13, 2026 22:38
@nik-sta
nik-sta force-pushed the feat/21-nanoid-non-secure branch from 83f00d9 to 99ddbe7 Compare July 13, 2026 22:38
@nik-sta

nik-sta commented Jul 14, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nik-sta

nik-sta commented Jul 14, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


You're currently rate limited under our Fair Usage Limits Policy. Your recent PR review activity is in the 95th percentile or higher among CodeRabbit users, so adaptive limits apply. Your next review will be available in 8 minutes.

@nik-sta

nik-sta commented Jul 14, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@nik-sta

nik-sta commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

Closing unmerged. We decided not to port the non-secure variant: there is no current use case that justifies it in this port. Can be revisited if a concrete need comes up.

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

Labels

enhancement New feature or request performance Improves speed or resource usage upstream-parity Tracks feature parity with the original ai/nanoid library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add non-secure variant nanoid_non_secure() without pgcrypto dependency

1 participant