Skip to content

feat(base): add +record-search for keyword-based record search#328

Merged
kongenpei merged 12 commits intomainfrom
feat-search-record
Apr 10, 2026
Merged

feat(base): add +record-search for keyword-based record search#328
kongenpei merged 12 commits intomainfrom
feat-search-record

Conversation

@kongenpei
Copy link
Copy Markdown
Collaborator

@kongenpei kongenpei commented Apr 8, 2026

Summary

Add a new base +record-search shortcut to pass through JSON payloads to the Base records search API, with dry-run support and test/doc coverage.

Changes

  • Add +record-search shortcut registration and execution for Base records search.
  • Reuse JSON-object parsing for the search request body and wire dry-run output to the /records/search endpoint.
  • Add tests for command registration, execution behavior, and dry-run request shape.
  • Update skills/lark-base docs and references for +record-search usage.

Test Plan

  • Unit tests pass (make unit-test)
  • Manual local verification confirms the lark xxx command works as expected (go run . base +record-search --base-token app_token --table-id tbl_token --json '{}' --dry-run)
  • go mod tidy (no changes to go.mod/go.sum)
  • go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run --new-from-rev=origin/main (local env reports an existing unrelated forbidigo issue in shortcuts/drive/drive_upload.go:186)

Related Issues

Summary by CodeRabbit

  • New Features

    • Added +record-search to search records by keyword with view selection, field filtering, JSON passthrough input, and pagination.
  • Documentation

    • Added detailed +record-search reference, updated skill docs and command index with usage, parameters, examples, constraints, and guidance to prefer search for keyword scenarios.
  • Behavior

    • Record upsert no longer performs local JSON validation (API passthrough); shortcuts catalog order updated to include +record-search.
  • Tests

    • Added tests and dry-run assertions for record-search and payload verification.

@github-actions github-actions bot added domain/base PR touches the base domain size/M Single-domain feat or fix with limited business impact labels Apr 8, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 8, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new +record-search Base shortcut with dry-run and execution handlers that POST to /open-apis/base/v3/bases/:base_token/tables/:table_id/records/search, updates tests to cover dry-run/execute/catalog changes, removes Validate from upsert shortcut, and adds documentation and skill guidance for the command.

Changes

Cohort / File(s) Summary
Shortcut implementation
shortcuts/base/record_search.go, shortcuts/base/record_ops.go, shortcuts/base/shortcuts.go
Introduce BaseRecordSearch shortcut; implement dryRunRecordSearch and executeRecordSearch to parse --json and POST to the Base records/search endpoint; register shortcut in Shortcuts().
Record upsert validation
shortcuts/base/record_upsert.go
Removed Validate hook that previously called validateRecordJSON from BaseRecordUpsert.
Tests
shortcuts/base/base_dryrun_ops_test.go, shortcuts/base/base_execute_test.go, shortcuts/base/base_shortcuts_test.go
Add dry-run assertion for records/search POST and body fragments; add execute subtest that mocks POST and validates request body and output; update catalog expectations to include +record-search; remove JSON validation checks in upsert test.
Documentation & skills
skills/lark-base/SKILL.md, skills/lark-base/references/lark-base-record-search.md, skills/lark-base/references/lark-base-record-list.md, skills/lark-base/references/lark-base-record.md
Add +record-search documentation, usage examples, parameter constraints, API endpoint reference; update skill guidance and command index to include +record-search.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI runtime
    participant Shortcut as +record-search Shortcut
    participant Parser as JSON parser
    participant BaseAPI as Base API (records/search)
    CLI->>Shortcut: invoke +record-search (--base-token, --table-id, --json)
    Shortcut->>Parser: parse `--json` body
    alt parse success
        Shortcut->>BaseAPI: POST /open-apis/base/v3/bases/:base_token/tables/:table_id/records/search (body)
        BaseAPI-->>Shortcut: 200 OK (records payload)
        Shortcut-->>CLI: write records to stdout
    else parse failure
        Shortcut-->>CLI: return parse error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through code and fields so wide,
