Skip to content

Commit a0eb1df

Browse files
Merge branch 'master' into mrschmidt/pendingwrites
2 parents 8f47d7a + 3960fda commit a0eb1df

File tree

40 files changed

+530
-249
lines changed

40 files changed

+530
-249
lines changed

packages-exp/app-types-exp/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"license": "Apache-2.0",
88
"scripts": {
99
"test": "tsc",
10+
"test:ci": "node ../../scripts/run_tests_in_ci.js",
1011
"api-report": "api-extractor run --local --verbose",
1112
"predoc": "node ../../scripts/exp/remove-exp.js temp",
1213
"doc": "api-documenter markdown --input temp --output docs",

packages/analytics-interop-types/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
66
"license": "Apache-2.0",
77
"scripts": {
8-
"test": "tsc"
8+
"test": "tsc",
9+
"test:ci": "node ../../scripts/run_tests_in_ci.js"
910
},
1011
"files": [
1112
"index.d.ts"

packages/analytics-types/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
66
"license": "Apache-2.0",
77
"scripts": {
8-
"test": "tsc"
8+
"test": "tsc",
9+
"test:ci": "node ../../scripts/run_tests_in_ci.js"
910
},
1011
"files": [
1112
"index.d.ts"

packages/app-types/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
66
"license": "Apache-2.0",
77
"scripts": {
8-
"test": "tsc"
8+
"test": "tsc",
9+
"test:ci": "node ../../scripts/run_tests_in_ci.js"
910
},
1011
"files": [
1112
"index.d.ts",

packages/auth-interop-types/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
66
"license": "Apache-2.0",
77
"scripts": {
8-
"test": "tsc"
8+
"test": "tsc",
9+
"test:ci": "node ../../scripts/run_tests_in_ci.js"
910
},
1011
"files": [
1112
"index.d.ts"

packages/auth-types/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
66
"license": "Apache-2.0",
77
"scripts": {
8-
"test": "tsc"
8+
"test": "tsc",
9+
"test:ci": "node ../../scripts/run_tests_in_ci.js"
910
},
1011
"files": [
1112
"index.d.ts"

packages/database-types/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
66
"license": "Apache-2.0",
77
"scripts": {
8-
"test": "tsc"
8+
"test": "tsc",
9+
"test:ci": "node ../../scripts/run_tests_in_ci.js"
910
},
1011
"files": [
1112
"index.d.ts"

packages/database/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Unreleased
22
- [feature] Added ServerValue.increment() to support atomic field value increments
33
without transactions.
4+
- [fixed] Fixed Realtime Database URL parsing bug to support domains with more than 3 components.
45

56
# Released
67
- [fixed] Fixed an issue that caused large numeric values with leading zeros to

packages/database/src/core/util/libs/parser.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @license
3-
* Copyright 2017 Google Inc.
3+
* Copyright 2017 Google LLC
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -72,7 +72,7 @@ export const parseRepoInfo = function(
7272
const parsedUrl = parseDatabaseURL(dataURL),
7373
namespace = parsedUrl.namespace;
7474

75-
if (parsedUrl.domain === 'firebase') {
75+
if (parsedUrl.domain === 'firebase.com') {
7676
fatal(
7777
parsedUrl.host +
7878
' is no longer supported. ' +
@@ -171,20 +171,21 @@ export const parseDatabaseURL = function(
171171
secure = scheme === 'https' || scheme === 'wss';
172172
port = parseInt(host.substring(colonInd + 1), 10);
173173
} else {
174-
colonInd = dataURL.length;
174+
colonInd = host.length;
175175
}
176176

177-
const parts = host.split('.');
178-
if (parts.length === 3) {
177+
const hostWithoutPort = host.slice(0, colonInd);
178+
if (hostWithoutPort.toLowerCase() === 'localhost') {
179+
domain = 'localhost';
180+
} else if (hostWithoutPort.split('.').length <= 2) {
181+
domain = hostWithoutPort;
182+
} else {
183+
// Interpret the subdomain of a 3 or more component URL as the namespace name.
184+
const dotInd = host.indexOf('.');
185+
subdomain = host.substring(0, dotInd).toLowerCase();
186+
domain = host.substring(dotInd + 1);
179187
// Normalize namespaces to lowercase to share storage / connection.
180-
domain = parts[1];
181-
subdomain = parts[0].toLowerCase();
182-
// We interpret the subdomain of a 3 component URL as the namespace name.
183188
namespace = subdomain;
184-
} else if (parts.length === 2) {
185-
domain = parts[0];
186-
} else if (parts[0].slice(0, colonInd).toLowerCase() === 'localhost') {
187-
domain = 'localhost';
188189
}
189190
// Always treat the value of the `ns` as the namespace name if it is present.
190191
if ('ns' in queryParams) {

packages/database/test/database.test.ts

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @license
3-
* Copyright 2017 Google Inc.
3+
* Copyright 2017 Google LLC
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
66
* you may not use this file except in compliance with the License.
@@ -62,18 +62,49 @@ describe('Database Tests', () => {
6262
expect(db.ref().toString()).to.equal('https://foo.bar.com/');
6363
});
6464

65+
it('Can get database with multi-region URL', () => {
66+
const db = defaultApp.database('http://foo.euw1.firebasedatabase.app');
67+
expect(db).to.be.ok;
68+
expect(db.repo_.repoInfo_.namespace).to.equal('foo');
69+
expect(db.ref().toString()).to.equal(
70+
'https://foo.euw1.firebasedatabase.app/'
71+
);
72+
});
73+
74+
it('Can get database with upper case URL', () => {
75+
const db = defaultApp.database('http://fOO.EUW1.firebaseDATABASE.app');
76+
expect(db).to.be.ok;
77+
expect(db.repo_.repoInfo_.namespace).to.equal('foo');
78+
expect(db.ref().toString()).to.equal(
79+
'https://foo.euw1.firebasedatabase.app/'
80+
);
81+
});
82+
83+
it('Can get database with localhost URL', () => {
84+
const db = defaultApp.database('http://localhost');
85+
expect(db).to.be.ok;
86+
expect(db.ref().toString()).to.equal('https://localhost/');
87+
});
88+
6589
it('Can get database with localhost URL and port', () => {
6690
const db = defaultApp.database('http://localhost:80');
6791
expect(db).to.be.ok;
6892
expect(db.ref().toString()).to.equal('http://localhost:80/');
6993
});
7094

71-
it('Can get database with localhost URL', () => {
72-
const db = defaultApp.database('http://localhost');
95+
it('Can get database with a upper case localhost URL', () => {
96+
const db = defaultApp.database('http://LOCALHOST');
7397
expect(db).to.be.ok;
7498
expect(db.ref().toString()).to.equal('https://localhost/');
7599
});
76100

101+
it('Can get database with a upper case localhost URL and ns', () => {
102+
const db = defaultApp.database('http://LOCALHOST?ns=foo');
103+
expect(db).to.be.ok;
104+
expect(db.repo_.repoInfo_.namespace).to.equal('foo');
105+
expect(db.ref().toString()).to.equal('https://localhost/');
106+
});
107+
77108
it('Can read ns query param', () => {
78109
const db = defaultApp.database('http://localhost:80/?ns=foo&unused=true');
79110
expect(db).to.be.ok;
@@ -111,10 +142,19 @@ describe('Database Tests', () => {
111142
}).to.throw(/Database initialized multiple times/i);
112143
});
113144

145+
it('Databases with legacy domain', () => {
146+
expect(() => {
147+
defaultApp.database('http://foo.firebase.com/');
148+
}).to.throw(/is no longer supported/i);
149+
});
150+
114151
it('Databases with invalid custom URLs', () => {
115152
expect(() => {
116153
defaultApp.database('not-a-url');
117154
}).to.throw(/Cannot parse Firebase url/i);
155+
expect(() => {
156+
defaultApp.database('http://foo.com');
157+
}).to.throw(/Cannot parse Firebase url/i);
118158
expect(() => {
119159
defaultApp.database('http://fblocal.com');
120160
}).to.throw(/Cannot parse Firebase url/i);

packages/firestore-types/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
66
"license": "Apache-2.0",
77
"scripts": {
8-
"test": "tsc"
8+
"test": "tsc",
9+
"test:ci": "node ../../scripts/run_tests_in_ci.js"
910
},
1011
"files": [
1112
"index.d.ts"

packages/firestore/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# Unreleased
2+
- [fixed] Fixed a regression introduced in v7.14.2 that incorrectly applied
3+
a `FieldValue.increment` in combination with `set({...}, {merge: true})`.
24
- [fixed] Firestore now rejects `onSnapshot()` listeners if they cannot be
35
registered in IndexedDB. Previously, these errors crashed the client.
46
- [fixed] Firestore now rejects write operations if they cannot be persisted

packages/firestore/src/api/field_value.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,17 @@ export class ArrayUnionFieldValueImpl extends FieldValueImpl {
102102
// Although array transforms are used with writes, the actual elements
103103
// being uniomed or removed are not considered writes since they cannot
104104
// contain any FieldValue sentinels, etc.
105-
const parseContext = context.contextWith({
106-
dataSource: UserDataSource.Argument,
107-
methodName: this._methodName
108-
});
105+
const parseContext = new ParseContext(
106+
{
107+
dataSource: UserDataSource.Argument,
108+
methodName: this._methodName,
109+
arrayElement: true
110+
},
111+
context.databaseId,
112+
context.serializer
113+
);
109114
const parsedElements = this._elements.map(
110-
(element, i) => parseData(element, parseContext.childContextForArray(i))!
115+
element => parseData(element, parseContext)!
111116
);
112117
const arrayUnion = new ArrayUnionTransformOperation(parsedElements);
113118
return new FieldTransform(context.path!, arrayUnion);
@@ -128,12 +133,17 @@ export class ArrayRemoveFieldValueImpl extends FieldValueImpl {
128133
// Although array transforms are used with writes, the actual elements
129134
// being unioned or removed are not considered writes since they cannot
130135
// contain any FieldValue sentinels, etc.
131-
const parseContext = context.contextWith({
132-
dataSource: UserDataSource.Argument,
133-
methodName: this._methodName
134-
});
136+
const parseContext = new ParseContext(
137+
{
138+
dataSource: UserDataSource.Argument,
139+
methodName: this._methodName,
140+
arrayElement: true
141+
},
142+
context.databaseId,
143+
context.serializer
144+
);
135145
const parsedElements = this._elements.map(
136-
(element, i) => parseData(element, parseContext.childContextForArray(i))!
146+
element => parseData(element, parseContext)!
137147
);
138148
const arrayUnion = new ArrayRemoveTransformOperation(parsedElements);
139149
return new FieldTransform(context.path!, arrayUnion);
@@ -151,8 +161,15 @@ export class NumericIncrementFieldValueImpl extends FieldValueImpl {
151161
}
152162

153163
toFieldTransform(context: ParseContext): FieldTransform {
154-
context.contextWith({ methodName: this._methodName });
155-
const operand = parseData(this._operand, context)!;
164+
const parseContext = new ParseContext(
165+
{
166+
dataSource: UserDataSource.Argument,
167+
methodName: this._methodName
168+
},
169+
context.databaseId,
170+
context.serializer
171+
);
172+
const operand = parseData(this._operand, parseContext)!;
156173
const numericIncrement = new NumericIncrementTransformOperation(
157174
context.serializer,
158175
operand

packages/firestore/src/api/user_data_reader.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,12 @@ interface ContextSettings {
140140
* nonempty path (indicating the context represents a nested location within
141141
* the data).
142142
*/
143-
readonly path: FieldPath | null;
144-
/** Whether or not this context corresponds to an element of an array. */
145-
readonly arrayElement: boolean;
143+
readonly path?: FieldPath;
144+
/**
145+
* Whether or not this context corresponds to an element of an array.
146+
* If not set, elements are treated as if they were outside of arrays.
147+
*/
148+
readonly arrayElement?: boolean;
146149
}
147150

148151
/** A "context" object passed around while parsing user data. */
@@ -181,7 +184,7 @@ export class ParseContext {
181184
this.fieldMask = fieldMask || [];
182185
}
183186

184-
get path(): FieldPath | null {
187+
get path(): FieldPath | undefined {
185188
return this.settings.path;
186189
}
187190

@@ -201,28 +204,28 @@ export class ParseContext {
201204
}
202205

203206
childContextForField(field: string): ParseContext {
204-
const childPath = this.path == null ? null : this.path.child(field);
207+
const childPath = this.path?.child(field);
205208
const context = this.contextWith({ path: childPath, arrayElement: false });
206209
context.validatePathSegment(field);
207210
return context;
208211
}
209212

210213
childContextForFieldPath(field: FieldPath): ParseContext {
211-
const childPath = this.path == null ? null : this.path.child(field);
214+
const childPath = this.path?.child(field);
212215
const context = this.contextWith({ path: childPath, arrayElement: false });
213216
context.validatePath();
214217
return context;
215218
}
216219

217220
childContextForArray(index: number): ParseContext {
218221
// TODO(b/34871131): We don't support array paths right now; so make path
219-
// null.
220-
return this.contextWith({ path: null, arrayElement: true });
222+
// undefined.
223+
return this.contextWith({ path: undefined, arrayElement: true });
221224
}
222225

223226
createError(reason: string): Error {
224227
const fieldDescription =
225-
this.path === null || this.path.isEmpty()
228+
!this.path || this.path.isEmpty()
226229
? ''
227230
: ` (found in field ${this.path.toString()})`;
228231
return new FirestoreError(
@@ -246,7 +249,7 @@ export class ParseContext {
246249
private validatePath(): void {
247250
// TODO(b/34871131): Remove null check once we have proper paths for fields
248251
// within arrays.
249-
if (this.path === null) {
252+
if (!this.path) {
250253
return;
251254
}
252255
for (let i = 0; i < this.path.length; i++) {

0 commit comments

Comments
 (0)