Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DO NOT MERGE: Upgrade idb version from 3.2.0 to 7.0.0 #5857

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/quiet-years-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@firebase/installations': patch
'@firebase/installations-compat': patch
'@firebase/messaging': patch
---

Update `idb` dependency from 3.0.2 to 7.0.0.
2 changes: 1 addition & 1 deletion packages/installations-compat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"@firebase/installations-types": "0.4.0",
"@firebase/util": "1.4.3",
"@firebase/component": "0.5.10",
"idb": "3.0.2",
"idb": "7.0.0",
"tslib": "^2.1.0"
}
}
2 changes: 1 addition & 1 deletion packages/installations/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"dependencies": {
"@firebase/util": "1.4.3",
"@firebase/component": "0.5.10",
"idb": "3.0.2",
"idb": "7.0.0",
"tslib": "^2.1.0"
}
}
34 changes: 18 additions & 16 deletions packages/installations/src/helpers/idb-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

import { DB, openDb } from 'idb';
import { IDBPDatabase, openDB } from 'idb';
import { AppConfig } from '../interfaces/installation-impl';
import { InstallationEntry } from '../interfaces/installation-entry';
import { getKey } from '../util/get-key';
Expand All @@ -25,18 +25,20 @@ const DATABASE_NAME = 'firebase-installations-database';
const DATABASE_VERSION = 1;
const OBJECT_STORE_NAME = 'firebase-installations-store';

