@@ -1286,7 +1286,7 @@ describe('withConverter() support', () => {
12861286 }
12871287 } ;
12881288
1289- describe ( 'NestedPartial ' , ( ) => {
1289+ describe ( 'nested partial support ' , ( ) => {
12901290 const testConverterMerge = {
12911291 toFirestore (
12921292 testObj : PartialWithFieldValue < TestObject > ,
@@ -1399,6 +1399,44 @@ describe('withConverter() support', () => {
13991399 ) ;
14001400 } ) ;
14011401 } ) ;
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+ } ) ;
14021440 } ) ;
14031441
14041442 describe ( 'WithFieldValue' , ( ) => {
@@ -1421,7 +1459,7 @@ describe('withConverter() support', () => {
14211459 } ) ;
14221460 } ) ;
14231461
1424- it ( 'requires all fields to be present' , async ( ) => {
1462+ it ( 'requires all outer fields to be present' , async ( ) => {
14251463 return withTestDoc ( async doc => {
14261464 const ref = doc . withConverter ( testConverter ) ;
14271465
@@ -1440,6 +1478,24 @@ describe('withConverter() support', () => {
14401478 } ) ;
14411479 } ) ;
14421480
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+
14431499 it ( 'validates inner and outer fields' , async ( ) => {
14441500 return withTestDoc ( async doc => {
14451501 const ref = doc . withConverter ( testConverter ) ;
@@ -1496,6 +1552,77 @@ describe('withConverter() support', () => {
14961552 } ) ;
14971553 } ) ;
14981554 } ) ;
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+ } ) ;
14991626 } ) ;
15001627
15011628 describe ( 'UpdateData' , ( ) => {
0 commit comments