From 670b128c712058547177f2e1158a54b11e83de43 Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Fri, 4 Jul 2025 15:08:45 +0800 Subject: [PATCH 1/4] feat: sqlite migration --- .gitignore | 9 ++++++++- chat_sdk.nimble | 3 +++ chat_sdk/migration.nim | 40 ++++++++++++++++++++++++++++++++++++++++ migrations/README.md | 9 +++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 chat_sdk/migration.nim create mode 100644 migrations/README.md diff --git a/.gitignore b/.gitignore index dbf16ae..897e386 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,11 @@ nimcache/ *.a # OS -.DS_Store \ No newline at end of file +.DS_Store + +# Temporary files +*.db + +# Compiled files +chat_sdk/* +!*.nim \ No newline at end of file diff --git a/chat_sdk.nimble b/chat_sdk.nimble index a64bb4f..6a66714 100644 --- a/chat_sdk.nimble +++ b/chat_sdk.nimble @@ -16,3 +16,6 @@ task buildSharedLib, "Build shared library for C bindings": task buildStaticLib, "Build static library for C bindings": exec "nim c --app:staticLib --out:../library/c-bindings/libchatsdk.a chat_sdk/chat_sdk.nim" + +task migrate, "Run database migrations": + exec "nim c -r chat_sdk/migration.nim" \ No newline at end of file diff --git a/chat_sdk/migration.nim b/chat_sdk/migration.nim new file mode 100644 index 0000000..31269ac --- /dev/null +++ b/chat_sdk/migration.nim @@ -0,0 +1,40 @@ +import os, osproc, sequtils, algorithm +import db_connector/db_sqlite + +proc ensureMigrationTable(db: DbConn) = + db.exec(sql""" + CREATE TABLE IF NOT EXISTS schema_migrations ( + filename TEXT PRIMARY KEY, + applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + +proc hasMigrationRun(db: DbConn, filename: string): bool = + for row in db.fastRows(sql"SELECT 1 FROM schema_migrations WHERE filename = ?", filename): + return true + return false + +proc markMigrationRun(db: DbConn, filename: string) = + db.exec(sql"INSERT INTO schema_migrations (filename) VALUES (?)", filename) + +proc runMigrations*(db: DbConn, dir = "migrations") = + ensureMigrationTable(db) + let files = walkFiles(dir / "*.sql").toSeq().sorted() + for file in files: + if hasMigrationRun(db, file): + echo "Already applied: ", file + else: + echo "Applying: ", file + let sql = readFile(file) + db.exec(sql(sql)) + markMigrationRun(db, file) + +proc main() = + let db = open("test.db", "", "", "") + try: + runMigrations(db) + finally: + db.close() + +when isMainModule: + main() \ No newline at end of file diff --git a/migrations/README.md b/migrations/README.md new file mode 100644 index 0000000..2aca949 --- /dev/null +++ b/migrations/README.md @@ -0,0 +1,9 @@ +## Database Migrations + +This directory contains SQL migration files for the Nim Chat SDK. + +Each migration file should be named in the format `NNN_description.sql`, where `NNN` is a zero-padded number indicating the order of the migration. For example, `001_create_user_table.sql` is the first migration. + +## Running Migrations + +If you want to install a test sqlite database with tables setup, you can run `nimble migrate` from the command line. This will execute all migration files in order, ensuring that your database schema is up to date. \ No newline at end of file From 3fe8fb2a03d7501197de809f87ba4a7b90e9cecd Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Wed, 9 Jul 2025 18:16:51 +0800 Subject: [PATCH 2/4] chore: refore code --- .gitignore | 2 ++ apps/nim.cfg | 1 + apps/run_migration.nim | 12 ++++++++++++ chat_sdk.nimble | 2 +- chat_sdk/migration.nim | 20 +++++++------------- 5 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 apps/nim.cfg create mode 100644 apps/run_migration.nim diff --git a/.gitignore b/.gitignore index 897e386..5aed900 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,6 @@ nimcache/ # Compiled files chat_sdk/* +!*.nim +apps/* !*.nim \ No newline at end of file diff --git a/apps/nim.cfg b/apps/nim.cfg new file mode 100644 index 0000000..d4a2be8 --- /dev/null +++ b/apps/nim.cfg @@ -0,0 +1 @@ +path = ".." \ No newline at end of file diff --git a/apps/run_migration.nim b/apps/run_migration.nim new file mode 100644 index 0000000..577fc77 --- /dev/null +++ b/apps/run_migration.nim @@ -0,0 +1,12 @@ +import db_connector/db_sqlite +import chat_sdk/migration + +proc main() = + let db = open("test.db", "", "", "") + try: + runMigrations(db) + finally: + db.close() + +when isMainModule: + main() \ No newline at end of file diff --git a/chat_sdk.nimble b/chat_sdk.nimble index 6a66714..e52efb9 100644 --- a/chat_sdk.nimble +++ b/chat_sdk.nimble @@ -18,4 +18,4 @@ task buildStaticLib, "Build static library for C bindings": exec "nim c --app:staticLib --out:../library/c-bindings/libchatsdk.a chat_sdk/chat_sdk.nim" task migrate, "Run database migrations": - exec "nim c -r chat_sdk/migration.nim" \ No newline at end of file + exec "nim c -r apps/run_migration.nim" \ No newline at end of file diff --git a/chat_sdk/migration.nim b/chat_sdk/migration.nim index 31269ac..c5edb3d 100644 --- a/chat_sdk/migration.nim +++ b/chat_sdk/migration.nim @@ -1,5 +1,6 @@ -import os, osproc, sequtils, algorithm +import os, sequtils, algorithm import db_connector/db_sqlite +import chronicles proc ensureMigrationTable(db: DbConn) = db.exec(sql""" @@ -18,23 +19,16 @@ proc markMigrationRun(db: DbConn, filename: string) = db.exec(sql"INSERT INTO schema_migrations (filename) VALUES (?)", filename) proc runMigrations*(db: DbConn, dir = "migrations") = + info "Migration process starting up" ensureMigrationTable(db) let files = walkFiles(dir / "*.sql").toSeq().sorted() for file in files: if hasMigrationRun(db, file): - echo "Already applied: ", file + info "Migration already applied", file + info "..." else: - echo "Applying: ", file + info "Applying migration", file + info "..." let sql = readFile(file) db.exec(sql(sql)) markMigrationRun(db, file) - -proc main() = - let db = open("test.db", "", "", "") - try: - runMigrations(db) - finally: - db.close() - -when isMainModule: - main() \ No newline at end of file From a0bdb421ffa43dc2e6c266b9aed2fa1aa42b4fb2 Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Wed, 9 Jul 2025 18:21:03 +0800 Subject: [PATCH 3/4] chore: use defer for db close --- apps/run_migration.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/run_migration.nim b/apps/run_migration.nim index 577fc77..abf28e4 100644 --- a/apps/run_migration.nim +++ b/apps/run_migration.nim @@ -3,10 +3,10 @@ import chat_sdk/migration proc main() = let db = open("test.db", "", "", "") - try: - runMigrations(db) - finally: + defer: db.close() + + runMigrations(db) when isMainModule: main() \ No newline at end of file From d57d81bdcb47a54bf065738e71ece40f0a0328e8 Mon Sep 17 00:00:00 2001 From: kaichaosun Date: Fri, 11 Jul 2025 10:54:15 +0800 Subject: [PATCH 4/4] chore: remove useless log --- chat_sdk/migration.nim | 2 -- 1 file changed, 2 deletions(-) diff --git a/chat_sdk/migration.nim b/chat_sdk/migration.nim index c5edb3d..8af88d3 100644 --- a/chat_sdk/migration.nim +++ b/chat_sdk/migration.nim @@ -25,10 +25,8 @@ proc runMigrations*(db: DbConn, dir = "migrations") = for file in files: if hasMigrationRun(db, file): info "Migration already applied", file - info "..." else: info "Applying migration", file - info "..." let sql = readFile(file) db.exec(sql(sql)) markMigrationRun(db, file)