Skip to content

[refactor] map Getting, Updating & Filter objects with Key Map field#24

Merged
TechQuery merged 5 commits intomainfrom
copilot/add-keymap-optional-property
Apr 3, 2026
Merged

[refactor] map Getting, Updating & Filter objects with Key Map field#24
TechQuery merged 5 commits intomainfrom
copilot/add-keymap-optional-property

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 2, 2026

PR-24 PR-24 PR-24 Powered by Pull Request Badge

BiDataTable had no way to bridge Lark's raw column header names (e.g. '商品名称') to TypeScript property names, requiring consumers to manually remap fields after fetching.

Changes

  • keyMap property — optional Partial<Record<keyof T, string>> on BiDataTableModel; declares { typeKey: 'columnHeaderName' } mappings; undeclared fields pass through unchanged
  • mapFields() method — wraps this.normalize(), applies keyMap renames, returns mapped T
  • Call sitesgetOne, updateOne, openStream now call this.mapFields() instead of this.normalize() directly

Example

class ProductTable extends BiDataTable<{ name: string; price: number }>() {
    client = app.client;
    keyMap = {
        name: '商品名称',
        price: '价格',
    };
}

// Raw Lark record: { fields: { '商品名称': 'Widget', '价格': 99 } }
// Normalized output: { name: 'Widget', price: 99 }