let dbPromise: Promise<DB> | null = null;
function getDbPromise(): Promise<DB> {
let dbPromise: Promise<IDBPDatabase> | null = null;
function getDbPromise(): Promise<IDBPDatabase> {
if (!dbPromise) {
dbPromise = openDb(DATABASE_NAME, DATABASE_VERSION, upgradeDB => {
// We don't use 'break' in this switch statement, the fall-through
// behavior is what we want, because if there are multiple versions between
// the old version and the current version, we want ALL the migrations
// that correspond to those versions to run, not only the last one.
// eslint-disable-next-line default-case
switch (upgradeDB.oldVersion) {
case 0:
upgradeDB.createObjectStore(OBJECT_STORE_NAME);
dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {
upgrade: (db, oldVersion) => {
// We don't use 'break' in this switch statement, the fall-through
// behavior is what we want, because if there are multiple versions between
// the old version and the current version, we want ALL the migrations
// that correspond to those versions to run, not only the last one.
// eslint-disable-next-line default-case
switch (oldVersion) {
case 0:
db.createObjectStore(OBJECT_STORE_NAME);
}
}
});
}
Expand Down Expand Up @@ -66,7 +68,7 @@ export async function set<ValueType extends InstallationEntry>(
const objectStore = tx.objectStore(OBJECT_STORE_NAME);
const oldValue = await objectStore.get(key);
await objectStore.put(value, key);
await tx.complete;
await tx.done;

if (!oldValue || oldValue.fid !== value.fid) {
fidChanged(appConfig, value.fid);
Expand All @@ -81,7 +83,7 @@ export async function remove(appConfig: AppConfig): Promise<void> {
const db = await getDbPromise();
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
await tx.objectStore(OBJECT_STORE_NAME).delete(key);
await tx.complete;
await tx.done;
}

/**
Expand All @@ -106,7 +108,7 @@ export async function update<ValueType extends InstallationEntry | undefined>(
} else {
await store.put(newValue, key);
}
await tx.complete;
await tx.done;

if (newValue && (!oldValue || oldValue.fid !== newValue.fid)) {
fidChanged(appConfig, newValue.fid);
Expand All @@ -119,5 +121,5 @@ export async function clear(): Promise<void> {
const db = await getDbPromise();
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
await tx.objectStore(OBJECT_STORE_NAME).clear();
await tx.complete;
await tx.done;
}
2 changes: 1 addition & 1 deletion packages/messaging/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"@firebase/messaging-interop-types": "0.1.0",
"@firebase/util": "1.4.3",
"@firebase/component": "0.5.10",
"idb": "3.0.2",
"idb": "7.0.0",
"tslib": "^2.1.0"
},
"devDependencies": {
Expand Down
30 changes: 16 additions & 14 deletions packages/messaging/src/helpers/migrate-old-database.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { FakePushSubscription } from '../testing/fakes/service-worker';
import { base64ToArray } from './array-base64-translator';
import { expect } from 'chai';
import { getFakeTokenDetails } from '../testing/fakes/token-details';
import { openDb } from 'idb';
import { openDB } from 'idb';

describe('migrateOldDb', () => {
it("does nothing if old DB didn't exist", async () => {
Expand Down Expand Up @@ -179,25 +179,27 @@ describe('migrateOldDb', () => {
});

async function put(version: number, value: object): Promise<void> {
const db = await openDb('fcm_token_details_db', version, upgradeDb => {
if (upgradeDb.oldVersion === 0) {
const objectStore = upgradeDb.createObjectStore(
'fcm_token_object_Store',
{
keyPath: 'swScope'
}
);
objectStore.createIndex('fcmSenderId', 'fcmSenderId', {
unique: false
});
objectStore.createIndex('fcmToken', 'fcmToken', { unique: true });
const db = await openDB('fcm_token_details_db', version, {
upgrade: (upgradeDb, oldVersion) => {
if (oldVersion === 0) {
const objectStore = upgradeDb.createObjectStore(
'fcm_token_object_Store',
{
keyPath: 'swScope'
}
);
objectStore.createIndex('fcmSenderId', 'fcmSenderId', {
unique: false
});
objectStore.createIndex('fcmToken', 'fcmToken', { unique: true });
}
}
});

try {
const tx = db.transaction('fcm_token_object_Store', 'readwrite');
await tx.objectStore('fcm_token_object_Store').put(value);
await tx.complete;
await tx.done;
} finally {
db.close();
}
Expand Down
134 changes: 68 additions & 66 deletions packages/messaging/src/helpers/migrate-old-database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

import { deleteDb, openDb } from 'idb';
import { deleteDB, openDB } from 'idb';

import { TokenDetails } from '../interfaces/token-details';
import { arrayToBase64 } from './array-base64-translator';
Expand Down Expand Up @@ -88,83 +88,85 @@ export async function migrateOldDatabase(

let tokenDetails: TokenDetails | null = null;

const db = await openDb(OLD_DB_NAME, OLD_DB_VERSION, async db => {
if (db.oldVersion < 2) {
// Database too old, skip migration.
return;
}

if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) {
// Database did not exist. Nothing to do.
return;
}

const objectStore = db.transaction.objectStore(OLD_OBJECT_STORE_NAME);
const value = await objectStore.index('fcmSenderId').get(senderId);
await objectStore.clear();
const db = await openDB(OLD_DB_NAME, OLD_DB_VERSION, {
upgrade: async (db, oldVersion, _newVersion, transaction) => {
if (oldVersion < 2) {
// Database too old, skip migration.
return;
}

if (!value) {
// No entry in the database, nothing to migrate.
return;
}
if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) {
// Database did not exist. Nothing to do.
return;
}

if (db.oldVersion === 2) {
const oldDetails = value as V2TokenDetails;
const objectStore = transaction.objectStore(OLD_OBJECT_STORE_NAME);
const value = await objectStore.index('fcmSenderId').get(senderId);
await objectStore.clear();

if (!oldDetails.auth || !oldDetails.p256dh || !oldDetails.endpoint) {
if (!value) {
// No entry in the database, nothing to migrate.
return;
}

tokenDetails = {
token: oldDetails.fcmToken,
createTime: oldDetails.createTime ?? Date.now(),
subscriptionOptions: {
auth: oldDetails.auth,
p256dh: oldDetails.p256dh,
endpoint: oldDetails.endpoint,
swScope: oldDetails.swScope,
vapidKey:
typeof oldDetails.vapidKey === 'string'
? oldDetails.vapidKey
: arrayToBase64(oldDetails.vapidKey)
}
};
} else if (db.oldVersion === 3) {
const oldDetails = value as V3TokenDetails;

tokenDetails = {
token: oldDetails.fcmToken,
createTime: oldDetails.createTime,
subscriptionOptions: {
auth: arrayToBase64(oldDetails.auth),
p256dh: arrayToBase64(oldDetails.p256dh),
endpoint: oldDetails.endpoint,
swScope: oldDetails.swScope,
vapidKey: arrayToBase64(oldDetails.vapidKey)
}
};
} else if (db.oldVersion === 4) {
const oldDetails = value as V4TokenDetails;

tokenDetails = {
token: oldDetails.fcmToken,
createTime: oldDetails.createTime,
subscriptionOptions: {
auth: arrayToBase64(oldDetails.auth),
p256dh: arrayToBase64(oldDetails.p256dh),
endpoint: oldDetails.endpoint,
swScope: oldDetails.swScope,
vapidKey: arrayToBase64(oldDetails.vapidKey)
if (oldVersion === 2) {
const oldDetails = value as V2TokenDetails;

if (!oldDetails.auth || !oldDetails.p256dh || !oldDetails.endpoint) {
return;
}
};

tokenDetails = {
token: oldDetails.fcmToken,
createTime: oldDetails.createTime ?? Date.now(),
subscriptionOptions: {
auth: oldDetails.auth,
p256dh: oldDetails.p256dh,
endpoint: oldDetails.endpoint,
swScope: oldDetails.swScope,
vapidKey:
typeof oldDetails.vapidKey === 'string'
? oldDetails.vapidKey
: arrayToBase64(oldDetails.vapidKey)
}
};
} else if (oldVersion === 3) {
const oldDetails = value as V3TokenDetails;

tokenDetails = {
token: oldDetails.fcmToken,
createTime: oldDetails.createTime,
subscriptionOptions: {
auth: arrayToBase64(oldDetails.auth),
p256dh: arrayToBase64(oldDetails.p256dh),
endpoint: oldDetails.endpoint,
swScope: oldDetails.swScope,
vapidKey: arrayToBase64(oldDetails.vapidKey)
}
};
} else if (oldVersion === 4) {
const oldDetails = value as V4TokenDetails;

tokenDetails = {
token: oldDetails.fcmToken,
createTime: oldDetails.createTime,
subscriptionOptions: {
auth: arrayToBase64(oldDetails.auth),
p256dh: arrayToBase64(oldDetails.p256dh),
endpoint: oldDetails.endpoint,
swScope: oldDetails.swScope,
vapidKey: arrayToBase64(oldDetails.vapidKey)
}
};
}
}
});
db.close();

// Delete all old databases.
await deleteDb(OLD_DB_NAME);
await deleteDb('fcm_vapid_details_db');
await deleteDb('undefined');
await deleteDB(OLD_DB_NAME);
await deleteDB('fcm_vapid_details_db');
await deleteDB('undefined');

return checkTokenDetails(tokenDetails) ? tokenDetails : null;
}
Expand Down
30 changes: 16 additions & 14 deletions packages/messaging/src/internals/idb-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* limitations under the License.
*/

import { DB, deleteDb, openDb } from 'idb';
import { IDBPDatabase, deleteDB, openDB } from 'idb';

import { FirebaseInternalDependencies } from '../interfaces/internal-dependencies';
import { TokenDetails } from '../interfaces/token-details';
Expand All @@ -26,17 +26,19 @@ export const DATABASE_NAME = 'firebase-messaging-database';
const DATABASE_VERSION = 1;
const OBJECT_STORE_NAME = 'firebase-messaging-store';

let dbPromise: Promise<DB> | null = null;
function getDbPromise(): Promise<DB> {
let dbPromise: Promise<IDBPDatabase> | null = null;
function getDbPromise(): Promise<IDBPDatabase> {
if (!dbPromise) {
dbPromise = openDb(DATABASE_NAME, DATABASE_VERSION, upgradeDb => {
// We don't use 'break' in this switch statement, the fall-through behavior is what we want,
// because if there are multiple versions between the old version and the current version, we
// want ALL the migrations that correspond to those versions to run, not only the last one.
// eslint-disable-next-line default-case
switch (upgradeDb.oldVersion) {
case 0:
upgradeDb.createObjectStore(OBJECT_STORE_NAME);
dbPromise = openDB(DATABASE_NAME, DATABASE_VERSION, {
upgrade: (upgradeDb, oldVersion) => {
// We don't use 'break' in this switch statement, the fall-through behavior is what we want,
// because if there are multiple versions between the old version and the current version, we
// want ALL the migrations that correspond to those versions to run, not only the last one.
// eslint-disable-next-line default-case
switch (oldVersion) {
case 0:
upgradeDb.createObjectStore(OBJECT_STORE_NAME);
}
}
});
}
Expand Down Expand Up @@ -77,7 +79,7 @@ export async function dbSet(
const db = await getDbPromise();
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
await tx.objectStore(OBJECT_STORE_NAME).put(tokenDetails, key);
await tx.complete;
await tx.done;
return tokenDetails;
}

Expand All @@ -89,14 +91,14 @@ export async function dbRemove(
const db = await getDbPromise();
const tx = db.transaction(OBJECT_STORE_NAME, 'readwrite');
await tx.objectStore(OBJECT_STORE_NAME).delete(key);
await tx.complete;
await tx.done;
}

/** Deletes the DB. Useful for tests. */
export async function dbDelete(): Promise<void> {
if (dbPromise) {
(await dbPromise).close();
await deleteDb(DATABASE_NAME);
await deleteDB(DATABASE_NAME);
dbPromise = null;
}
}
Expand Down