@@ -1286,7 +1286,7 @@ describe('withConverter() support', () => {
1286
1286
}
1287
1287
} ;
1288
1288
1289
- describe ( 'NestedPartial ' , ( ) => {
1289
+ describe ( 'nested partial support ' , ( ) => {
1290
1290
const testConverterMerge = {
1291
1291
toFirestore (
1292
1292
testObj : PartialWithFieldValue < TestObject > ,
@@ -1399,6 +1399,44 @@ describe('withConverter() support', () => {
1399
1399
) ;
1400
1400
} ) ;
1401
1401
} ) ;
1402
+
1403
+ it ( 'allows omitting fields' , async ( ) => {
1404
+ return withTestDoc ( async doc => {
1405
+ const ref = doc . withConverter ( testConverterMerge ) ;
1406
+
1407
+ // Omit outer fields
1408
+ await setDoc (
1409
+ ref ,
1410
+ {
1411
+ outerString : deleteField ( ) ,
1412
+ nested : {
1413
+ innerNested : {
1414
+ innerNestedNum : increment ( 1 )
1415
+ } ,
1416
+ innerArr : arrayUnion ( 2 ) ,
1417
+ timestamp : serverTimestamp ( )
1418
+ }
1419
+ } ,
1420
+ { merge : true }
1421
+ ) ;
1422
+
1423
+ // Omit inner fields
1424
+ await setDoc (
1425
+ ref ,
1426
+ {
1427
+ outerString : deleteField ( ) ,
1428
+ outerArr : [ ] ,
1429
+ nested : {
1430
+ innerNested : {
1431
+ innerNestedNum : increment ( 1 )
1432
+ } ,
1433
+ timestamp : serverTimestamp ( )
1434
+ }
1435
+ } ,
1436
+ { merge : true }
1437
+ ) ;
1438
+ } ) ;
1439
+ } ) ;
1402
1440
} ) ;
1403
1441
1404
1442
describe ( 'WithFieldValue' , ( ) => {
@@ -1421,7 +1459,7 @@ describe('withConverter() support', () => {
1421
1459
} ) ;
1422
1460
} ) ;
1423
1461
1424
- it ( 'requires all fields to be present' , async ( ) => {
1462
+ it ( 'requires all outer fields to be present' , async ( ) => {
1425
1463
return withTestDoc ( async doc => {
1426
1464
const ref = doc . withConverter ( testConverter ) ;
1427
1465
@@ -1440,6 +1478,24 @@ describe('withConverter() support', () => {
1440
1478
} ) ;
1441
1479
} ) ;
1442
1480
1481
+ it ( 'requires all nested fields to be present' , async ( ) => {
1482
+ return withTestDoc ( async doc => {
1483
+ const ref = doc . withConverter ( testConverter ) ;
1484
+
1485
+ await setDoc ( ref , {
1486
+ outerString : 'foo' ,
1487
+ outerArr : [ ] ,
1488
+ // @ts -expect-error
1489
+ nested : {
1490
+ innerNested : {
1491
+ innerNestedNum : increment ( 1 )
1492
+ } ,
1493
+ timestamp : serverTimestamp ( )
1494
+ }
1495
+ } ) ;
1496
+ } ) ;
1497
+ } ) ;
1498
+
1443
1499
it ( 'validates inner and outer fields' , async ( ) => {
1444
1500
return withTestDoc ( async doc => {
1445
1501
const ref = doc . withConverter ( testConverter ) ;
@@ -1496,6 +1552,77 @@ describe('withConverter() support', () => {
1496
1552
} ) ;
1497
1553
} ) ;
1498
1554
} ) ;
1555
+
1556
+ it ( 'allows certain types but not others' , ( ) => {
1557
+ const withTryCatch = async ( fn : ( ) => Promise < void > ) : Promise < void > => {
1558
+ try {
1559
+ await fn ( ) ;
1560
+ } catch { }
1561
+ } ;
1562
+
1563
+ // These tests exist to establish which object types are allowed to be
1564
+ // passed in by default when `T = DocumentData`. Some objects extend
1565
+ // the Javascript `{}`, which is why they're allowed whereas others
1566
+ // throw an error.
1567
+ return withTestDoc ( async doc => {
1568
+ // @ts -expect-error
1569
+ await withTryCatch ( ( ) => setDoc ( doc , 1 ) ) ;
1570
+ // @ts -expect-error
1571
+ await withTryCatch ( ( ) => setDoc ( doc , 'foo' ) ) ;
1572
+ // @ts -expect-error
1573
+ await withTryCatch ( ( ) => setDoc ( doc , false ) ) ;
1574
+ await withTryCatch ( ( ) => setDoc ( doc , undefined ) ) ;
1575
+ await withTryCatch ( ( ) => setDoc ( doc , null ) ) ;
1576
+ await withTryCatch ( ( ) => setDoc ( doc , [ 0 ] ) ) ;
1577
+ await withTryCatch ( ( ) => setDoc ( doc , new Set < string > ( ) ) ) ;
1578
+ await withTryCatch ( ( ) => setDoc ( doc , new Map < string , number > ( ) ) ) ;
1579
+ } ) ;
1580
+ } ) ;
1581
+
1582
+ describe ( 'used as a type' , ( ) => {
1583
+ class ObjectWrapper < T > {
1584
+ withFieldValueT ( value : WithFieldValue < T > ) : WithFieldValue < T > {
1585
+ return value ;
1586
+ }
1587
+
1588
+ withPartialFieldValueT (
1589
+ value : PartialWithFieldValue < T >
1590
+ ) : PartialWithFieldValue < T > {
1591
+ return value ;
1592
+ }
1593
+
1594
+ // Wrapper to avoid having Firebase types in non-Firebase code.
1595
+ withT ( value : T ) : void {
1596
+ this . withFieldValueT ( value ) ;
1597
+ }
1598
+
1599
+ // Wrapper to avoid having Firebase types in non-Firebase code.
1600
+ withPartialT ( value : Partial < T > ) : void {
1601
+ this . withPartialFieldValueT ( value ) ;
1602
+ }
1603
+ }
1604
+
1605
+ it ( 'supports passing in the object as `T`' , ( ) => {
1606
+ interface Foo {
1607
+ id : string ;
1608
+ foo : number ;
1609
+ }
1610
+ const foo = new ObjectWrapper < Foo > ( ) ;
1611
+ foo . withFieldValueT ( { id : '' , foo : increment ( 1 ) } ) ;
1612
+ foo . withPartialFieldValueT ( { foo : increment ( 1 ) } ) ;
1613
+ foo . withT ( { id : '' , foo : 1 } ) ;
1614
+ foo . withPartialT ( { foo : 1 } ) ;
1615
+ } ) ;
1616
+
1617
+ it ( 'does not allow primitive types to use FieldValue' , ( ) => {
1618
+ type Bar = number ;
1619
+ const bar = new ObjectWrapper < Bar > ( ) ;
1620
+ // @ts -expect-error
1621
+ bar . withFieldValueT ( increment ( 1 ) ) ;
1622
+ // @ts -expect-error
1623
+ bar . withPartialFieldValueT ( increment ( 1 ) ) ;
1624
+ } ) ;
1625
+ } ) ;
1499
1626
} ) ;
1500
1627
1501
1628
describe ( 'UpdateData' , ( ) => {
0 commit comments