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

Altering database structure #152

Open
Kriso23 opened this issue Aug 25, 2023 · 3 comments
Open

Altering database structure #152

Kriso23 opened this issue Aug 25, 2023 · 3 comments

Comments

@Kriso23
Copy link

Kriso23 commented Aug 25, 2023

Hi there,
Wondering if there is any way for me to alter my database structure that is persistent?
For example I'm making a game with future planned features and I want to be able to add columns or split tables into 2 etc.
What methods are available to me to do this?
I guess what I'm asking is how does migration work with this addon?

@Kriso23
Copy link
Author

Kriso23 commented Aug 25, 2023

Because I could write a function which stores old data in dictionaries and adds it as rows to a new db but what if the user is 2 alterations behind? feels like it will get cumbersome quickly

@2shady4u
Copy link
Owner

Hello @Kriso23,

Other users have devised methods to update their databases depending on a version entry in their database.
The best way, according to them, seems to be to update your outdated databases using so-called "migrations". (Django does this for example)

This can either be implemented in GDScript or in C++, the choice is yours.

Unfortunately this feature is not part of the scope of godot-sqlite and no native method will ever be implemented in this repository.

@cridenour
Copy link
Contributor

@Kriso23 if you're looking for some code for migrations:

First have a migrations table.

CREATE TABLE migrations
(
    migration_name TEXT NOT NULL
        PRIMARY KEY,
    applied        TEXT NOT NULL
);

Second, where you manage your database, keep a GDScript Array of Dictionaries of migration names and functions.

var migrations: Array[Dictionary] = [
  {
    'name': '001_save_meta',
    'apply': migration_001_save_meta,
  },
  ...
]

Then after you load your database, you can check where that file has been migrated and move it along.

func migrate() -> void:
  # Checks what migrations we have applied and apply any missing
  var db_results := query('SELECT migration_name FROM migrations')
  var applied: Array[String] = []
  for result in db_results:
    applied.append(result['migration_name'])
  
  var ok: bool  
  for migration in migrations:
    if !applied.has(migration['name']):
      query('BEGIN TRANSACTION')
      ok = migration['apply'].call()
      if ok:
        query('INSERT INTO migrations (migration_name, applied) VALUES (?, ?)', [migration['name'], Time.get_datetime_string_from_system()])
        query('COMMIT TRANSACTION')
      else:
        query('ROLLBACK TRANSACTION')
      
        push_error('Could not upgrade save file. Failed at %s' % migration['name'])
        # TODO: Show user error
        return

In this case, query is a helper function over _db.query_with_bindings where _db is my SQLite variable.

And migration_001_save_meta and other migration functions just return true/false based on success. Most are just a bunch of query calls or running SQL from a file.

Hope that helps!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants