-
-
Notifications
You must be signed in to change notification settings - Fork 14
feat: add kysely postgres adapter #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add kysely postgres adapter #15
Conversation
|
Caution Review failedThe pull request is closed. Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a Kysely-based PostgreSQL storage adapter and tests, updates package/build/docker/CI configs to include Kysely (and separate DB services for Kysely/Drizzle/Prisma), exposes the adapter via package exports with an optional Kysely dependency, and adjusts existing test DB endpoints and cleanup logic. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant KyselyStore
participant Kysely
participant Postgres
rect rgb(235,245,255)
Client->>KyselyStore: save(record)
KyselyStore->>Kysely: insert row (toRow)
Kysely->>Postgres: INSERT INTO apikey
Postgres-->>Kysely: OK
Kysely-->>KyselyStore: result
KyselyStore-->>Client: void
end
rect rgb(245,255,235)
Client->>KyselyStore: findByTags(tags, ownerId?)
KyselyStore->>Kysely: SELECT WHERE metadata @> {...} OR tags match
Kysely->>Postgres: SELECT ... JSONB containment
Postgres-->>Kysely: rows[]
Kysely-->>KyselyStore: rows[]
KyselyStore->>Client: ApiKeyRecord[]
end
rect rgb(255,245,235)
Client->>KyselyStore: updateMetadata(id, partialMetadata)
KyselyStore->>Kysely: SELECT by id (existence)
Kysely->>Postgres: SELECT
alt exists
KyselyStore->>Kysely: UPDATE metadata = merged
Kysely->>Postgres: UPDATE
Postgres-->>Kysely: OK
KyselyStore-->>Client: void
else not found
KyselyStore-->>Client: Error (not found)
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (9)
package.json (1)
74-74: Use bun test instead of vitest for the Kysely test scriptPer project rules, prefer Bun’s test runner.
As per coding guidelines / Based on learnings
- "test:kysely": "vitest run src/storage/kysely.test.ts", + "test:kysely": "bun test src/storage/kysely.test.ts",src/storage/kysely.ts (1)
99-109: Add a GIN index on metadata for JSONB containment queries
metadata @> ...benefits significantly from a GIN index for owner/tag scans.Optionally document/ensure:
CREATE INDEX IF NOT EXISTS apikey_metadata_gin_idx ON apikey USING GIN (metadata jsonb_path_ops);or without
jsonb_path_opsdepending on query mix.src/storage/kysely.test.ts (7)
3-3: Use Bun’s test runner instead of VitestSwitch imports to
"bun:test"to align with project rules.As per coding guidelines / Based on learnings
-import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest"; +import { afterAll, afterEach, beforeAll, describe, expect, it } from "bun:test";
23-27: Skip the suite when DATABASE_URL is missing (avoid failing locally/CI without Postgres)Gate
describeto skip cleanly instead of warning/throwing later.-describe("KyselyStore", () => { +const describePg = process.env.DATABASE_URL ? describe : describe.skip; +describePg("KyselyStore", () => {As per coding guidelines (don’t use console).
36-44: Remove console.warn and avoid throwing in setup for “skipped” runsWith the gated describe above, this try/catch and console usage can be dropped.
- try { - await pool.query("SELECT 1"); - } catch (error) { - console.warn( - "PostgreSQL not available. Skipping Kysely tests. Start with: docker-compose up postgres" - ); - throw error; - } + await pool.query("SELECT 1");
57-64: Drop redundant non-unique index; keep only the UNIQUE index on key_hashThe unique index already provides an index on
key_hash; maintaining both increases write overhead.- await sql` - CREATE INDEX IF NOT EXISTS apikey_key_hash_idx ON apikey(key_hash) - `.execute(db); - await sql` CREATE UNIQUE INDEX IF NOT EXISTS apikey_key_hash_unique ON apikey(key_hash) `.execute(db);
624-639: Avoid awaiting sequentially in loops; parallelize to speed up testsThis block can run in parallel safely.
- const longDescription = "A".repeat(LONG_DESCRIPTION_LENGTH); - - const { key, record } = await keys.create({ - ownerId: "user_long_description", - description: longDescription, - }); + const longDescription = "A".repeat(LONG_DESCRIPTION_LENGTH); + const { key, record } = await keys.create({ + ownerId: "user_long_description", + description: longDescription, + });And for other places like Lines 645-651 and 1194-1199, batch with
Promise.all(...)instead offor/awaitloops to reduce test time. As per coding guidelines.
198-201: Prefer at() over bracket indexing for arraysUse
.at(0)for clarity and to follow local rules.Examples:
- expect(found[0]?.id).toBe(record.id); + expect(found.at(0)?.id).toBe(record.id);As per coding guidelines.
Also applies to: 232-235, 248-251
1-2: Consider replacing pg with a Bun-compatible approach (future work)Guidelines prefer Bun.sql over
pg/postgres.js. Kysely’s PostgresDialect typically usespgorpostgres—evaluate a Bun-compatible dialect (e.g., community Bun dialect for Kysely) or an adapter over Bun.sql in a follow-up.If you want, I can draft a spike plan to prototype a Bun.sql-backed Kysely dialect and migration steps.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (3)
package.json(3 hunks)src/storage/kysely.test.ts(1 hunks)src/storage/kysely.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
{**/*.{ts,tsx,js,jsx},package.json}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
{**/*.{ts,tsx,js,jsx},package.json}: Usebun <file>instead ofnode <file>orts-node <file>
UseBun.serve()for HTTP/WebSocket servers; do not useexpress
Usebun:sqlitefor SQLite; do not usebetter-sqlite3
UseBun.redisfor Redis; do not useioredis
UseBun.sqlfor Postgres; do not usepgorpostgres.js
Use the built-inWebSocket; do not usews
UseBun.$shell (e.g., Bun.$ls) instead ofexeca
Files:
package.jsonsrc/storage/kysely.test.tssrc/storage/kysely.ts
{**/*.test.{ts,tsx,js,jsx},package.json}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
{**/*.test.{ts,tsx,js,jsx},package.json}: Usebun testinstead ofjestorvitest
Usebun testto run tests
Files:
package.jsonsrc/storage/kysely.test.ts
{**/*.{html,ts,css},package.json}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file.html|file.ts|file.css>instead ofwebpackoresbuild
Files:
package.jsonsrc/storage/kysely.test.tssrc/storage/kysely.ts
package.json
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
package.json: Usebun installinstead ofnpm install,yarn install, orpnpm install
Usebun run <script>instead ofnpm run <script>,yarn run <script>, orpnpm run <script>
Files:
package.json
{**/*.html,package.json}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()for frontend; do not usevite
Files:
package.json
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{ts,tsx,js,jsx}: Don't use consecutive spaces in regular expression literals
Don't use the comma operator
Avoid functions exceeding configured Cognitive Complexity
Don't use unnecessary boolean casts
Don't use unnecessary callbacks with flatMap
Prefer for...of statements over Array.forEach
Don't create classes that only have static members
Don't use this and super in static contexts
Don't use unnecessary catch clauses
Don't use unnecessary constructors
Don't use unnecessary continue statements
Don't export empty modules
Don't use unnecessary escape sequences in regex literals
Don't use unnecessary labels
Don't use unnecessary nested block statements
Don't rename imports/exports/destructured assignments to the same name
Avoid unnecessary string or template literal concatenation
Don't use String.raw in template literals without escapes
Don't use useless case statements in switch
Avoid ternary operators when simpler alternatives exist
Don't use useless this aliasing
Don't initialize variables to undefined
Don't use the void operator
Prefer arrow functions over function expressions
Use Date.now() for epoch milliseconds
Prefer .flatMap() over map().flat() when possible
Use literal property access instead of computed when possible
Don't use parseInt/Number.parseInt for binary, octal, or hex literals
Use optional chaining instead of chained logical expressions
Prefer regex literals over RegExp constructor when possible
Don't use non-decimal or underscored number literal member names
Remove redundant terms from logical expressions
Use while loops when for initial/update are not needed
Don't reassign const variables
Don't use constant expressions in conditions
Avoid Math.min/Math.max to clamp when result is constant
Don't return a value from a constructor
Don't use empty character classes in regex literals
Don't use empty destructuring patterns
Don't call global object properties as functions
Don't declare functions/vars that escape their block (use block scoping prop...
Files:
src/storage/kysely.test.tssrc/storage/kysely.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{ts,tsx}: Don't use the arguments object
Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use any or unknown as type constraints
Don't return a value from a function with return type void
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables/params/class properties initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with ! postfix
Don't use parameter properties in class constructors
Don't use user-defined types (type aliases) where discouraged
Prefer as const over literal types/type annotations for literals
Use either T[] or Array consistently
Initialize each enum member value explicitly
Use export type for types
Use import type for types
Ensure all enum members are literal values
Don't use const enum
Don't declare empty interfaces
Don't let variables evolve into any through reassignments
Don't use the any type
Don't misuse non-null assertion operator in TS files
Don't use implicit any in variable declarations
Don't merge interfaces and classes unsafely
Place overload signatures adjacent to each other
Use namespace keyword instead of module to declare TS namespaces
Don't use void type outside generics or return types
Files:
src/storage/kysely.test.tssrc/storage/kysely.ts
**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Ensure assertions (e.g., expect) are placed inside an it() call
Don't use disabled tests
Files:
src/storage/kysely.test.ts
**/*.{jsx,tsx,js,ts}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx,js,ts}: Ensure preconnect is used with Google Fonts
Use a recommended display strategy with Google Fonts
Files:
src/storage/kysely.test.tssrc/storage/kysely.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
Don't import next/document outside of pages/_document.jsx
Files:
src/storage/kysely.test.tssrc/storage/kysely.ts
🧠 Learnings (2)
📚 Learning: 2025-10-25T11:54:06.273Z
Learnt from: CR
PR: izadoesdev/keypal#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-10-25T11:54:06.273Z
Learning: Applies to {**/*.test.{ts,tsx,js,jsx},package.json} : Use `bun test` instead of `jest` or `vitest`
Applied to files:
package.json
📚 Learning: 2025-10-25T11:54:06.273Z
Learnt from: CR
PR: izadoesdev/keypal#0
File: .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc:0-0
Timestamp: 2025-10-25T11:54:06.273Z
Learning: Applies to {**/*.test.{ts,tsx,js,jsx},package.json} : Use `bun test` to run tests
Applied to files:
package.json
🧬 Code graph analysis (1)
src/storage/kysely.test.ts (1)
src/storage/kysely.ts (2)
ApiKeysDatabase(8-14)KyselyStore(39-176)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: cubic · AI code reviewer
🔇 Additional comments (2)
package.json (2)
35-39: Export entry for Kysely looks goodPaths align with dist layout used by other storage adapters.
112-114: Optional dependency additions look fineAdding "@prisma/client" and "kysely" as optional aligns with pluggable storage approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 4 files
Prompt for AI agents (all 1 issues)
Understand the root cause of the following 1 issues and fix them.
<file name="src/storage/kysely.ts">
<violation number="1" location="src/storage/kysely.ts:127">
The OR clause for tag filters wraps each `metadata @> …` condition in `IS NOT NULL`, so the predicate always evaluates to true and the query returns every API key instead of filtering by the requested tags.</violation>
</file>
Since this is your first cubic review, here's how it works:
- cubic automatically reviews your code and comments on bugs and improvements
- Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
- Ask questions if you need clarification on any suggestion
React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.
src/storage/kysely.ts
Outdated
|
|
||
| // biome-ignore lint/suspicious/noExplicitAny: Kysely or/eb types are complex | ||
| query = query.where(({ or, eb }: any) => | ||
| or(tagConditions.map((condition: any) => eb(condition, "is not", null))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The OR clause for tag filters wraps each metadata @> … condition in IS NOT NULL, so the predicate always evaluates to true and the query returns every API key instead of filtering by the requested tags.
Prompt for AI agents
Address the following comment on src/storage/kysely.ts at line 127:
<comment>The OR clause for tag filters wraps each `metadata @> …` condition in `IS NOT NULL`, so the predicate always evaluates to true and the query returns every API key instead of filtering by the requested tags.</comment>
<file context>
@@ -0,0 +1,177 @@
+
+ // biome-ignore lint/suspicious/noExplicitAny: Kysely or/eb types are complex
+ query = query.where(({ or, eb }: any) =>
+ or(tagConditions.map((condition: any) => eb(condition, "is not", null)))
+ );
+ }
</file context>
✅ Addressed in c2d2014
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/storage/kysely.test.ts (1)
1176-1176: Consider avoiding empty string fallback in test assertions.Using
|| ""as a fallback whenrecords[i]?.idis undefined passes an empty string to methods that expect valid IDs. While safe (returns null), this pattern could mask test logic issues.Consider using more explicit guards:
-const updated = await store.findById(records[0]?.id || ""); +const record = records[0]; +expect(record).toBeDefined(); +const updated = await store.findById(record!.id);-store.delete(records[i]?.id || "") +const record = records[i]; +if (!record) throw new Error("Record not found"); +store.delete(record.id)Also applies to: 1182-1182
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc(0 hunks).github/workflows/test.yml(2 hunks)FEATURE_SUGGESTIONS.md(1 hunks)build.config.ts(2 hunks)docker-compose.yml(2 hunks)src/storage/drizzle.test.ts(1 hunks)src/storage/kysely.test.ts(1 hunks)src/storage/kysely.ts(1 hunks)src/storage/prisma.test.ts(2 hunks)
💤 Files with no reviewable changes (1)
- .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{ts,tsx,js,jsx}: Don't use consecutive spaces in regular expression literals
Don't use the comma operator
Avoid functions exceeding configured Cognitive Complexity
Don't use unnecessary boolean casts
Don't use unnecessary callbacks with flatMap
Prefer for...of statements over Array.forEach
Don't create classes that only have static members
Don't use this and super in static contexts
Don't use unnecessary catch clauses
Don't use unnecessary constructors
Don't use unnecessary continue statements
Don't export empty modules
Don't use unnecessary escape sequences in regex literals
Don't use unnecessary labels
Don't use unnecessary nested block statements
Don't rename imports/exports/destructured assignments to the same name
Avoid unnecessary string or template literal concatenation
Don't use String.raw in template literals without escapes
Don't use useless case statements in switch
Avoid ternary operators when simpler alternatives exist
Don't use useless this aliasing
Don't initialize variables to undefined
Don't use the void operator
Prefer arrow functions over function expressions
Use Date.now() for epoch milliseconds
Prefer .flatMap() over map().flat() when possible
Use literal property access instead of computed when possible
Don't use parseInt/Number.parseInt for binary, octal, or hex literals
Use optional chaining instead of chained logical expressions
Prefer regex literals over RegExp constructor when possible
Don't use non-decimal or underscored number literal member names
Remove redundant terms from logical expressions
Use while loops when for initial/update are not needed
Don't reassign const variables
Don't use constant expressions in conditions
Avoid Math.min/Math.max to clamp when result is constant
Don't return a value from a constructor
Don't use empty character classes in regex literals
Don't use empty destructuring patterns
Don't call global object properties as functions
Don't declare functions/vars that escape their block (use block scoping prop...
Files:
src/storage/prisma.test.tssrc/storage/drizzle.test.tssrc/storage/kysely.test.tssrc/storage/kysely.tsbuild.config.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{ts,tsx}: Don't use the arguments object
Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use any or unknown as type constraints
Don't return a value from a function with return type void
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables/params/class properties initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with ! postfix
Don't use parameter properties in class constructors
Don't use user-defined types (type aliases) where discouraged
Prefer as const over literal types/type annotations for literals
Use either T[] or Array consistently
Initialize each enum member value explicitly
Use export type for types
Use import type for types
Ensure all enum members are literal values
Don't use const enum
Don't declare empty interfaces
Don't let variables evolve into any through reassignments
Don't use the any type
Don't misuse non-null assertion operator in TS files
Don't use implicit any in variable declarations
Don't merge interfaces and classes unsafely
Place overload signatures adjacent to each other
Use namespace keyword instead of module to declare TS namespaces
Don't use void type outside generics or return types
Files:
src/storage/prisma.test.tssrc/storage/drizzle.test.tssrc/storage/kysely.test.tssrc/storage/kysely.tsbuild.config.ts
**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Ensure assertions (e.g., expect) are placed inside an it() call
Don't use disabled tests
Files:
src/storage/prisma.test.tssrc/storage/drizzle.test.tssrc/storage/kysely.test.ts
**/*.{jsx,tsx,js,ts}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
**/*.{jsx,tsx,js,ts}: Ensure preconnect is used with Google Fonts
Use a recommended display strategy with Google Fonts
Files:
src/storage/prisma.test.tssrc/storage/drizzle.test.tssrc/storage/kysely.test.tssrc/storage/kysely.tsbuild.config.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)
Don't import next/document outside of pages/_document.jsx
Files:
src/storage/prisma.test.tssrc/storage/drizzle.test.tssrc/storage/kysely.test.tssrc/storage/kysely.tsbuild.config.ts
{**/*.{ts,tsx,js,jsx},package.json}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
{**/*.{ts,tsx,js,jsx},package.json}: Usebun <file>instead ofnode <file>orts-node <file>
UseBun.serve()for HTTP/WebSocket servers; do not useexpress
Usebun:sqlitefor SQLite; do not usebetter-sqlite3
UseBun.redisfor Redis; do not useioredis
UseBun.sqlfor Postgres; do not usepgorpostgres.js
Use the built-inWebSocket; do not usews
UseBun.$shell (e.g., Bun.$ls) instead ofexeca
Files:
src/storage/prisma.test.tssrc/storage/drizzle.test.tssrc/storage/kysely.test.tssrc/storage/kysely.tsbuild.config.ts
{**/*.test.{ts,tsx,js,jsx},package.json}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
{**/*.test.{ts,tsx,js,jsx},package.json}: Usebun testinstead ofjestorvitest
Usebun testto run tests
Files:
src/storage/prisma.test.tssrc/storage/drizzle.test.tssrc/storage/kysely.test.ts
{**/*.{html,ts,css},package.json}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file.html|file.ts|file.css>instead ofwebpackoresbuild
Files:
src/storage/prisma.test.tssrc/storage/drizzle.test.tssrc/storage/kysely.test.tssrc/storage/kysely.tsbuild.config.ts
🧬 Code graph analysis (1)
src/storage/kysely.test.ts (2)
src/drizzle/db.ts (1)
db(5-12)src/storage/kysely.ts (2)
ApiKeysDatabase(8-14)KyselyStore(39-179)
🪛 Checkov (3.2.334)
.github/workflows/test.yml
[medium] 104-105: Basic Auth Credentials
(CKV_SECRET_4)
🔇 Additional comments (8)
docker-compose.yml (1)
19-68: LGTM! Well-isolated test database services.The three new PostgreSQL services provide proper isolation for testing Kysely, Drizzle, and Prisma adapters separately. Port mappings (5433, 5434, 5435) avoid conflicts, and dedicated volumes prevent cross-contamination between test runs.
FEATURE_SUGGESTIONS.md (1)
68-76: LGTM! Clearer template usage pattern.The updated example shows a more explicit pattern by assigning the template to a variable before using it, which improves clarity.
src/storage/kysely.ts (1)
1-180: LGTM! Solid Kysely adapter implementation.The implementation correctly handles:
- JSONB containment queries for owner and tag filtering
- OR logic across tags (line 131) without the previously flagged wrapping issue
- Existence validation before metadata updates
- Proper type conversions between database rows and API records
The use of
anytype at line 130 is reasonable given Kysely's complex type inference for theorhelper.build.config.ts (1)
13-13: LGTM! Build configuration updated correctly.The Kysely adapter is properly included in build entries, and both
kyselyandpgare correctly externalized to prevent bundling peer dependencies.Also applies to: 40-41
src/storage/drizzle.test.ts (1)
34-34: LGTM! Database endpoint updated for isolated testing.The connection string now points to the dedicated Drizzle test database (port 5434, keypal_drizzle), ensuring proper test isolation.
src/storage/prisma.test.ts (1)
32-32: LGTM! Streamlined test setup and cleanup.The test suite now uses the dedicated Prisma database (port 5435, keypal_prisma) and simplifies cleanup by removing unnecessary conditional checks. The unconditional cleanup is cleaner and safe.
Also applies to: 62-62, 66-66
.github/workflows/test.yml (1)
39-79: LGTM! Well-structured multi-database test workflow.The workflow properly isolates each adapter's tests with dedicated PostgreSQL service containers and correct DATABASE_URL environment variables. This ensures tests don't interfere with each other.
Note: The static analysis warning about credentials at line 104 is a false positive—these are test database credentials for CI, not production secrets.
Also applies to: 94-119
src/storage/kysely.test.ts (1)
1-1215: LGTM! Comprehensive test coverage for KyselyStore.The test suite provides excellent coverage including CRUD operations, tag filtering with OR logic, concurrent operations, edge cases, Unicode handling, key rotation, and revocation. The structure mirrors existing adapter tests, ensuring consistency across the codebase.
This PR aims to add a Kysely Postgres adapter:
Summary by cubic
Adds a Kysely Postgres adapter for API key storage with JSONB metadata, matching the Drizzle adapter’s API. Includes a full test suite and a new package export for easy use.
New Features
Migration
Summary by CodeRabbit
New Features
Tests
Chores