Human changes

  1. [refactor] map Getting, Updating & Filter objects with Key Map (resolve BiDataTable 支持字段名映射 #23)
  2. [optimize] update Upstream packages & GitHub-reward scripts

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • open.feishu.cn
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/MobX-Lark/MobX-Lark/node_modules/.bin/ts-node test/index.spec.ts node -Lar�� 490ff7debfb7366a6b7a95cf -Lark/src/module/BITable/index.ts odules/npm/node_modules/@npmcli/run-script/lib/node-gyp-bin/node (dns block)
    • Triggering command: /home/REDACTED/work/_temp/ghcca-node/node/bin/node node /home/REDACTED/work/MobX-Lark/MobX-Lark/node_modules/.bin/ts-node test/index.spec.ts node /hom�� ex.spec.ts (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI linked an issue Apr 2, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Add optional keyMap property to BiDataTable abstract class feat(BiDataTable): add keyMap property and mapFields() for column header → type key mapping Apr 2, 2026
Copilot AI requested a review from TechQuery April 2, 2026 18:29
@TechQuery TechQuery added the enhancement Some improvements label Apr 3, 2026
@TechQuery TechQuery marked this pull request as ready for review April 3, 2026 17:21
Copilot AI review requested due to automatic review settings April 3, 2026 17:21
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a first-class way for BiDataTable consumers to map between Lark BITable column header names (often non-identifier strings) and TypeScript model property keys, so returned records can be consumed without manual post-processing.

Changes:

  • Introduces keyMap and field key remapping in BiDataTable (read/write + filters), using a new mapKeys() helper.
  • Updates tests and README examples to demonstrate keyMap usage.
  • Updates GitHub reward scripts and bumps a few dependencies / lockfile.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/module/BITable/index.ts Adds keyMap/nameMap, mapFields(), and applies mapping to getOne, updateOne, streaming, and search filters.
src/module/BITable/utility.ts Adds mapKeys() helper and applies formatting adjustments.
test/index.spec.ts Updates BITable-related tests to set keyMap.
ReadMe.md Documents keyMap usage in example model.
.github/scripts/share-reward.ts Deduplicates users and adds git config cleanup; introduces an npm: import.
.github/scripts/count-reward.ts Exits gracefully when no reward data is present; cleans up git config.
package.json Version bump + dependency updates.
pnpm-lock.yaml Lockfile updates corresponding to dependency bumps.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

map: Partial<Record<keyof I, PropertyKey>>
) =>
Object.fromEntries(
Object.entries(data).map(([key, value]) => [map[key as keyof I] || key, value])
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

mapKeys() uses map[...] || key when selecting the mapped key. This will incorrectly fall back to the original key when the intended mapped key is a valid falsy PropertyKey (e.g. an empty string or 0). Use nullish-coalescing (or an explicit in/hasOwnProperty check) so that defined mappings are always honored.

Suggested change
Object.entries(data).map(([key, value]) => [map[key as keyof I] || key, value])
Object.entries(data).map(([key, value]) => [map[key as keyof I] ?? key, value])

Copilot uses AI. Check for mistakes.
Comment on lines 101 to +110
async updateOne(data: F, id?: string) {
const fields = this.wrapFields(data);
const rawData = this.wrapFields(data);

const fields = isEmpty(this.keyMap) ? rawData : (mapKeys(rawData, this.keyMap) as D);

const { body } = await (id
? this.client.put<TableRecordData<T>>(`${this.baseURI}/${id}`, {
fields
})
: this.client.post<TableRecordData<T>>(this.baseURI, {
fields
}));
return (this.currentOne = this.normalize(body!.data!.record));
? this.client.put<TableRecordData<D>>(`${this.baseURI}/${id}`, { fields })
: this.client.post<TableRecordData<D>>(this.baseURI, { fields }));

return (this.currentOne = this.mapFields(body!.data!.record));
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

updateOne() builds a fields object whose keys are BITable column names after applying keyMap, but it is still typed/cast as D. This is misleading and can mask mistakes (the resulting object is no longer shaped like D). Consider typing the request payload as TableRecordFields (or a dedicated Record<string, unknown>) once keys are mapped, and only keep D for the normalized return value.

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +58
get nameMap() {
return this.keyMap
? Object.fromEntries(Object.entries(this.keyMap).map(([key, name]) => [name, key]))
: {};
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

nameMap is recomputed from keyMap on every access, and mapFields() calls it for every record in openStream(). For large tables this adds avoidable per-record overhead. Consider memoizing the inverted map (and invalidating when keyMap changes) or computing it once in mapFields() based on a cached value.

Suggested change
get nameMap() {
return this.keyMap
? Object.fromEntries(Object.entries(this.keyMap).map(([key, name]) => [name, key]))
: {};
private cachedKeyMap?: Partial<Record<keyof D, string>>;
private cachedNameMap: Partial<Record<string, keyof D>> = {};
get nameMap() {
if (this.keyMap !== this.cachedKeyMap) {
this.cachedKeyMap = this.keyMap;
this.cachedNameMap = this.keyMap
? (Object.fromEntries(
Object.entries(this.keyMap).map(([key, name]) => [name, key])
) as Partial<Record<string, keyof D>>)
: {};
}
return this.cachedNameMap;

Copilot uses AI. Check for mistakes.
Comment on lines 180 to 183
export function BiSearch<D extends DataObject, F extends BiSearchFilter<D> = BiSearchFilter<D>>(
Model: Constructor<ListModel<D, F>>
Model: ReturnType<typeof BiDataTable<D, F>>
) {
abstract class BiSearchModel extends Model {
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

BiSearch() now requires Model: ReturnType<typeof BiDataTable<...>>, whereas it previously accepted any Constructor<ListModel<...>>. This is a compile-time breaking change for consumers who passed non-BiDataTable list models into BiSearch, but the package version is only bumped as a patch. If the narrower type is intentional, consider keeping backward compatibility by using a structural constraint (e.g. requiring makeFilter/mapFilter) or documenting it as a breaking change / adjusting versioning accordingly.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to 4
import 'npm:array-unique-proposal';

import { components } from 'npm:@octokit/openapi-types';
import { $, argv, YAML } from 'npm:zx';
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

This script introduces an unpinned runtime dependency via import 'npm:array-unique-proposal'. Using npm: without an explicit version makes workflow behavior non-deterministic over time and increases supply-chain risk. Prefer pinning the version (e.g. npm:array-unique-proposal@x.y.z) or avoiding prototype-patching entirely by deduplicating with a local Set/utility function.

Suggested change
import 'npm:array-unique-proposal';
import { components } from 'npm:@octokit/openapi-types';
import { $, argv, YAML } from 'npm:zx';
import 'npm:array-unique-proposal@1.0.4';
import { components } from 'npm:@octokit/openapi-types@22.2.0';
import { $, argv, YAML } from 'npm:zx@8.1.9';

Copilot uses AI. Check for mistakes.
@TechQuery TechQuery changed the title feat(BiDataTable): add keyMap property and mapFields() for column header → type key mapping [refactor] map Getting, Updating & Filter objects with Key Map field Apr 3, 2026
@TechQuery TechQuery merged commit 444069e into main Apr 3, 2026
6 checks passed
@TechQuery TechQuery deleted the copilot/add-keymap-optional-property branch April 3, 2026 17:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Some improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BiDataTable 支持字段名映射

3 participants