diff --git a/packages/app/lib/common/index.js b/packages/app/lib/common/index.js index c731d7f341..aff69744e8 100644 --- a/packages/app/lib/common/index.js +++ b/packages/app/lib/common/index.js @@ -268,6 +268,47 @@ const mapOfDeprecationReplacements = { setCrashlyticsCollectionEnabled: 'setCrashlyticsCollectionEnabled()', }, }, + + database: { + default: { + useEmulator: 'connectDatabaseEmulator()', + goOffline: 'goOffline()', + goOnline: 'goOnline()', + ref: 'ref()', + refFromURL: 'refFromURL()', + setPersistenceEnabled: 'setPersistenceEnabled()', + setLoggingEnabled: 'setLoggingEnabled()', + setPersistenceCacheSizeBytes: 'setPersistenceCacheSizeBytes()', + getServerTime: 'getServerTime()', + }, + statics: { + ServerValue: 'ServerValue', + }, + DatabaseReference: { + child: 'child()', + set: 'set()', + update: 'update()', + setWithPriority: 'setWithPriority()', + remove: 'remove()', + on: 'onValue()', + once: 'get()', + endAt: 'endAt()', + endBefore: 'endBefore()', + startAt: 'startAt()', + startAfter: 'startAfter()', + limitToFirst: 'limitToFirst()', + limitToLast: 'limitToLast()', + orderByChild: 'orderByChild()', + orderByKey: 'orderByKey()', + orderByValue: 'orderByValue()', + equalTo: 'equalTo()', + setPriority: 'setPriority()', + push: 'push()', + onDisconnect: 'onDisconnect()', + keepSynced: 'keepSynced()', + transaction: 'runTransaction()', + }, + }, firestore: { default: { batch: 'writeBatch()', @@ -519,6 +560,9 @@ export function createMessage( } function getNamespace(target) { + if (target.constructor.name === 'DatabaseReference') { + return 'database'; + } if (target.GeoPoint || target.CustomProvider) { // target is statics object. GeoPoint - Firestore, CustomProvider - AppCheck return 'firestore'; @@ -529,7 +573,6 @@ function getNamespace(target) { if (target.constructor.name === 'StorageReference') { return 'storage'; } - const className = target.name ? target.name : target.constructor.name; return Object.keys(mapOfDeprecationReplacements).find(key => { if (mapOfDeprecationReplacements[key][className]) { @@ -543,6 +586,9 @@ function getInstanceName(target) { // target is statics object. GeoPoint - Firestore, CustomProvider - AppCheck return 'statics'; } + if (target.ServerValue) { + return 'statics'; + } if (target._config) { // module class instance, we use default to store map of deprecated methods return 'default'; @@ -625,6 +671,9 @@ export function createDeprecationProxy(instance) { ) { deprecationConsoleWarning('messaging', prop, 'statics', false); } + if (prop === 'ServerValue') { + deprecationConsoleWarning('database', prop, 'statics', false); + } if (prop !== 'setLogLevel') { // we want to capture setLogLevel function call which we do below diff --git a/packages/database/__tests__/database.test.ts b/packages/database/__tests__/database.test.ts index 2d9e3b5adf..96005442e8 100644 --- a/packages/database/__tests__/database.test.ts +++ b/packages/database/__tests__/database.test.ts @@ -1,4 +1,4 @@ -import { afterAll, beforeAll, describe, expect, it } from '@jest/globals'; +import { afterAll, beforeAll, describe, expect, it, beforeEach, jest } from '@jest/globals'; import database, { firebase, @@ -46,8 +46,17 @@ import database, { push, remove, update, + ServerValue, } from '../lib'; +import { + createCheckV9Deprecation, + CheckV9DeprecationFunction, +} from '../../app/lib/common/unitTestUtils'; + +// @ts-ignore test +import FirebaseModule from '../../app/lib/internal/FirebaseModule'; + describe('Database', function () { describe('namespace', function () { beforeAll(async function () { @@ -283,4 +292,346 @@ describe('Database', function () { expect(update).toBeDefined(); }); }); + + describe('test `console.warn` is called for RNFB v8 API & not called for v9 API', function () { + let databaseV9Deprecation: CheckV9DeprecationFunction; + let staticsV9Deprecation: CheckV9DeprecationFunction; + let referenceV9Deprecation: CheckV9DeprecationFunction; + + beforeEach(function () { + databaseV9Deprecation = createCheckV9Deprecation(['database']); + staticsV9Deprecation = createCheckV9Deprecation(['database', 'statics']); + referenceV9Deprecation = createCheckV9Deprecation(['database', 'DatabaseReference']); + // @ts-ignore test + jest.spyOn(FirebaseModule.prototype, 'native', 'get').mockImplementation(() => { + return new Proxy( + {}, + { + get: (_target, prop) => { + if (prop === 'constants') { + return { + isDatabaseCollectionEnabled: true, + url: 'https://test.firebaseio.com', + ref: 'ref()', + }; + } + // Mock the once method to return proper snapshot data + if (prop === 'once') { + return jest.fn().mockResolvedValue({ + key: 'test', + value: 'mock_value', + exists: true, + childKeys: [], + priority: null, + } as never); + } + return jest.fn().mockResolvedValue({ + constants: { + isDatabaseCollectionEnabled: true, + url: 'https://test.firebaseio.com', + }, + } as never); + }, + }, + ); + }); + }); + + it('useEmulator', function () { + const db = getDatabase(); + databaseV9Deprecation( + () => connectDatabaseEmulator(db, 'localhost', 9000), + () => db.useEmulator('localhost', 9000), + 'useEmulator', + ); + }); + + it('goOffline', function () { + const db = getDatabase(); + databaseV9Deprecation( + () => goOffline(db), + () => db.goOffline(), + 'goOffline', + ); + }); + + it('goOnline', function () { + const db = getDatabase(); + databaseV9Deprecation( + () => goOnline(db), + () => db.goOnline(), + 'goOnline', + ); + }); + + it('ref', function () { + const db = getDatabase(); + databaseV9Deprecation( + () => ref(db, 'test'), + () => db.ref('test'), + 'ref', + ); + }); + + it('refFromURL', function () { + const db = getDatabase(); + // Mock the _customUrlOrRegion property directly on the database instance + (db as any)._customUrlOrRegion = 'https://test.firebaseio.com'; + databaseV9Deprecation( + () => refFromURL(db, 'https://test.firebaseio.com'), + () => db.refFromURL('https://test.firebaseio.com'), + 'refFromURL', + ); + }); + + it('setPersistenceEnabled', function () { + const db = getDatabase(); + databaseV9Deprecation( + () => setPersistenceEnabled(db, true), + () => db.setPersistenceEnabled(true), + 'setPersistenceEnabled', + ); + }); + + it('setLoggingEnabled', function () { + const db = getDatabase(); + databaseV9Deprecation( + () => setLoggingEnabled(db, true), + () => db.setLoggingEnabled(true), + 'setLoggingEnabled', + ); + }); + + it('setPersistenceCacheSizeBytes', function () { + const db = getDatabase(); + databaseV9Deprecation( + () => setPersistenceCacheSizeBytes(db, 10000000), + () => db.setPersistenceCacheSizeBytes(10000000), + 'setPersistenceCacheSizeBytes', + ); + }); + + it('getServerTime', function () { + const db = getDatabase(); + databaseV9Deprecation( + () => getServerTime(db), + () => db.getServerTime(), + 'getServerTime', + ); + }); + + describe('statics', function () { + it('ServerValue', function () { + staticsV9Deprecation( + () => ServerValue, + () => firebase.database.ServerValue, + 'ServerValue', + ); + }); + }); + + describe('DatabaseReference', function () { + it('child', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => child(testRef, 'child'), + () => testRef.child('child'), + 'child', + ); + }); + + it('set', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => set(testRef, 'value'), + () => testRef.set('value'), + 'set', + ); + }); + + it('update', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => update(testRef, { value: 'value' }), + () => testRef.update({ value: 'value' }), + 'update', + ); + }); + + it('setWithPriority', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => setWithPriority(testRef, 'value', 1), + () => testRef.setWithPriority('value', 1), + 'setWithPriority', + ); + }); + + it('remove', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => remove(testRef), + () => testRef.remove(), + 'remove', + ); + }); + + it('onValue', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => onValue(testRef, () => {}), + () => testRef.on('value', () => {}), + 'on', + ); + }); + + it('get', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => get(testRef), + () => testRef.once('value'), + 'once', + ); + }); + + it('endAt', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => query(testRef, endAt('value')), + () => testRef.endAt('value'), + 'endAt', + ); + }); + + it('startAt', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => query(testRef, startAt('value')), + () => testRef.startAt('value'), + 'startAt', + ); + }); + + it('limitToFirst', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => query(testRef, limitToFirst(10)), + () => testRef.limitToFirst(10), + 'limitToFirst', + ); + }); + + it('limitToLast', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => query(testRef, limitToLast(10)), + () => testRef.limitToLast(10), + 'limitToLast', + ); + }); + + it('orderByChild', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => query(testRef, orderByChild('name')), + () => testRef.orderByChild('name'), + 'orderByChild', + ); + }); + + it('orderByKey', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => query(testRef, orderByKey()), + () => testRef.orderByKey(), + 'orderByKey', + ); + }); + + it('orderByValue', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => query(testRef, orderByValue()), + () => testRef.orderByValue(), + 'orderByValue', + ); + }); + + it('equalTo', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => query(testRef, equalTo('value')), + () => testRef.equalTo('value'), + 'equalTo', + ); + }); + + it('setPriority', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => setPriority(testRef, 'value'), + () => testRef.setPriority('value'), + 'setPriority', + ); + }); + + it('push', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => push(testRef, 'value'), + () => testRef.push('value'), + 'push', + ); + }); + + it('onDisconnect', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => onDisconnect(testRef), + () => testRef.onDisconnect(), + 'onDisconnect', + ); + }); + + it('keepSynced', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => keepSynced(testRef, true), + () => testRef.keepSynced(true), + 'keepSynced', + ); + }); + }); + + describe('DatabaseTransaction', function () { + it('runTransaction', function () { + const db = getDatabase(); + const testRef = ref(db, 'test'); + referenceV9Deprecation( + () => runTransaction(testRef, currentData => currentData, { applyLocally: true }), + () => testRef.transaction(currentData => currentData, undefined, true), + 'transaction', + ); + }); + }); + }); }); diff --git a/packages/database/e2e/DatabaseStatics.e2e.js b/packages/database/e2e/DatabaseStatics.e2e.js index f1f2aba603..28712c57ee 100644 --- a/packages/database/e2e/DatabaseStatics.e2e.js +++ b/packages/database/e2e/DatabaseStatics.e2e.js @@ -100,10 +100,10 @@ describe('database.X', function () { }); it('populates the property with a Unix timestamp', async function () { - const { serverTimestamp, getDatabase, ref, set } = databaseModular; + const { serverTimestamp, getDatabase, ref, set, get } = databaseModular; const dbRef = ref(getDatabase(), `${TEST_PATH}/timestamp`); await set(dbRef, serverTimestamp()); - const snapshot = await dbRef.once('value'); + const snapshot = await get(dbRef, 'value'); snapshot.val().should.be.a.Number(); }); }); diff --git a/packages/database/e2e/helpers.js b/packages/database/e2e/helpers.js index d93c769a28..614fe72a79 100644 --- a/packages/database/e2e/helpers.js +++ b/packages/database/e2e/helpers.js @@ -52,10 +52,10 @@ const CONTENT = { }; exports.seed = function seed(path) { - const { getDatabase, ref } = databaseModular; + const { getDatabase, ref, set } = databaseModular; return Promise.all([ - ref(getDatabase(), `${path}/types`).set(CONTENT.TYPES), - ref(getDatabase(), `${path}/query`).set(CONTENT.QUERY), + set(ref(getDatabase(), `${path}/types`), CONTENT.TYPES), + set(ref(getDatabase(), `${path}/query`), CONTENT.QUERY), // The database emulator does not load rules correctly. We force them pre-test. // TODO(ehesp): This is current erroring - however without it, we can't test rules. testingUtils.initializeTestEnvironment({ @@ -71,8 +71,8 @@ exports.seed = function seed(path) { }; exports.wipe = function wipe(path) { - const { getDatabase, ref } = databaseModular; - return ref(getDatabase(), path).remove(); + const { getDatabase, ref, remove } = databaseModular; + return remove(ref(getDatabase(), path)); }; exports.PATH = PATH; diff --git a/packages/database/e2e/onDisconnect/cancel.e2e.js b/packages/database/e2e/onDisconnect/cancel.e2e.js index 365c3c4650..357cd4e20c 100644 --- a/packages/database/e2e/onDisconnect/cancel.e2e.js +++ b/packages/database/e2e/onDisconnect/cancel.e2e.js @@ -105,11 +105,11 @@ describe('database().ref().onDisconnect().cancel()', function () { }); it('cancels all previously queued events', async function () { - const { getDatabase, ref, onDisconnect, goOffline, goOnline, get } = databaseModular; + const { getDatabase, ref, onDisconnect, goOffline, goOnline, get, set } = databaseModular; const db = getDatabase(); const dbRef = ref(db, TEST_PATH); - await dbRef.set('foobar'); + await set(dbRef, 'foobar'); const value = Date.now(); await onDisconnect(dbRef).set(value); diff --git a/packages/database/e2e/onDisconnect/update.e2e.js b/packages/database/e2e/onDisconnect/update.e2e.js index 08b2b36464..db8c072f5d 100644 --- a/packages/database/e2e/onDisconnect/update.e2e.js +++ b/packages/database/e2e/onDisconnect/update.e2e.js @@ -214,14 +214,14 @@ describe('database().ref().onDisconnect().update()', function () { }); it('calls back to the onComplete function', async function () { - const { getDatabase, ref, onDisconnect, goOffline, goOnline } = databaseModular; + const { getDatabase, ref, onDisconnect, goOffline, goOnline, set } = databaseModular; const db = getDatabase(); const callback = sinon.spy(); const dbRef = ref(db, TEST_PATH); // Set an initial value - await dbRef.set('foo'); + await set(dbRef, 'foo'); await onDisconnect(dbRef).update({ foo: 'bar' }, callback); await goOffline(db); await goOnline(db); diff --git a/packages/database/e2e/query/on.e2e.js b/packages/database/e2e/query/on.e2e.js index 105259986a..6f4c6bb45b 100644 --- a/packages/database/e2e/query/on.e2e.js +++ b/packages/database/e2e/query/on.e2e.js @@ -115,7 +115,7 @@ describe('database().ref().on()', function () { await Utils.sleep(100); await ref.set('bar'); await Utils.spyToBeCalledTimesAsync(callback, 2); - ref.off('value'); + await ref.off('value'); callback.getCall(0).args[0].should.equal('foo'); callback.getCall(1).args[0].should.equal('bar'); }); diff --git a/packages/database/e2e/query/onChildMoved.e2e.js b/packages/database/e2e/query/onChildMoved.e2e.js index 60ea239295..acaa0f4ab4 100644 --- a/packages/database/e2e/query/onChildMoved.e2e.js +++ b/packages/database/e2e/query/onChildMoved.e2e.js @@ -35,7 +35,7 @@ describe('onChildMoved', function () { this.skip(); } - const { getDatabase, ref, query, orderByChild, set, child, onChildMoved } = databaseModular; + const { getDatabase, ref, set, child, onChildMoved, query, orderByChild } = databaseModular; const dbRef = ref(getDatabase(), `${TEST_PATH}/childMoved`); const orderedRef = query(dbRef, orderByChild('nuggets')); @@ -69,7 +69,7 @@ describe('onChildMoved', function () { if (Platform.other) { this.skip(); } - const { getDatabase, ref, query, orderByChild, onChildMoved, set, child } = databaseModular; + const { getDatabase, ref, onChildMoved, set, child, query, orderByChild } = databaseModular; const callback = sinon.spy(); const dbRef = ref(getDatabase(), `${TEST_PATH}/childMoved2`); diff --git a/packages/database/e2e/reference/push.e2e.js b/packages/database/e2e/reference/push.e2e.js index c479a08543..69f48d4f1c 100644 --- a/packages/database/e2e/reference/push.e2e.js +++ b/packages/database/e2e/reference/push.e2e.js @@ -107,38 +107,34 @@ describe('database().ref().push()', function () { }); describe('modular', function () { - it('returns a promise when no value is passed', function () { - const { getDatabase, ref, push } = databaseModular; + it('returns a Promise when a value is passed', function () { + const { getDatabase, ref, push, get } = databaseModular; const dbRef = ref(getDatabase(), `${TEST_PATH}/boop`); - const pushed = push(dbRef); + const pushed = push(dbRef, null); + return pushed .then(childRef => { - pushed.ref.parent.toString().should.eql(dbRef.toString()); - pushed.toString().should.eql(childRef.toString()); - return pushed.once('value'); + childRef.should.have.property('key').which.is.a.String(); + return get(childRef); }) .then(snap => { should.equal(snap.val(), null); - snap.ref.toString().should.eql(pushed.toString()); + snap.ref.should.have.property('key').which.is.a.String(); }); }); - it('returns a promise and sets the provided value', function () { - const { getDatabase, ref, push } = databaseModular; + it('returns a promise and sets the provided value', async function () { + const { getDatabase, ref, push, get } = databaseModular; const dbRef = ref(getDatabase(), `${TEST_PATH}/value`); - const pushed = push(dbRef, 6); - return pushed - .then(childRef => { - pushed.ref.parent.toString().should.eql(dbRef.toString()); - pushed.toString().should.eql(childRef.toString()); - return pushed.once('value'); - }) - .then(snap => { - snap.val().should.equal(6); - snap.ref.toString().should.eql(pushed.toString()); - }); + const childRef = await push(dbRef, 6); + + childRef.should.have.property('key').which.is.a.String(); + + const snap = await get(childRef); + snap.val().should.equal(6); + snap.ref.should.eql(childRef); }); it('throws if push errors', async function () { diff --git a/packages/database/e2e/reference/transaction.e2e.js b/packages/database/e2e/reference/transaction.e2e.js index 256a5d4985..fb2828ca54 100644 --- a/packages/database/e2e/reference/transaction.e2e.js +++ b/packages/database/e2e/reference/transaction.e2e.js @@ -304,10 +304,10 @@ describe('database().ref().transaction()', function () { }); it('sets a value if one does not exist', async function () { - const { getDatabase, ref, runTransaction } = databaseModular; + const { getDatabase, ref, runTransaction, remove } = databaseModular; const dbRef = ref(getDatabase(), `${TEST_PATH}/transactionCreate`); - await dbRef.remove(); + await remove(dbRef); const value = Date.now(); diff --git a/packages/database/e2e/reference/update.e2e.js b/packages/database/e2e/reference/update.e2e.js index 72a0302dfc..e0a201a168 100644 --- a/packages/database/e2e/reference/update.e2e.js +++ b/packages/database/e2e/reference/update.e2e.js @@ -21,8 +21,8 @@ const TEST_PATH = `${PATH}/update`; describe('database().ref().update()', function () { after(async function () { - const { getDatabase, ref } = databaseModular; - await ref(getDatabase(), TEST_PATH).remove(); + const { getDatabase, ref, remove } = databaseModular; + await remove(ref(getDatabase(), TEST_PATH)); }); describe('v8 compatibility', function () { diff --git a/packages/database/lib/DatabaseDataSnapshot.js b/packages/database/lib/DatabaseDataSnapshot.js index a555d046db..1e897921e3 100644 --- a/packages/database/lib/DatabaseDataSnapshot.js +++ b/packages/database/lib/DatabaseDataSnapshot.js @@ -24,13 +24,14 @@ import { } from '@react-native-firebase/app/lib/common'; import { deepGet } from '@react-native-firebase/app/lib/common/deeps'; +import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/lib/common'; export default class DatabaseDataSnapshot { constructor(reference, snapshot) { this._snapshot = snapshot; if (reference.key !== snapshot.key) { // reference is a query? - this._ref = reference.ref.child(snapshot.key); + this._ref = reference.ref.child.call(reference.ref, snapshot.key, MODULAR_DEPRECATION_ARG); } else { this._ref = reference; } @@ -65,7 +66,7 @@ export default class DatabaseDataSnapshot { value = null; } - const childRef = this._ref.child(path); + const childRef = this._ref.child.call(this._ref, path, MODULAR_DEPRECATION_ARG); let childPriority = null; if (this._snapshot.childPriorities) { @@ -137,7 +138,7 @@ export default class DatabaseDataSnapshot { for (let i = 0; i < this._snapshot.childKeys.length; i++) { const key = this._snapshot.childKeys[i]; - const snapshot = this.child(key); + const snapshot = this.child.call(this, key, MODULAR_DEPRECATION_ARG); const actionReturn = action(snapshot, i); if (actionReturn === true) { diff --git a/packages/database/lib/DatabaseQuery.js b/packages/database/lib/DatabaseQuery.js index 3c95d855d1..c635705f10 100644 --- a/packages/database/lib/DatabaseQuery.js +++ b/packages/database/lib/DatabaseQuery.js @@ -26,6 +26,8 @@ import { pathIsEmpty, pathToUrlEncodedString, ReferenceBase, + createDeprecationProxy, + MODULAR_DEPRECATION_ARG, } from '@react-native-firebase/app/lib/common'; import DatabaseDataSnapshot from './DatabaseDataSnapshot'; import DatabaseSyncTree from './DatabaseSyncTree'; @@ -52,7 +54,7 @@ export default class DatabaseQuery extends ReferenceBase { * @url https://firebase.google.com/docs/reference/js/firebase.database.Query.html#endat */ get ref() { - return new DatabaseReference(this._database, this.path); + return createDeprecationProxy(new DatabaseReference(this._database, this.path)); } /** @@ -83,7 +85,7 @@ export default class DatabaseQuery extends ReferenceBase { const modifiers = this._modifiers._copy().endAt(value, key); modifiers.validateModifiers('firebase.database().ref().endAt()'); - return new DatabaseQuery(this._database, this.path, modifiers); + return createDeprecationProxy(new DatabaseQuery(this._database, this.path, modifiers)); } /** @@ -117,7 +119,10 @@ export default class DatabaseQuery extends ReferenceBase { ); } - return this.startAt(value, key).endAt(value, key); + // Internal method calls should always use MODULAR_DEPRECATION_ARG to avoid false deprecation warnings + return this.startAt + .call(this, value, key, MODULAR_DEPRECATION_ARG) + .endAt.call(this, value, MODULAR_DEPRECATION_ARG); } /** @@ -155,10 +160,8 @@ export default class DatabaseQuery extends ReferenceBase { ); } - return new DatabaseQuery( - this._database, - this.path, - this._modifiers._copy().limitToFirst(limit), + return createDeprecationProxy( + new DatabaseQuery(this._database, this.path, this._modifiers._copy().limitToFirst(limit)), ); } @@ -180,7 +183,9 @@ export default class DatabaseQuery extends ReferenceBase { ); } - return new DatabaseQuery(this._database, this.path, this._modifiers._copy().limitToLast(limit)); + return createDeprecationProxy( + new DatabaseQuery(this._database, this.path, this._modifiers._copy().limitToLast(limit)), + ); } /** @@ -210,7 +215,7 @@ export default class DatabaseQuery extends ReferenceBase { throw new Error("firebase.database().ref().off(_, *) 'callback' must be a function."); } - if (!isUndefined(context) && !isObject(context)) { + if (!isUndefined(context) && !isNull(context) && !isObject(context)) { throw new Error("firebase.database().ref().off(_, _, *) 'context' must be an object."); } @@ -279,7 +284,7 @@ export default class DatabaseQuery extends ReferenceBase { ); } - if (!isUndefined(context) && !isObject(context)) { + if (!isUndefined(context) && !isNull(context) && !isObject(context)) { throw new Error("firebase.database().ref().on(_, _, _, *) 'context' must be an object."); } @@ -434,7 +439,7 @@ export default class DatabaseQuery extends ReferenceBase { const modifiers = this._modifiers._copy().orderByChild(path); modifiers.validateModifiers('firebase.database().ref().orderByChild()'); - return new DatabaseQuery(this._database, this.path, modifiers); + return createDeprecationProxy(new DatabaseQuery(this._database, this.path, modifiers)); } /** @@ -450,7 +455,7 @@ export default class DatabaseQuery extends ReferenceBase { const modifiers = this._modifiers._copy().orderByKey(); modifiers.validateModifiers('firebase.database().ref().orderByKey()'); - return new DatabaseQuery(this._database, this.path, modifiers); + return createDeprecationProxy(new DatabaseQuery(this._database, this.path, modifiers)); } /** @@ -466,7 +471,7 @@ export default class DatabaseQuery extends ReferenceBase { const modifiers = this._modifiers._copy().orderByPriority(); modifiers.validateModifiers('firebase.database().ref().orderByPriority()'); - return new DatabaseQuery(this._database, this.path, modifiers); + return createDeprecationProxy(new DatabaseQuery(this._database, this.path, modifiers)); } /** @@ -482,7 +487,7 @@ export default class DatabaseQuery extends ReferenceBase { const modifiers = this._modifiers._copy().orderByValue(); modifiers.validateModifiers('firebase.database().ref().orderByValue()'); - return new DatabaseQuery(this._database, this.path, modifiers); + return createDeprecationProxy(new DatabaseQuery(this._database, this.path, modifiers)); } startAt(value, key) { @@ -507,7 +512,7 @@ export default class DatabaseQuery extends ReferenceBase { const modifiers = this._modifiers._copy().startAt(value, key); modifiers.validateModifiers('firebase.database().ref().startAt()'); - return new DatabaseQuery(this._database, this.path, modifiers); + return createDeprecationProxy(new DatabaseQuery(this._database, this.path, modifiers)); } toJSON() { diff --git a/packages/database/lib/DatabaseReference.js b/packages/database/lib/DatabaseReference.js index 0ebe0119f4..3ee9a62073 100644 --- a/packages/database/lib/DatabaseReference.js +++ b/packages/database/lib/DatabaseReference.js @@ -28,6 +28,7 @@ import { pathChild, pathParent, promiseWithOptionalCallback, + createDeprecationProxy, } from '@react-native-firebase/app/lib/common'; import DatabaseDataSnapshot from './DatabaseDataSnapshot'; import DatabaseOnDisconnect from './DatabaseOnDisconnect'; @@ -210,7 +211,11 @@ export default class DatabaseReference extends DatabaseQuery { if (error) { onComplete(error, committed, null); } else { - onComplete(null, committed, new DatabaseDataSnapshot(this, snapshotData)); + onComplete( + null, + committed, + createDeprecationProxy(new DatabaseDataSnapshot(this, snapshotData)), + ); } } @@ -219,7 +224,7 @@ export default class DatabaseReference extends DatabaseQuery { } return resolve({ committed, - snapshot: new DatabaseDataSnapshot(this, snapshotData), + snapshot: createDeprecationProxy(new DatabaseDataSnapshot(this, snapshotData)), }); }; diff --git a/packages/database/lib/index.js b/packages/database/lib/index.js index 73a58d0d8d..bcc2f1e14c 100644 --- a/packages/database/lib/index.js +++ b/packages/database/lib/index.js @@ -15,7 +15,13 @@ * */ -import { isAndroid, isBoolean, isNumber, isString } from '@react-native-firebase/app/lib/common'; +import { + isAndroid, + isBoolean, + isNumber, + isString, + MODULAR_DEPRECATION_ARG, +} from '@react-native-firebase/app/lib/common'; import { createModuleNamespace, FirebaseModule, @@ -28,6 +34,8 @@ import DatabaseTransaction from './DatabaseTransaction'; import version from './version'; import fallBackModule from './web/RNFBDatabaseModule'; +import { createDeprecationProxy } from '@react-native-firebase/app/lib/common'; + const namespace = 'database'; const nativeModuleName = [ @@ -54,9 +62,13 @@ class FirebaseDatabaseModule extends FirebaseModule { * @private */ _syncServerTimeOffset() { - this.ref('.info/serverTimeOffset').on('value', snapshot => { - this._serverTimeOffset = snapshot.val(); - }); + this.ref('.info/serverTimeOffset').on( + 'value', + snapshot => { + this._serverTimeOffset = snapshot.val(); + }, + MODULAR_DEPRECATION_ARG, + ); } /** @@ -84,7 +96,7 @@ class FirebaseDatabaseModule extends FirebaseModule { ); } - return new DatabaseReference(this, path); + return createDeprecationProxy(new DatabaseReference(this, path)); } /** @@ -112,7 +124,7 @@ class FirebaseDatabaseModule extends FirebaseModule { path = path.slice(0, path.indexOf('?')); } - return new DatabaseReference(this, path || '/'); + return createDeprecationProxy(new DatabaseReference(this, path || '/')); } /** diff --git a/packages/database/lib/modular/index.d.ts b/packages/database/lib/modular/index.d.ts index 1f3c86f96a..be790654cd 100644 --- a/packages/database/lib/modular/index.d.ts +++ b/packages/database/lib/modular/index.d.ts @@ -220,6 +220,20 @@ export function getServerTime(db: Database): Promise; */ export function increment(delta: number): object; +/** + * Server specific values. + */ +export const ServerValue: { + /** + * A placeholder value for auto-populating the current timestamp. + */ + TIMESTAMP: object; + /** + * Returns a placeholder value that can be used to atomically increment the current database value. + */ + increment(delta: number): object; +}; + /** * Logs debugging information to the console. Not implemented on native. * diff --git a/packages/database/lib/modular/index.js b/packages/database/lib/modular/index.js index 19921f9dae..7fe20e7a35 100644 --- a/packages/database/lib/modular/index.js +++ b/packages/database/lib/modular/index.js @@ -2,6 +2,7 @@ import { getApp } from '@react-native-firebase/app'; import DatabaseStatics from '../DatabaseStatics'; const { ServerValue } = DatabaseStatics; +import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/lib/common'; /** * @typedef {import("..").FirebaseApp} FirebaseApp @@ -28,7 +29,7 @@ export function getDatabase(app, url) { * @returns {void} */ export function connectDatabaseEmulator(db, host, port) { - db.useEmulator(host, port); + db.useEmulator.call(db, host, port, MODULAR_DEPRECATION_ARG); } /** @@ -36,7 +37,7 @@ export function connectDatabaseEmulator(db, host, port) { * @returns {Promise} */ export function goOffline(db) { - return db.goOffline(); + return db.goOffline.call(db, MODULAR_DEPRECATION_ARG); } /** @@ -44,7 +45,7 @@ export function goOffline(db) { * @returns {Promise} */ export function goOnline(db) { - return db.goOnline(); + return db.goOnline.call(db, MODULAR_DEPRECATION_ARG); } /** @@ -53,7 +54,7 @@ export function goOnline(db) { * @returns {DatabaseReference} */ export function ref(db, path) { - return db.ref(path); + return db.ref.call(db, path, MODULAR_DEPRECATION_ARG); } /** @@ -62,7 +63,7 @@ export function ref(db, path) { * @returns {DatabaseReference} */ export function refFromURL(db, url) { - return db.refFromURL(url); + return db.refFromURL.call(db, url, MODULAR_DEPRECATION_ARG); } /** @@ -71,7 +72,7 @@ export function refFromURL(db, url) { * @returns {void} */ export function setPersistenceEnabled(db, enabled) { - return db.setPersistenceEnabled(enabled); + return db.setPersistenceEnabled.call(db, enabled, MODULAR_DEPRECATION_ARG); } /** @@ -80,7 +81,7 @@ export function setPersistenceEnabled(db, enabled) { * @returns {void} */ export function setLoggingEnabled(db, enabled) { - return db.setLoggingEnabled(enabled); + return db.setLoggingEnabled.call(db, enabled, MODULAR_DEPRECATION_ARG); } /** @@ -89,7 +90,7 @@ export function setLoggingEnabled(db, enabled) { * @returns {void} */ export function setPersistenceCacheSizeBytes(db, bytes) { - return db.setPersistenceCacheSizeBytes(bytes); + return db.setPersistenceCacheSizeBytes.call(db, bytes, MODULAR_DEPRECATION_ARG); } export function forceLongPolling() { @@ -105,7 +106,7 @@ export function forceWebSockets() { * @returns {Date} */ export function getServerTime(db) { - return db.getServerTime(); + return db.getServerTime.call(db, MODULAR_DEPRECATION_ARG); } /** @@ -120,9 +121,11 @@ export function serverTimestamp() { * @returns {object} */ export function increment(delta) { - return ServerValue.increment(delta); + return ServerValue.increment.call(ServerValue, delta, MODULAR_DEPRECATION_ARG); } +export { ServerValue }; + export function enableLogging(_enabled, _persistent) { throw new Error('enableLogging() is not implemented'); } diff --git a/packages/database/lib/modular/query.js b/packages/database/lib/modular/query.js index 192573dab4..1eed7ce2ac 100644 --- a/packages/database/lib/modular/query.js +++ b/packages/database/lib/modular/query.js @@ -13,6 +13,9 @@ /** * @implements {IQueryConstraint} */ + +import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/lib/common'; + class QueryConstraint { constructor(type, ...args) { this._type = type; @@ -20,8 +23,7 @@ class QueryConstraint { } _apply(query) { - // eslint-disable-next-line prefer-spread - return query[this._type].apply(query, this._args); + return query[this._type].apply(query, [...this._args, MODULAR_DEPRECATION_ARG]); } } @@ -138,14 +140,14 @@ function addEventListener(query, eventType, callback, cancelCallbackOrListenOpti if (options && options.onlyOnce) { const userCallback = callback; callback = snapshot => { - query.off(eventType, callback); + query.off.call(query, eventType, callback, null, MODULAR_DEPRECATION_ARG); return userCallback(snapshot); }; } - query.on(eventType, callback, cancelCallback); + query.on.call(query, eventType, callback, cancelCallback, null, MODULAR_DEPRECATION_ARG); - return () => query.off(eventType, callback); + return () => query.off.call(query, eventType, callback, null, MODULAR_DEPRECATION_ARG); } /** @@ -209,7 +211,7 @@ export function onChildRemoved(query, callback, cancelCallbackOrListenOptions, o * @returns {Promise} */ export function set(ref, value) { - return ref.set(value); + return ref.set.call(ref, value, () => {}, MODULAR_DEPRECATION_ARG); } /** @@ -218,7 +220,7 @@ export function set(ref, value) { * @returns {Promise} */ export function setPriority(ref, priority) { - return ref.setPriority(priority); + return ref.setPriority.call(ref, priority, () => {}, MODULAR_DEPRECATION_ARG); } /** @@ -228,7 +230,7 @@ export function setPriority(ref, priority) { * @returns {Promise} */ export function setWithPriority(ref, value, priority) { - return ref.setWithPriority(value, priority); + return ref.setWithPriority.call(ref, value, priority, () => {}, MODULAR_DEPRECATION_ARG); } /** @@ -236,7 +238,14 @@ export function setWithPriority(ref, value, priority) { * @returns {DataSnapshot} */ export function get(query) { - return query.once('value'); + return query.once.call( + query, + 'value', + () => {}, + () => {}, + {}, + MODULAR_DEPRECATION_ARG, + ); } export function off(_query, _eventType, _callback) { @@ -249,7 +258,7 @@ export function off(_query, _eventType, _callback) { * @returns {DatabaseReference} */ export function child(parent, path) { - return parent.child(path); + return parent.child.call(parent, path, MODULAR_DEPRECATION_ARG); } /** @@ -257,7 +266,7 @@ export function child(parent, path) { * @returns {OnDisconnect} */ export function onDisconnect(ref) { - return ref.onDisconnect(); + return ref.onDisconnect.call(ref, MODULAR_DEPRECATION_ARG); } /** @@ -266,7 +275,7 @@ export function onDisconnect(ref) { * @returns {Promise} */ export function keepSynced(ref, value) { - return ref.keepSynced(value); + return ref.keepSynced.call(ref, value, MODULAR_DEPRECATION_ARG); } /** @@ -275,7 +284,7 @@ export function keepSynced(ref, value) { * @returns {ThenableReference} */ export function push(parent, value) { - return parent.push(value); + return parent.push.call(parent, value, MODULAR_DEPRECATION_ARG); } /** @@ -283,7 +292,7 @@ export function push(parent, value) { * @returns {Promise} */ export function remove(ref) { - return ref.remove(); + return ref.remove.call(ref, MODULAR_DEPRECATION_ARG); } /** @@ -292,5 +301,5 @@ export function remove(ref) { * @returns {Promise} */ export function update(ref, values) { - return ref.update(values); + return ref.update.call(ref, values, MODULAR_DEPRECATION_ARG); } diff --git a/packages/database/lib/modular/transaction.js b/packages/database/lib/modular/transaction.js index c5c8b5e05e..c9f35ae411 100644 --- a/packages/database/lib/modular/transaction.js +++ b/packages/database/lib/modular/transaction.js @@ -10,6 +10,15 @@ * @param {TransactionOptions?} options * @returns {Promise} */ + +import { MODULAR_DEPRECATION_ARG } from '@react-native-firebase/app/lib/common'; + export function runTransaction(ref, transactionUpdate, options) { - return ref.transaction(transactionUpdate, undefined, options && options.applyLocally); + return ref.transaction.call( + ref, + transactionUpdate, + undefined, + options && options.applyLocally, + MODULAR_DEPRECATION_ARG, + ); } diff --git a/tests/test-app/examples/database/index.js b/tests/test-app/examples/database/index.js new file mode 100644 index 0000000000..52dd8efb17 --- /dev/null +++ b/tests/test-app/examples/database/index.js @@ -0,0 +1,60 @@ +import React from 'react'; +import { AppRegistry, Button, Text, View } from 'react-native'; + +// import firebase, { utils } from '@react-native-firebase/app'; +import { + getDatabase, + ref, + query, + orderByChild, + set, + child, + onChildMoved, + connectDatabaseEmulator, +} from '@react-native-firebase/database'; + +connectDatabaseEmulator(getDatabase(), '127.0.0.1', 9000); + +function App() { + return ( + + text text text + text text text +