Repository navigation
Commit d85ff19
fix(core): resolve an import lookup cell by the target object's unique fields, an autonumber included (#28112)
Fixes #27947
Clause-②: no
Metadata-protocol: none
Skills-docs: none — `skills/**` and `content/docs/**` (outside the
generated `references/` and the release-owned `releases/`) carry no
sentence listing the import lookup candidate fields; grepped for the
fixed keys, `reference_not_found`, `reference_ambiguous` and the
lookup-cell wording.
## 维护者速读
- 改了什么:数据导入的 lookup 单元格匹配,在原有候选(id、lookup 的
displayField、目标对象标题字段、name/title/label/full_name/email/username)全部落空后,再按目标对象字段声明顺序尝试其唯一字段(`unique`
声明了约束的字段,以及未写 `unique` 的 autonumber 字段)。
- 为什么改:单元格写的是目标记录的编号(如 `ACC-000012`)或其它唯一字段时,今天一律报
`reference_not_found`;记录标题一改,之前导出的文件就全部导不回来。
- 风险与回滚:只在原有候选全部未命中时才多查几次;原有候选命中时行为不变,多条命中仍报
`reference_ambiguous`,不会静默挑一条。回滚即还原 `import-runner.ts` 这一处候选列表。
- 先看:`packages/core/src/utils/import-runner.ts` 的
`isUniqueReferenceField`(autonumber 默认唯一、`unique: false` 退出)与
`resolveRef` 候选列表末尾一行;其次 `import-runner-reference-unique.test.ts`。
- 两分钟验证:`pnpm --filter @objectstack/core exec vitest run
src/utils/import-runner-reference-unique.test.ts`,预期 6 个用例全绿。
- 需要你做的:无,席位落地。
## What changes
`resolveRef` in `packages/core/src/utils/import-runner.ts` asked the id,
the lookup's `displayField`, the target's title field, then `name` /
`title` / `label` / `full_name` / `email` / `username`, and stopped. A
cell holding the target's autonumber or another unique field answered
`reference_not_found`.
The target's unique fields are now appended to the candidate list, read
once per target per import off the same declaration the exposure check
already reads (`servesReferenceTarget`), so no extra metadata read:
- a field whose `unique` declares a constraint, judged by the spec's own
`isUniqueDeclared` (`true`, `'organization'`, `'global'`);
- an `autonumber` field that omits `unique`: the spec makes it `unique:
'organization'` by contract (`FieldSchema`'s autonumber default). The
default is applied in the predicate too, so a declaration read unparsed
still counts;
- an `autonumber` declared `unique: false` has opted out (the spec's
display-only ordinal) and is not asked.
They come after every existing candidate, in the target's declared field
order, de-duplicated against the existing list (a unique `email` is
asked once, in its fixed place), and virtual fields are still skipped.
The existing rules are unchanged: the first field to match wins, and a
field matching more than one record is `reference_ambiguous`.
No spec key, no published shape and no public export changes.
## Tests
New `packages/core/src/utils/import-runner-reference-unique.test.ts` (6
cases), beside the `#24981` title pins:
- an autonumber cell `ACC-000012` resolves and stores the matched id,
asked after every existing candidate;
- another declared-unique field (`unique: true`) resolves;
- order control: a cell that is one record's `name` and another record's
autonumber links the `name` match, and the autonumber is never asked;
- a cell matching nothing still answers `reference_not_found`, after
asking the unique fields in declared order, the unique `email` once, the
opted-out autonumber never;
- an opted-out autonumber's value answers `reference_not_found`;
- a unique field two records answer is `reference_ambiguous` and links
neither.
Measured on `main` 8cb8c7f before the fix: 4 of 6 red, the autonumber
cell answering `reference_not_found` (`expected ok: true`, received
`code: "reference_not_found"`, `field: "account"`).
Ablations on the fix commit, each restored from `HEAD` after the run:
| Ablation | Red |
|:---|:---|
| drop the unique-field candidates | 4 (autonumber, unique, not-found
order, ambiguity) |
| ask the unique fields first | 5, the order-control pin among them |
| ignore the `unique: false` opt-out | 2 (opt-out pin, declared-order
pin) |
| silently pick the first of several matches | 1 (ambiguity pin) |
| drop the de-duplication | 4 |
## Acceptance notes
- A cell that matches nothing now costs one query more per unique field
of the target before it answers `reference_not_found` (misses are not
cached, as before, so a repeated unmatched cell repeats them). Matching
cells cost what they did.
- An `organization`-scoped unique field read across organizations can
answer two records; that is reported `reference_ambiguous`, never a
silent pick.
## Verification
- Pins and ablations as above.
- Local gates: every family `node scripts/pm/dispatch-gates.mjs
--commands` derives for this diff, exit codes captured, reconciled with
`--ran`; `pnpm lint`. Counts are in the os-dev report on the card.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_016WV4czVnUdQQCVKSW5J2uk
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: objectstack-fleet[bot] <332303061+objectstack-fleet[bot]@users.noreply.github.com>1 parent 27e0bd5 commit d85ff19
3 files changed
Lines changed: 188 additions & 6 deletions
File tree
- .changeset
- packages/core/src/utils
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| |||
639 | 639 | | |
640 | 640 | | |
641 | 641 | | |
| 642 | + | |
642 | 643 | | |
643 | 644 | | |
644 | | - | |
| 645 | + | |
| 646 | + | |
645 | 647 | | |
646 | 648 | | |
647 | 649 | | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
648 | 669 | | |
649 | 670 | | |
650 | 671 | | |
| |||
662 | 683 | | |
663 | 684 | | |
664 | 685 | | |
665 | | - | |
| 686 | + | |
666 | 687 | | |
667 | | - | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
668 | 696 | | |
669 | | - | |
| 697 | + | |
670 | 698 | | |
671 | 699 | | |
672 | 700 | | |
| |||
821 | 849 | | |
822 | 850 | | |
823 | 851 | | |
824 | | - | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
825 | 856 | | |
826 | 857 | | |
827 | 858 | | |
| |||
836 | 867 | | |
837 | 868 | | |
838 | 869 | | |
| 870 | + | |
839 | 871 | | |
840 | 872 | | |
841 | 873 | | |
| |||
0 commit comments