Skip to content

Add rowid-based selection support to fmodata mutations and docs#214

Open
eluce2 wants to merge 1 commit intomainfrom
codex/select-by-rowid
Open

Add rowid-based selection support to fmodata mutations and docs#214
eluce2 wants to merge 1 commit intomainfrom
codex/select-by-rowid

Conversation

@eluce2
Copy link
Copy Markdown
Collaborator

@eluce2 eluce2 commented Apr 16, 2026

Summary

  • add rowid selection support across fmodata mutation/query builders
  • update docs, README, and skill guidance for the new selection flow
  • add tests covering delete, update, navigation, record builder, and helper behavior
  • refresh docs app layouts/content tied to the new documentation

Testing

  • Not run (not requested)

Summary by CodeRabbit

  • New Features

    • Added support for FileMaker ROWID record locators to fetch, update, and delete individual records directly via get({ ROWID: n }), update().byRowId(n), and delete().byRowId(n).
  • Documentation

    • Added examples and guidance for using ROWID-based record operations across API references and guides.
  • Tests

    • Added test coverage for ROWID-based queries and mutations.
  • Style

    • Minor JSX formatting adjustments.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 16, 2026

🦋 Changeset detected

Latest commit: 7906ee8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@proofkit/fmodata Minor
@proofkit/better-auth Patch
@proofkit/typegen Patch
@proofkit/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
proofkit-docs Ready Ready Preview Apr 16, 2026 0:04am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 16, 2026

📝 Walkthrough

Walkthrough

This PR adds FileMaker ROWID record locator support to @proofkit/fmodata. It introduces a structured RecordLocator abstraction replacing scalar recordId values, enabling single-record retrieval and mutations via get({ ROWID: n }), update().byRowId(n), and delete().byRowId(n) while updating URL construction and navigation logic across query and mutation builders. Documentation and comprehensive test coverage are added.

Changes

Cohort / File(s) Summary
Record Locator Abstraction
packages/fmodata/src/client/builders/mutation-helpers.ts
Introduces RowIdRecordLocator, RecordLocator types, and exports buildRecordLocatorSegment() and buildRecordPath() helpers for OData key formatting. Updates buildMutationUrl() signature from recordId?: string | number to recordLocator?: RecordLocator.
Query & Navigation URL Building
packages/fmodata/src/client/query/url-builder.ts, packages/fmodata/src/client/record-builder.ts
Updates NavigationConfig and QueryUrlBuilder.buildRecordUrl() to accept recordLocator instead of recordId. Refactors RecordBuilder to centralize path construction via buildRecordResourcePath(), delegating key formatting to buildRecordPath().
Entity Set & CRUD Builders
packages/fmodata/src/client/entity-set.ts, packages/fmodata/src/client/delete-builder.ts, packages/fmodata/src/client/update-builder.ts
Updates EntitySet.get() parameter from id to locator accepting RowIdRecordLocator | string | number. Adds DeleteBuilder.byRowId() and UpdateBuilder.byRowId() methods, and refactors both builders to use recordLocator internally.
Test Coverage
packages/fmodata/tests/{mutation-helpers,delete,update,navigate,record-builder-select-expand,typescript}.test.ts
Adds test cases verifying ROWID-based record access, mutation targeting, navigation, and OData key escaping. Updates existing mutation-helpers test to use recordLocator parameter.
Documentation
.changeset/fresh-falcons-grow.md, packages/fmodata/README.md, packages/fmodata/skills/fmodata-client/SKILL.md, apps/docs/content/docs/fmodata/{crud,extra-properties,methods}.mdx
Documents new ROWID-based APIs with query and mutation examples. Adds changelog entry and updates API reference tables.
Layout Formatting
apps/docs/src/app/(home)/page.tsx, apps/docs/src/app/docs/(docs)/layout.tsx, apps/docs/src/app/docs/templates/layout.tsx
Condenses multi-line JSX attributes and anchor elements into single-line formatting without behavioral changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 pull request title clearly and accurately summarizes the main change: adding ROWID-based record locator support to fmodata single-record APIs (mutations and queries) with corresponding documentation updates.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/select-by-rowid

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 (6)
packages/fmodata/tests/navigate.test.ts (1)

93-98: Optional: replace inline ROWID literal with a named constant.
Line 95 can be a bit clearer/maintainable with a constant like ROW_ID.

