MockingMagician / promised-db

Promised version of indexed DB that simplify usage
ISC License
2 stars 1 forks source link

Must I provide migrations for all versions? #2

Open retorquere opened 1 week ago

retorquere commented 1 week ago

I'm using indexeddb as a cache, so my upgrade action is always "delete all stores, recreate what I need". Is it supported to just do


import { DatabaseFactory } from '@idxdb/promised';

const requestedVersion = 3;

const migrations = [
    {
        version: requestedVersion,
        upgrade: async ({db, transaction, currentVersionUpgrade}) => {
            for (const store of db.objectStoreNames) {
              db.deleteObjectStore(store)
            }
            const store = db.createObjectStore('users', { keyPath: 'id' })
            store.createIndex('name_idx', 'name', { unique: false });
        },
    },
]

const db = await DatabaseFactory.open('mydatabase', requestedVersion, migrations);
MockingMagician commented 1 week ago

Hello @retorquere

Yeap, it should works as expected, just upgrade the requestedVersion number when you'll need to reset the database.

Let me know if you have any problem

MockingMagician commented 1 week ago

By the way let's say anytime a user refresh the application you want that the db reset you can use:

const requestedVersion = new Date().getTime() // Version number based on time

const migrations = [
    {
        version: requestedVersion,
        upgrade: async ({db, transaction}) => {
            for (const store of db.objectStoreNames) {
              db.deleteObjectStore(store) // correctly delete all previous existing stores
            }
            // creates the fresh new stores and their indexes
            const store = db.createObjectStore('users', { keyPath: 'id' })
            store.createIndex('name_idx', 'name', { unique: false });
        },
    },
]

const db = await DatabaseFactory.open('mydatabase', requestedVersion, migrations);

Or you can use the mechanism you want, just upgrade the version number when it is needed.

retorquere commented 1 week ago

In an upgrade, is currentVersionUpgrade the version being upgraded to (I assume so) or the version of the database being upgraded?

MockingMagician commented 1 week ago

currentVersionUpgrade always equal to the version value of the migration. Example:

const db = await DatabaseFactory.open('my-db', 2, [
    {
        version: 1,
        upgrade: async ({ currentVersionUpgrade }) => {
            console.log(currentVersionUpgrade) // 1
        },
    },
    {
        version: 2,
        upgrade: async ({ db, currentVersionUpgrade }) => {
            console.log(currentVersionUpgrade) // 2
        },
    },
])

I've just noticed a bug, one of my tests was wrong in the assertion. Thanks to your question, I was able to see and correct it.

https://github.com/MockingMagician/promised-db/blob/25084f7cd4e7027c75c143247485a2aefdb35d5a/src/database-factory.ts#L91

https://github.com/MockingMagician/promised-db/blob/25084f7cd4e7027c75c143247485a2aefdb35d5a/test/database-factory.test.ts#L17-L76

retorquere commented 1 week ago

But the old version is available during migration right?

MockingMagician commented 1 week ago

Yes old version is available during the event upgradeneeded

But when you ask But the old version is available during migration right?

Did you ask about in the upgrade function of migrations ? upgrade: async ({ db, transaction, currentVersionUpgrade })

retorquere commented 1 week ago

Yes, that is what I meant. db.version would be the same as currentVersionUpgrade, right? the oldVersion is available on the event I think.

MockingMagician commented 1 week ago

The point here is that currentVersionUpgrade isn't really useful during migration (upgrade), it was used in the context of my test only to ensure that migrations take place in the right order.

retorquere commented 1 week ago

The IDBVersionChangeEvent provides oldVersion and newVersion, I use that to log upgrade activity.

MockingMagician commented 1 week ago

Yes, the mechanism is the same here. Perhaps the name currentVersionUpgrade is confusing. It should be migrationVersion. Because I'm not just monitoring the transition from v1 to v25, I'm checking that all the migrations provided, e.g. v3, v4, etcc... have been executed during the transition from v1 to v25. And above all, in the right order.

retorquere commented 1 week ago

But what does currentVersionUpgrade correspond to then? I think it's the version the migration is about to establish (so newVersion. The oldVersion should be available as db.version I think, so then I'd have the information I need.

Personally I'd say that even for the stacked migrations you offer, newVersion would be more clear than currentVersionUpgrade. It's the new version being created, regardless of whether newer versions will follow.

MockingMagician commented 1 week ago

Let me clarify why I've included this information in the upgrade function

https://github.com/MockingMagician/promised-db/blob/7dd31ee4c6b42a2e82c0aef782cd20039fe6393d/test/database-factory.test.ts#L65-L74

All I needed to do was make sure that the migrations were carried out in the right order.

This parameter is of no real use in production. It will never be used.

In your case, the value of newVersion, requestedVersion and currentVersionUpgrade will always be the same. But there's no need to pay attention to this parameter, which was only there for testing purposes.

In the example

const requestedVersion = 1

const db = await DatabaseFactory.open('my-db', requestedVersion, [
    {
        version: 1,
        upgrade: async ({ currentVersionUpgrade }) => {
            console.log(currentVersionUpgrade) // 1
        },
    },
    {
        version: 2,
        upgrade: async ({ db, currentVersionUpgrade }) => {
            // It will be never executed because I've requested version 1
            console.log(currentVersionUpgrade)
        },
    },
])

I'm going a bit beyond the scope of your question, but what are the uses and benefits of having a list of the different DB versions?

In short, in your usecase, since you reset your DB each time it is needed, it may not be of any interest.

retorquere commented 1 week ago

I'm not looking for the list of the different DB versions; I will only ever have one migration. For diagnostic purposes, I do want to log what the database version was before I reset it, or in the case of a delete, that I am re-creating it at user request. If I messed something up in a way that the reset-and-recreate does not work, I want to be able to go into my git history to see how I had defined my schema then.

MockingMagician commented 1 week ago

So, if I understand your need correctly, you'd be interested in finding the value of oldVersion and newVersion in the upgrade function.

retorquere commented 1 week ago

Yes.

MockingMagician commented 6 days ago

It will be available in the next release ;-)

retorquere commented 9 hours ago

Why are the migrations async BTW? I don't think any of the methods you can call there are async, and if you call outside async functions, you'll abort the transaction the migration is running under.