Skip to content
This repository was archived by the owner on Mar 4, 2026. It is now read-only.

Commit 789d9eb

Browse files
fix: Update the depth validation used when writing documents (#1815)
fix: Update the depth validation used when writing documents, so that it matches the validation of the Firestore backend.
1 parent 653a8e9 commit 789d9eb

2 files changed

Lines changed: 247 additions & 1 deletion

File tree

dev/src/serializer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ export function validateUserInput(
312312
level?: number,
313313
inArray?: boolean
314314
): void {
315-
if (path && path.size > MAX_DEPTH) {
315+
if (path && path.size - 1 > MAX_DEPTH) {
316316
throw new Error(
317317
`${invalidArgumentMessage(
318318
arg,

dev/test/serializer.ts

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
// Copyright 2023 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import {it} from 'mocha';
16+
import {expect} from 'chai';
17+
import {validateUserInput} from '../src/serializer';
18+
19+
describe('validateUserInput', () => {
20+
it('validates the depth of nested objects and arrays - 20', () => {
21+
// This nested object is 20 levels deep
22+
const nestedObject = {
23+
// depth 0
24+
links: [
25+
// depth 1
26+
{
27+
// depth 2
28+
child: {
29+
// depth 3
30+
links: [
31+
// depth 4
32+
{
33+
// depth 5
34+
child: {
35+
// depth 6
36+
links: [
37+
// depth 7
38+
{
39+
// depth 8
40+
child: {
41+
// depth 9
42+
links: [
43+
// depth 10
44+
{
45+
// depth 11
46+
child: {
47+
// depth 12
48+
links: [
49+
// depth 13
50+
{
51+
// depth 14
52+
child: {
53+
// depth 15
54+
links: [
55+
// depth 16
56+
{
57+
// depth 17
58+
child: {
59+
// depth 18
60+
uiData: {
61+
// depth 19
62+
choicesFactors: {
63+
// depth 20
64+
rarely: 1,
65+
},
66+
},
67+
},
68+
},
69+
],
70+
},
71+
},
72+
],
73+
},
74+
},
75+
],
76+
},
77+
},
78+
],
79+
},
80+
},
81+
],
82+
},
83+
},
84+
],
85+
};
86+
87+
validateUserInput('nestedObject', nestedObject, 'Firestore Object', {
88+
allowDeletes: 'none',
89+
allowTransforms: false,
90+
allowUndefined: false,
91+
});
92+
});
93+
94+
it('validates the depth of nested objects and arrays - 21', () => {
95+
// This nested object is 21 levels deep
96+
const nestedObject = {
97+
// depth 0
98+
links: [
99+
// depth 1
100+
{
101+
// depth 2
102+
child: {
103+
// depth 3
104+
links: [
105+
// depth 4
106+
{
107+
// depth 5
108+
child: {
109+
// depth 6
110+
links: [
111+
// depth 7
112+
{
113+
// depth 8
114+
child: {
115+
// depth 9
116+
links: [
117+
// depth 10
118+
{
119+
// depth 11
120+
child: {
121+
// depth 12
122+
links: [
123+
// depth 13
124+
{
125+
// depth 14
126+
child: {
127+
// depth 15
128+
links: [
129+
// depth 16
130+
{
131+
// depth 17
132+
child: {
133+
// depth 18
134+
uiData: {
135+
// depth 19
136+
choicesFactors: {
137+
// depth 20
138+
rarely: {
139+
// depth 21
140+
cat: true,
141+
},
142+
},
143+
},
144+
},
145+
},
146+
],
147+
},
148+
},
149+
],
150+
},
151+
},
152+
],
153+
},
154+
},
155+
],
156+
},
157+
},
158+
],
159+
},
160+
},
161+
],
162+
};
163+
164+
expect(() =>
165+
validateUserInput('nestedObject', nestedObject, 'Firestore Object', {
166+
allowDeletes: 'none',
167+
allowTransforms: false,
168+
allowUndefined: false,
169+
})
170+
).to.throw(/Input object is deeper than 20 levels/i);
171+
});
172+
173+
it('validates the depth of nested objects - 20', () => {
174+
// This nested object is 20 levels deep
175+
const nestedObject = {
176+
a: {
177+
b: {
178+
c: {
179+
d: {
180+
e: {
181+
f: {
182+
g: {
183+
h: {
184+
i: {
185+
j: {
186+
k: {
187+
l: {m: {n: {o: {p: {q: {r: {s: {t: {u: 1}}}}}}}}},
188+
},
189+
},
190+
},
191+
},
192+
},
193+
},
194+
},
195+
},
196+
},
197+
},
198+
},
199+
};
200+
201+
validateUserInput('nestedObject', nestedObject, 'Firestore Object', {
202+
allowDeletes: 'none',
203+
allowTransforms: false,
204+
allowUndefined: false,
205+
});
206+
});
207+
208+
it('validates the depth of nested objects and arrays - 21', () => {
209+
// This nested object is 21 levels deep
210+
const nestedObject = {
211+
a: {
212+
b: {
213+
c: {
214+
d: {
215+
e: {
216+
f: {
217+
g: {
218+
h: {
219+
i: {
220+
j: {
221+
k: {
222+
l: {
223+
m: {n: {o: {p: {q: {r: {s: {t: {u: {v: 1}}}}}}}}},
224+
},
225+
},
226+
},
227+
},
228+
},
229+
},
230+
},
231+
},
232+
},
233+
},
234+
},
235+
},
236+
};
237+
238+
expect(() =>
239+
validateUserInput('nestedObject', nestedObject, 'Firestore Object', {
240+
allowDeletes: 'none',
241+
allowTransforms: false,
242+
allowUndefined: false,
243+
})
244+
).to.throw(/Input object is deeper than 20 levels/i);
245+
});
246+
});

0 commit comments

Comments
 (0)