As per coding guidelines, "Use meaningful variable names instead of magic numbers - extract constants with descriptive names".

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

In `@packages/fmodata/tests/navigate.test.ts` around lines 93 - 98, Replace the
inline ROWID literal with a named constant to improve clarity and
maintainability: define a constant (e.g., ROW_ID) near the top of the test (or
in the test scope) and use it in the call to get({ ROWID: ROW_ID }) inside the
test that builds queryBuilder for contacts -> users; update the expect to use
the same constant so the test continues to assert
"/contacts(ROWID=2)/users?$select=name" while avoiding the magic number in get({
ROWID: 2 }).
packages/fmodata/tests/update.test.ts (1)

156-162: Optional: extract repeated ROWID literal into a constant for test clarity.
Using a shared constant instead of inline 2 in both new tests will improve readability and reduce duplication.

As per coding guidelines, "Use meaningful variable names instead of magic numbers - extract constants with descriptive names".

Also applies to: 199-209

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

In `@packages/fmodata/tests/update.test.ts` around lines 156 - 162, Extract the
repeated magic number ROWID used in tests into a descriptive constant (e.g.,
const ROWID = 2) and replace inline uses of 2 in the tests that call
db.from(users).update(...).byRowId(2) and any other occurrences (including the
similar assertions around lines 199-209) with that constant; update the
expectations accordingly so tests still assert an ExecutableUpdateBuilder from
byRowId(ROWID) and any comparisons use ROWID for clarity and reduced
duplication.
packages/fmodata/tests/typescript.test.ts (1)

52-57: Optional: use a named ROWID constant in this ergonomics test.
This keeps intent explicit and aligns with the same pattern used across related test files.

As per coding guidelines, "Use meaningful variable names instead of magic numbers - extract constants with descriptive names".

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

In `@packages/fmodata/tests/typescript.test.ts` around lines 52 - 57, Replace the
magic number used for the ROWID call with a descriptive constant to match other
tests: define a named constant (e.g., ROWID = 2 or ROWID_INDEX) at the top of
the test and use it in the table.get call so that the assertions referencing
getBuilder and rowIdBuilder (from table.get and getBuilder.getRequestConfig)
read with explicit intent and follow the project pattern.
packages/fmodata/tests/delete.test.ts (1)

52-58: Optional: centralize test ROWID value into a constant.
Both new test blocks hardcode 2; using one named constant will make updates easier and keep intent explicit.

As per coding guidelines, "Use meaningful variable names instead of magic numbers - extract constants with descriptive names".

Also applies to: 101-110

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

In `@packages/fmodata/tests/delete.test.ts` around lines 52 - 58, Extract the
hardcoded row id (the literal 2) used in the delete tests into a single
descriptive constant (e.g., TEST_ROW_ID or SAMPLE_ROW_ID) and use that constant
in both places where byRowId(2) appears; update the tests referencing
db.from(usersTO).delete().byRowId(...) and any related assertions that use the
same literal so they all reference the new constant (keeps the tests DRY and
makes intent explicit).
packages/fmodata/tests/record-builder-select-expand.test.ts (1)

168-173: Optional: extract the ROWID literal to a named constant.
Line 169 uses a raw 2; a constant (e.g., const ROW_ID = 2) improves intent and consistency across tests.

As per coding guidelines, "Use meaningful variable names instead of magic numbers - extract constants with descriptive names".

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

In `@packages/fmodata/tests/record-builder-select-expand.test.ts` around lines 168
- 173, Extract the magic number 2 used in the test "should support ROWID
locators in get()" into a named constant (for example ROW_ID = 2) and use that
constant in the call db.from(contacts).get({ ROWID: ROW_ID }).getQueryString();
update the expect assertions if they reference the literal directly to use the
constant where applicable to improve readability and consistency.
packages/fmodata/src/client/query/url-builder.ts (1)

127-144: Consider extracting shared navigation URL logic.

There's noticeable duplication between buildPath and buildRecordNavigation for constructing the base URL with sourceTable, baseRelation, and recordLocator. Consider extracting this into a shared private helper to reduce repetition.

The redundant recordLocator === undefined check (lines 138-140) can never be true since line 127 already guarantees recordLocator is defined when entering this branch.