A JSON map tucked safe inside,
I nudged a POST and watched it roam,
Records returned to bring them home,
A rabbit's cheer for search and stride ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% 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 The pull request description matches the required template with all main sections completed: Summary, Changes, Test Plan with checkboxes, and Related Issues.
Title check ✅ Passed The PR title 'feat(base): add +record-search for keyword-based record search' accurately summarizes the main change—implementing a new keyword-based record search shortcut—matching the changeset's primary objective.

✏️ 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 feat-search-record

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

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 8, 2026

Greptile Summary

This PR adds the +record-search shortcut, which passes a user-supplied JSON body straight through to POST /open-apis/base/v3/bases/:base_token/tables/:table_id/records/search. It follows the established API-passthrough pattern used by +record-upsert and also removes the local Validate step from upsert for consistency. Implementation, tests, and docs are all tidy.

Confidence Score: 5/5

Safe to merge — new shortcut is additive, well-tested, and consistent with existing patterns.

No P0 or P1 findings. All remaining observations from prior threads appear resolved (no parseRecordSearchBody wrapper in the code). The implementation mirrors the established API-passthrough design of +record-upsert, with proper error handling in the execute path and intentional error-discarding in dry-run (matching every other dry-run function in the package). Tests cover catalog registration, dry-run shape, execute body forwarding, and validate-nil assertions.

No files require special attention.

Vulnerabilities

No security concerns identified. The shortcut is correctly scoped to base:record:read, marked with risk: read, and performs no privileged write operations. User-supplied JSON is passed directly to the Lark API, which is the intended passthrough design and consistent with other shortcuts in the package.

Important Files Changed

Filename Overview
shortcuts/base/record_search.go New shortcut definition for +record-search; correctly marks all flags as required, sets risk to read, and wires dry-run and execute handlers.
shortcuts/base/record_ops.go Adds dryRunRecordSearch and executeRecordSearch; both call parseJSONObject directly (no unnecessary wrapper), consistent with upsert pattern; execute properly returns parse/API errors.
shortcuts/base/shortcuts.go Inserts BaseRecordSearch between BaseRecordList and BaseRecordGet in the catalog, matching the updated test expectation and intended ordering.
shortcuts/base/record_upsert.go Removes the Validate field from BaseRecordUpsert, aligning upsert with the API-passthrough philosophy; test asserts Validate == nil.
shortcuts/base/base_dryrun_ops_test.go Adds dry-run assertion for record search; uses offset:-1 and limit:500 intentionally to prove CLI does not clamp/validate passthrough values.
shortcuts/base/base_execute_test.go Adds an execute test that stubs the POST search endpoint, runs the shortcut, and verifies both stdout and the captured request body contain the expected fields.
shortcuts/base/base_shortcuts_test.go Updates catalog order test to include +record-search, and adds a Validate == nil assertion for both the new search shortcut and the modified upsert shortcut.
skills/lark-base/references/lark-base-record-search.md New reference doc; covers parameters, constraints, usage examples, caveats and cross-references; filter field is absent from the JSON format table (noted in a prior thread).
skills/lark-base/SKILL.md Adds +record-search to the command index and updates the record commands row in the quick-reference table.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as lark-cli base +record-search
    participant Parser as parseJSONObject
    participant API as Lark Base API

    User->>CLI: --base-token --table-id --json '{...}'
    alt --dry-run flag
        CLI->>Parser: parseJSONObject(json)
        Parser-->>CLI: body (error discarded)
        CLI-->>User: POST /open-apis/base/v3/bases/:base_token/tables/:table_id/records/search + body preview
    else execute
        CLI->>Parser: parseJSONObject(json)
        Parser-->>CLI: body, err
        alt parse error
            CLI-->>User: error returned
        else valid JSON object
            CLI->>API: POST /open-apis/base/v3/bases/{base_token}/tables/{table_id}/records/search
            API-->>CLI: {code, data: {fields, record_id_list, data, has_more, query_context}}
            CLI-->>User: JSON output
        end
    end
Loading

