@@ -437,6 +437,82 @@ describe('Scalar', () => {
437437 } ) ;
438438 } ) ;
439439
440+ describe ( 'nested array-of-records under a plain object schema (regression)' , ( ) => {
441+ // `[Scalar]` (or `Collection([Scalar])`) nested inside a plain object schema
442+ // — `{ stock: [Scalar] }` — must derive each item's entity pk from the item
443+ // itself, not from the parent's field name. Previously `Array.normalize`
444+ // forwarded its enclosing field name (e.g. `'stock'`) as `key` to each
445+ // child; `Scalar.entityPk` returned that key (since it was non-undefined),
446+ // collapsing every cell onto compound pk `Company|stock|<lens>` and
447+ // silently corrupting the data.
448+ it ( 'keys cells by item id, not by parent field name' , ( ) => {
449+ const objSchema = { stock : [ PortfolioScalar ] } ;
450+ const state = normalize (
451+ objSchema ,
452+ {
453+ stock : [
454+ { id : '1' , pct_equity : 0.7 , shares : 555 } ,
455+ { id : '2' , pct_equity : 0.1 , shares : 999 } ,
456+ ] ,
457+ } ,
458+ [ { portfolio : 'portfolioB' } ] ,
459+ ) ;
460+
461+ expect ( state . result ) . toEqual ( {
462+ stock : [ 'Company|1|portfolioB' , 'Company|2|portfolioB' ] ,
463+ } ) ;
464+ expect ( state . entities [ 'Scalar(portfolio)' ] ) . toMatchObject ( {
465+ 'Company|1|portfolioB' : {
466+ id : '1' ,
467+ pct_equity : 0.7 ,
468+ shares : 555 ,
469+ } ,
470+ 'Company|2|portfolioB' : {
471+ id : '2' ,
472+ pct_equity : 0.1 ,
473+ shares : 999 ,
474+ } ,
475+ } ) ;
476+ // Must not key any cell by the parent field name.
477+ expect (
478+ Object . keys ( state . entities [ 'Scalar(portfolio)' ] ?? { } ) . some ( k =>
479+ k . includes ( '|stock|' ) ,
480+ ) ,
481+ ) . toBe ( false ) ;
482+ } ) ;
483+
484+ it ( 'keys cells by item id when nested as Collection([Scalar])' , ( ) => {
485+ const columns = new Collection ( [ PortfolioScalar ] , {
486+ nestKey : ( parent : any , key : string ) => ( { portfolio : key } ) ,
487+ } ) ;
488+ const objSchema = { stock : columns } ;
489+ const state = normalize (
490+ objSchema ,
491+ {
492+ stock : [
493+ { id : '1' , pct_equity : 0.7 , shares : 555 } ,
494+ { id : '2' , pct_equity : 0.1 , shares : 999 } ,
495+ ] ,
496+ } ,
497+ [ { portfolio : 'portfolioB' } ] ,
498+ ) ;
499+
500+ // Cells are keyed by item id, not by the parent field name.
501+ expect ( state . entities [ 'Scalar(portfolio)' ] ) . toMatchObject ( {
502+ 'Company|1|portfolioB' : {
503+ id : '1' ,
504+ pct_equity : 0.7 ,
505+ shares : 555 ,
506+ } ,
507+ 'Company|2|portfolioB' : {
508+ id : '2' ,
509+ pct_equity : 0.1 ,
510+ shares : 999 ,
511+ } ,
512+ } ) ;
513+ } ) ;
514+ } ) ;
515+
440516 describe ( 'composite primary keys containing "|"' , ( ) => {
441517 class CompositeCompany extends IDEntity {
442518 type = '' ;
0 commit comments