♻️ Optional: Extract shared logic
+  private buildRecordNavigationBase(
+    navigation: NavigationConfig,
+    useEntityIds: boolean,
+  ): string {
+    const sourceTable = useEntityIds
+      ? (navigation.sourceTableEntityId ?? navigation.sourceTableName)
+      : navigation.sourceTableName;
+    const baseRelation = useEntityIds
+      ? (navigation.baseRelationEntityId ?? navigation.baseRelation)
+      : navigation.baseRelation;
+    const { recordLocator } = navigation;
+    if (recordLocator === undefined) {
+      throw new Error("recordLocator is required for record navigation");
+    }
+    return baseRelation
+      ? buildRecordPath(`${sourceTable}/${baseRelation}`, recordLocator)
+      : buildRecordPath(sourceTable, recordLocator);
+  }

Then use this helper in both buildRecordNavigation and buildPath.

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

In `@packages/fmodata/src/client/query/url-builder.ts` around lines 127 - 144,
Extract the duplicated logic that builds the base navigation segment from
buildPath and buildRecordNavigation into a private helper (e.g.,
buildNavigationBase or buildRecordBasePath) which takes parameters
effectiveUseEntityIds, navigation (or its sourceTable, baseRelation, and
recordLocator) and returns the base path string (using buildRecordPath when
baseRelation is present); update both buildPath and buildRecordNavigation to
call this helper to construct the base and then append the relation and
queryString as before, and remove the redundant recordLocator undefined check
inside buildRecordNavigation since the outer branch already guarantees its
presence.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/docs/src/app/docs/`(docs)/layout.tsx:
- Line 19: The footer anchor using href="http://proof.sh" should use HTTPS;
update the anchor element (the <a> with className "underline" and
target="_blank") in layout.tsx to use "https://proof.sh" so the link is loaded
securely and avoids insecure redirects or content tampering.

In `@apps/docs/src/app/docs/templates/layout.tsx`:
- Line 89: Update the external footer anchor in layout.tsx to use HTTPS by
changing the href value on the anchor element (the <a className="underline" ...>
tag) from "http://proof.sh" to "https://proof.sh"; keep the existing
rel="noopener noreferrer" and target="_blank" attributes intact to preserve
security and behavior.

---

Nitpick comments:
In `@packages/fmodata/src/client/query/url-builder.ts`:
- Around line 127-144: Extract the duplicated logic that builds the base
navigation segment from buildPath and buildRecordNavigation into a private
helper (e.g., buildNavigationBase or buildRecordBasePath) which takes parameters
effectiveUseEntityIds, navigation (or its sourceTable, baseRelation, and
recordLocator) and returns the base path string (using buildRecordPath when
baseRelation is present); update both buildPath and buildRecordNavigation to
call this helper to construct the base and then append the relation and
queryString as before, and remove the redundant recordLocator undefined check
inside buildRecordNavigation since the outer branch already guarantees its
presence.

In `@packages/fmodata/tests/delete.test.ts`:
- Around line 52-58: Extract the hardcoded row id (the literal 2) used in the
delete tests into a single descriptive constant (e.g., TEST_ROW_ID or
SAMPLE_ROW_ID) and use that constant in both places where byRowId(2) appears;
update the tests referencing db.from(usersTO).delete().byRowId(...) and any
related assertions that use the same literal so they all reference the new
constant (keeps the tests DRY and makes intent explicit).

In `@packages/fmodata/tests/navigate.test.ts`:
- Around line 93-98: Replace the inline ROWID literal with a named constant to
improve clarity and maintainability: define a constant (e.g., ROW_ID) near the
top of the test (or in the test scope) and use it in the call to get({ ROWID:
ROW_ID }) inside the test that builds queryBuilder for contacts -> users; update
the expect to use the same constant so the test continues to assert
"/contacts(ROWID=2)/users?$select=name" while avoiding the magic number in get({
ROWID: 2 }).

In `@packages/fmodata/tests/record-builder-select-expand.test.ts`:
- Around line 168-173: Extract the magic number 2 used in the test "should
support ROWID locators in get()" into a named constant (for example ROW_ID = 2)
and use that constant in the call db.from(contacts).get({ ROWID: ROW_ID
}).getQueryString(); update the expect assertions if they reference the literal
directly to use the constant where applicable to improve readability and
consistency.

In `@packages/fmodata/tests/typescript.test.ts`:
- Around line 52-57: Replace the magic number used for the ROWID call with a
descriptive constant to match other tests: define a named constant (e.g., ROWID
= 2 or ROWID_INDEX) at the top of the test and use it in the table.get call so
that the assertions referencing getBuilder and rowIdBuilder (from table.get and
getBuilder.getRequestConfig) read with explicit intent and follow the project
pattern.

In `@packages/fmodata/tests/update.test.ts`:
- Around line 156-162: Extract the repeated magic number ROWID used in tests
into a descriptive constant (e.g., const ROWID = 2) and replace inline uses of 2
in the tests that call db.from(users).update(...).byRowId(2) and any other
occurrences (including the similar assertions around lines 199-209) with that
constant; update the expectations accordingly so tests still assert an
ExecutableUpdateBuilder from byRowId(ROWID) and any comparisons use ROWID for
clarity and reduced duplication.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 22534d7d-5d18-4f20-ab20-df5ffe2be6a8

📥 Commits

Reviewing files that changed from the base of the PR and between f4c5a64 and 7906ee8.

📒 Files selected for processing (21)
  • .changeset/fresh-falcons-grow.md
  • apps/docs/content/docs/fmodata/crud.mdx
  • apps/docs/content/docs/fmodata/extra-properties.mdx
  • apps/docs/content/docs/fmodata/methods.mdx
  • apps/docs/src/app/(home)/page.tsx
  • apps/docs/src/app/docs/(docs)/layout.tsx
  • apps/docs/src/app/docs/templates/layout.tsx
  • packages/fmodata/README.md
  • packages/fmodata/skills/fmodata-client/SKILL.md
  • packages/fmodata/src/client/builders/mutation-helpers.ts
  • packages/fmodata/src/client/delete-builder.ts
  • packages/fmodata/src/client/entity-set.ts
  • packages/fmodata/src/client/query/url-builder.ts
  • packages/fmodata/src/client/record-builder.ts
  • packages/fmodata/src/client/update-builder.ts
  • packages/fmodata/tests/delete.test.ts
  • packages/fmodata/tests/mutation-helpers.test.ts
  • packages/fmodata/tests/navigate.test.ts
  • packages/fmodata/tests/record-builder-select-expand.test.ts
  • packages/fmodata/tests/typescript.test.ts
  • packages/fmodata/tests/update.test.ts

rel="noopener"
target="_blank"
>
<a className="underline" href="http://proof.sh" rel="noopener" target="_blank">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use HTTPS here as well.

This footer link also uses http://proof.sh. Please switch to HTTPS to avoid insecure redirects/content tampering.

Suggested fix
-              <a className="underline" href="http://proof.sh" rel="noopener" target="_blank">
+              <a className="underline" href="https://proof.sh" rel="noopener" target="_blank">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<a className="underline" href="http://proof.sh" rel="noopener" target="_blank">
<a className="underline" href="https://proof.sh" rel="noopener" target="_blank">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/docs/src/app/docs/`(docs)/layout.tsx at line 19, The footer anchor using
href="http://proof.sh" should use HTTPS; update the anchor element (the <a> with
className "underline" and target="_blank") in layout.tsx to use
"https://proof.sh" so the link is loaded securely and avoids insecure redirects
or content tampering.

rel="noopener noreferrer"
target="_blank"
>
<a className="underline" href="http://proof.sh" rel="noopener noreferrer" target="_blank">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use HTTPS for the external footer link.

href="http://proof.sh" downgrades transport security and allows interception/redirect risks. Switch to HTTPS.

Suggested fix
-              <a className="underline" href="http://proof.sh" rel="noopener noreferrer" target="_blank">
+              <a className="underline" href="https://proof.sh" rel="noopener noreferrer" target="_blank">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<a className="underline" href="http://proof.sh" rel="noopener noreferrer" target="_blank">
<a className="underline" href="https://proof.sh" rel="noopener noreferrer" target="_blank">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/docs/src/app/docs/templates/layout.tsx` at line 89, Update the external
footer anchor in layout.tsx to use HTTPS by changing the href value on the
anchor element (the <a className="underline" ...> tag) from "http://proof.sh" to
"https://proof.sh"; keep the existing rel="noopener noreferrer" and
target="_blank" attributes intact to preserve security and behavior.

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