Reviews (7): Last reviewed commit: "fix: align record search JSON parsing wi..." | Re-trigger Greptile

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@02ff0365056ec79c3467436ffb30793269114772

🧩 Skill update

npx skills add larksuite/cli#feat-search-record -y -g

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 (1)
shortcuts/base/record_ops.go (1)

162-167: Consider removing trivial wrapper.

parseRecordSearchBody is a pass-through to parseJSONObject with no additional logic. You could call parseJSONObject(runtime.Str("json"), "json") directly in dryRunRecordSearch and executeRecordSearch, matching the pattern used in dryRunRecordUpsert (line 47) and executeRecordUpsert (line 131).

If you're keeping this for future search-specific validation, that's fine too.

♻️ Optional: inline the calls
 func dryRunRecordSearch(_ context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
-	body, _ := parseRecordSearchBody(runtime)
+	body, _ := parseJSONObject(runtime.Str("json"), "json")
 	return common.NewDryRunAPI().
 func executeRecordSearch(runtime *common.RuntimeContext) error {
-	body, err := parseRecordSearchBody(runtime)
+	body, err := parseJSONObject(runtime.Str("json"), "json")
 	if err != nil {

Then remove parseRecordSearchBody entirely.

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

In `@shortcuts/base/record_ops.go` around lines 162 - 167, parseRecordSearchBody
is a trivial passthrough to parseJSONObject and can be removed; replace calls to
parseRecordSearchBody(...) in dryRunRecordSearch and executeRecordSearch with
direct calls to parseJSONObject(runtime.Str("json"), "json") (mirroring the
pattern used by dryRunRecordUpsert and executeRecordUpsert), and then delete the
parseRecordSearchBody function unless you intend to add search-specific
validation later.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@skills/lark-base/references/lark-base-record-search.md`:
- Around line 39-41: The fenced code block containing the API path "POST
/open-apis/base/v3/bases/:base_token/tables/:table_id/records/search" should
include a language tag to satisfy markdownlint MD040; update the backtick fence
around that path to use a language identifier (e.g., http) so the block becomes
a labeled code fence for the API path.
- Around line 45-53: Add a row documenting the optional `filter` field in the
JSON schema table in lark-base-record-search.md: state field name `filter`, 必填
否, 类型 object (JSON), 约束 指定为合法 JSON 对象并遵循文档中“JSON 格式要求”规则(例如允许的表达式/字段格式),并 note
it may be omitted; ensure the description matches examples that use `filter` so
payload shape is unambiguous.

---

Nitpick comments:
In `@shortcuts/base/record_ops.go`:
- Around line 162-167: parseRecordSearchBody is a trivial passthrough to
parseJSONObject and can be removed; replace calls to parseRecordSearchBody(...)
in dryRunRecordSearch and executeRecordSearch with direct calls to
parseJSONObject(runtime.Str("json"), "json") (mirroring the pattern used by
dryRunRecordUpsert and executeRecordUpsert), and then delete the
parseRecordSearchBody function unless you intend to add search-specific
validation later.
🪄 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: a1b4139e-565d-44f8-9ff3-408e83db0fbe

📥 Commits

Reviewing files that changed from the base of the PR and between adef52a and 38556f5.

📒 Files selected for processing (10)
  • shortcuts/base/base_dryrun_ops_test.go
  • shortcuts/base/base_execute_test.go
  • shortcuts/base/base_shortcuts_test.go
  • shortcuts/base/record_ops.go
  • shortcuts/base/record_search.go
  • shortcuts/base/shortcuts.go
  • skills/lark-base/SKILL.md
  • skills/lark-base/references/lark-base-record-list.md
  • skills/lark-base/references/lark-base-record-search.md
  • skills/lark-base/references/lark-base-record.md

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.

♻️ Duplicate comments (2)
skills/lark-base/references/lark-base-record-search.md (2)

39-41: ⚠️ Potential issue | 🟡 Minor

Add a language tag to the API path code fence.

This fenced block is unlabeled and can fail markdownlint MD040. Use an explicit language (e.g., http).

Suggested patch
-```
+```http
 POST /open-apis/base/v3/bases/:base_token/tables/:table_id/records/search
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @skills/lark-base/references/lark-base-record-search.md around lines 39 - 41,
The unlabeled fenced code block containing the API path "POST
/open-apis/base/v3/bases/:base_token/tables/:table_id/records/search" should
include a language tag to satisfy markdownlint MD040; update the fence from tohttp so it reads as a labeled http code block, preserving the exact API
path text inside the fence.


</details>

---

`45-52`: _⚠️ Potential issue_ | _🟡 Minor_

**Document `filter` in the JSON schema table for payload completeness.**

`filter` is supported in request bodies but is absent from the table, which makes payload shape ambiguous.
 

<details>
<summary>Suggested patch</summary>

```diff
 | `search_fields` | 是 | string[] | 数组长度 `1-20`;每项是字段 `field_id` 或字段名,代表在这些字段中做关键词搜索 |
 | `select_fields` | 否 | string[] | 数组长度 `<=50`;每项是字段 `field_id` 或字段名 |
+| `filter` | 否 | object | 过滤条件对象(如 `conjunction` / `conditions`),可省略 |
 | `offset` | 否 | int | `>=0`,默认 `0` |
 | `limit` | 否 | int | `1-200`,默认 `10` |
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against the current code and only fix it if needed.

In `@skills/lark-base/references/lark-base-record-search.md` around lines 45 - 52,
Add the missing `filter` row to the JSON schema table in
lark-base-record-search.md: document `filter` as an optional field named
`filter`, type "object" (or "string"/JSON expression if your API accepts
serialized filters), and describe constraints/shape (e.g., allowed operators,
nested structure, or reference to the filter schema used elsewhere), and note
any size/complexity limits; ensure the new row sits alongside `view_id`,
`keyword`, `search_fields`, etc., and include a brief cross-reference to the
canonical filter schema or example usage so payload shape is unambiguous.
```

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @skills/lark-base/references/lark-base-record-search.md:

  • Around line 39-41: The unlabeled fenced code block containing the API path
    "POST /open-apis/base/v3/bases/:base_token/tables/:table_id/records/search"
    should include a language tag to satisfy markdownlint MD040; update the fence
    from tohttp so it reads as a labeled http code block, preserving the
    exact API path text inside the fence.
  • Around line 45-52: Add the missing filter row to the JSON schema table in
    lark-base-record-search.md: document filter as an optional field named
    filter, type "object" (or "string"/JSON expression if your API accepts
    serialized filters), and describe constraints/shape (e.g., allowed operators,
    nested structure, or reference to the filter schema used elsewhere), and note
    any size/complexity limits; ensure the new row sits alongside view_id,
    keyword, search_fields, etc., and include a brief cross-reference to the
    canonical filter schema or example usage so payload shape is unambiguous.

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: defaults

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `faa04148-e356-4d08-a8c8-8bda361ca991`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 38556f5aa4444eaf869705e547b362d57b8e01e2 and 037a1c43706c7cfaa9bb319976429f4c10e1c9d0.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `skills/lark-base/SKILL.md`
* `skills/lark-base/references/lark-base-record-list.md`
* `skills/lark-base/references/lark-base-record-search.md`

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (1)</summary>

* skills/lark-base/references/lark-base-record-list.md

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* skills/lark-base/SKILL.md

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Copy link
Copy Markdown

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

kongenpei has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

Copy link
Copy Markdown

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

kongenpei has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

zgz2048
zgz2048 previously approved these changes Apr 10, 2026
Copy link
Copy Markdown

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

kongenpei has reached the 50-review limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@kongenpei kongenpei changed the title feat(base): add +record-search json passthrough shortcut feat(base): add +record-search for keyword-based record search Apr 10, 2026
@kongenpei kongenpei merged commit d8b0865 into main Apr 10, 2026
16 checks passed
@kongenpei kongenpei deleted the feat-search-record branch April 10, 2026 09:18
@kongenpei
Copy link
Copy Markdown
Collaborator Author

close #143

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

Labels

domain/base PR touches the base domain size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants