push updates

This commit is contained in:
ehesp
2019-06-05 11:12:47 +01:00
parent ce0b15ceba
commit 8c33c889e6
9 changed files with 283 additions and 94 deletions

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
const { PATH, wipe } = require('./helpers');
const TEST_PATH = `${PATH}/issues`;
describe('database issues', () => {
after(() => wipe(TEST_PATH));
it('#100 array should return null where key is missing', async () => {
const ref = firebase.database().ref(`${TEST_PATH}/issue_100`);
const data = {
1: {
someKey: 'someValue',
someOtherKey: 'someOtherValue',
},
2: {
someKey: 'someValue',
someOtherKey: 'someOtherValue',
},
3: {
someKey: 'someValue',
someOtherKey: 'someOtherValue',
},
};
await ref.set(data);
const snapshot = await ref.once('value');
snapshot
.val()
.should.eql(
jet.contextify([
null,
jet.contextify(data[1]),
jet.contextify(data[2]),
jet.contextify(data[3]),
]),
);
});
describe('#108 filters correctly by float values', () => {
it('returns filtered results', async () => {
const ref = firebase.database().ref(`${TEST_PATH}/issue_108/filter`);
const data = {
foobar: {
name: 'Foobar Pizzas',
latitude: 34.1013717,
},
notTheFoobar: {
name: "Not the pizza you're looking for",
latitude: 34.456787,
},
notAFloat: {
name: 'Not a float',
latitude: 37,
},
};
await ref.set(data);
const snapshot = await ref
.orderByChild('latitude')
.startAt(34.00867000999119)
.endAt(34.17462960866099)
.once('value');
const val = snapshot.val();
val.foobar.should.eql(jet.contextify(data.foobar));
should.equal(Object.keys(val).length, 1);
});
it('returns correct results when not using float values', async () => {
const ref = firebase.database().ref(`${TEST_PATH}/issue_108/integer`);
const data = {
foobar: {
name: 'Foobar Pizzas',
latitude: 34.1013717,
},
notTheFoobar: {
name: "Not the pizza you're looking for",
latitude: 34.456787,
},
notAFloat: {
name: 'Not a float',
latitude: 37,
},
};
await ref.set(data);
const snapshot = await ref
.orderByChild('latitude')
.equalTo(37)
.once('value');
const val = snapshot.val();
val.notAFloat.should.eql(jet.contextify(data.notAFloat));
should.equal(Object.keys(val).length, 1);
});
});
it('#489 reutrns long numbers correctly', async () => {
const LONG = 1508777379000;
const ref = firebase.database().ref(`${TEST_PATH}/issue_489`);
await ref.set(LONG);
const snapshot = await ref.once('value');
snapshot.val().should.eql(LONG);
});
});

View File

@@ -55,6 +55,22 @@ describe('database().ref().onDisconnect().update()', () => {
}
});
it('throws if update paths are not valid', async () => {
try {
await firebase
.database()
.ref(TEST_PATH)
.onDisconnect()
.update({
$$$$: 'foo',
});
return Promise.reject(new Error('Did not throw an Error.'));
} catch (error) {
error.message.should.containEql(`'values' contains an invalid path.`);
return Promise.resolve();
}
});
it('throws if onComplete is not a function', () => {
const ref = firebase
.database()

View File

@@ -15,12 +15,27 @@
*
*/
// const { PATH, seed, wipe } = require('../helpers');
const { PATH, seed, wipe } = require('../helpers');
// const TEST_PATH = `${PATH}/push`;
const TEST_PATH = `${PATH}/push`;
xdescribe('database().ref().push()', () => {
describe.only('database().ref().push()', () => {
// before(() => seed(TEST_PATH));
// after(() => wipe(TEST_PATH));
// TODO
it('wraps Firebase.push when no value is passed', () => {
const ref = firebase.database().ref(`${TEST_PATH}/boop`);
const pushed = ref.push();
return pushed
.then(childRef => {
pushed.ref.parent.toString().should.eql(ref.toString());
pushed.toString().should.eql(childRef.toString());
return pushed.once('value');
})
.then(snap => {
should.equal(snap.val(), null);
snap.ref.toString().should.eql(pushed.toString());
});
});
});

View File

@@ -51,6 +51,21 @@ describe('database().ref().update()', () => {
}
});
it('throws if update paths are not valid', async () => {
try {
await firebase
.database()
.ref(TEST_PATH)
.update({
$$$$: 'foo',
});
return Promise.reject(new Error('Did not throw an Error.'));
} catch (error) {
error.message.should.containEql(`'values' contains an invalid path.`);
return Promise.resolve();
}
});
it('throws if onComplete is not a function', async () => {
try {
await firebase

View File

@@ -22,6 +22,7 @@ import {
isNumber,
isObject,
isString,
isValidPath,
isUndefined,
promiseWithOptionalCallback,
} from '@react-native-firebase/common';
@@ -125,7 +126,14 @@ export default class DatabaseOnDisconnect {
);
}
// TODO validate keys; / . # $ |
const keys = Object.keys(values);
for (let i = 0; i < keys.length; i++) {
if (!isValidPath(keys[i])) {
throw new Error(
`firebase.database().onDisconnect().update(*) 'values' contains an invalid path. Paths must be non-empty strings and can't contain ".", "#", "$", "[", or "]"`,
);
}
}
if (!isUndefined(onComplete) && !isFunction(onComplete)) {
throw new Error(

View File

@@ -21,7 +21,7 @@ import {
pathParent,
pathChild,
isValidPath,
// generateDatabaseId,
generateDatabaseId,
isNumber,
isNull,
isUndefined,
@@ -35,6 +35,7 @@ import DatabaseQuery from './DatabaseQuery';
import DatabaseQueryModifiers from './DatabaseQueryModifiers';
import DatabaseOnDisconnect from './DatabaseOnDisconnect';
import DatabaseDataSnapshot from './DatabaseDataSnapshot';
import DatabaseThenableReference from './DatabaseThenableReference';
const internalRefs = ['.info/connected', '.info/serverTimeOffset'];
@@ -113,7 +114,14 @@ export default class DatabaseReference extends DatabaseQuery {
);
}
// TODO validate keys
const keys = Object.keys(values);
for (let i = 0; i < keys.length; i++) {
if (!isValidPath(keys[i])) {
throw new Error(
`firebase.database().update(*) 'values' contains an invalid path. Paths must be non-empty strings and can't contain ".", "#", "$", "[", or "]"`,
);
}
}
if (!isUndefined(onComplete) && !isFunction(onComplete)) {
throw new Error(
@@ -250,15 +258,32 @@ export default class DatabaseReference extends DatabaseQuery {
* @param onComplete
* @returns {DatabaseReference}
*/
// push(value, onComplete) {
// TODO validate value?
//
// const id = generateDatabaseId(this._database._serverTime);
// const pushRef = this.child(id);
// const thennablePushRef = this.child(id);
//
// return thennablePushRef;
// }
push(value, onComplete) {
if (!isUndefined(onComplete) && !isFunction(onComplete)) {
throw new Error('TODO');
}
const id = generateDatabaseId(this._database._serverTime);
if (isUndefined(value) || isNull(value)) {
return new DatabaseThenableReference(
this._database,
pathChild(this.path, id),
Promise.resolve(this.child(id)),
);
}
const pushRef = this.child(id);
const promise = pushRef.set(value, onComplete).then(() => pushRef);
// Prevent unhandled promise rejection if onComplete is passed
if (onComplete) {
promise.catch(() => {});
}
return new DatabaseThenableReference(this._database, pathChild(this.path, id), promise);
}
/**
* @url https://firebase.google.com/docs/reference/js/firebase.database.Reference#ondisconnect

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2016-present Invertase Limited & Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this library except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import DatabaseReference from './DatabaseReference';
export default class DatabaseThenableReference extends DatabaseReference {
constructor(database, path, promise) {
super(database, path);
this._promise = promise;
}
get then() {
return this._promise.then.bind(this._promise);
}
get catch() {
return this._promise.catch.bind(this._promise);
}
}