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

Tauri adapter #1758

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions flow-typed/custom/tauri-plugin-sql.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
declare class TauriDB {
execute(query: string, args?: any[]): Promise<any>;
select(query: string, args?: any[]): Promise<any[]>;
close(): Promise<void>;
}
declare module 'tauri-plugin-sql' {
declare export default {
load: (path: string) => Promise<TauriDB>
};
}

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"@babel/runtime": "7.21.0",
"@nozbe/simdjson": "3.1.0-wmelon1",
"@nozbe/sqlite": "3.40.1",
"@tauri-apps/api": "^1.5.3",
"hoist-non-react-statics": "^3.3.2",
"lokijs": "npm:@nozbe/[email protected]",
"rxjs": "^7.8.0",
Expand Down Expand Up @@ -164,8 +165,10 @@
"react-test-renderer": "18.2.0",
"rimraf": "^4.1.2",
"semver": "^7.3.8",
"tauri-plugin-sql": "https://github.com/tauri-apps/tauri-plugin-sql#v1",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.15.0",
"typescript": "^4.5.0"
}
},
"packageManager": "[email protected]"
}
1 change: 0 additions & 1 deletion src/adapters/sqlite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ export default class SQLiteAdapter implements DatabaseAdapter {
}

_setUpWithMigrations(databaseVersion: SchemaVersion, callback: ResultCallback<void>): void {
logger.log('[SQLite] Database needs migrations')
invariant(databaseVersion > 0, 'Invalid database schema version')

const migrationSteps = this._migrationSteps(databaseVersion)
Expand Down
2 changes: 1 addition & 1 deletion src/adapters/sqlite/makeDispatcher/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow
/* eslint-disable global-require */

import DatabaseBridge from '../sqlite-node/DatabaseBridge'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This path is hardcoded for node and I just replaced it for now.

import DatabaseBridge from '../sqlite-tauri/DatabaseBridge'
import { type ConnectionTag } from '../../../utils/common'
import { type ResultCallback } from '../../../utils/fp/Result'
import type {
Expand Down
128 changes: 128 additions & 0 deletions src/adapters/sqlite/sqlite-tauri/Database.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/* eslint-disable no-console */
// @flow

const SQLite = require('tauri-plugin-sql').default
const {removeFile} = require('@tauri-apps/api/fs')
const { appConfigDir } = require('@tauri-apps/api/path')


class Database {
instance: TauriDB
path: string

constructor(path: string = ':memory:'): void {
this.path = path
}

async open(): Promise<void> {
try {
this.instance = await SQLite.load(`sqlite:${this.path}`)
} catch (error) {
throw new Error(`Failed to open the database. - ${error}`)
}

if (!this.instance) {
throw new Error('Failed to open the database.')
}
}

async inTransaction(executeBlock: () => Promise<void>): Promise<void> {
try {
await this.instance.execute('BEGIN TRANSACTION')
await executeBlock()
await this.instance.execute('COMMIT')
} catch (error) {
console.log('Error in transaction', error)
await this.instance.execute('ROLLBACK')
throw error
}
}

async execute(query: string, args: any[] = []): Promise<any> {
return this.instance.select(query, args)
}

async executeStatements(queries: string): Promise<any> {
return this.instance.execute(queries, [])
}

async queryRaw(query: string, args: any[] = []): Promise<any | any[]> {
return this.instance.select(query, args)
}

async count(query: string, args: any[] = []): Promise<number> {
const results = await this.instance.select(query, args)
if (results.length === 0) {
throw new Error('Invalid count query, can`t find next() on the result')
}

const result = results[0]

return Number.parseInt(result.count, 10)
}

async userVersion(): Promise<number> {
const results = await this.instance.select('PRAGMA user_version')
return results[0].user_version
}

async setUserVersion(version: number): Promise<void> {
await this.instance.execute(`PRAGMA user_version = ${version}`)
}

async unsafeDestroyEverything(): Promise<void> {
// Deleting files by default because it seems simpler, more reliable
// And we have a weird problem with sqlite code 6 (database busy) in sync mode
// But sadly this won't work for in-memory (shared) databases, so in those cases,
// drop all tables, indexes, and reset user version to 0

// if (this.isInMemoryDatabase()) {
// this.inTransaction(async () => {
// const results = await this.queryRaw(`SELECT * FROM sqlite_master WHERE type = 'table'`)
// const tables = results.map((table) => table.name)

// tables.forEach((table) => {
// this.execute(`DROP TABLE IF EXISTS '${table}'`)
// })

// this.execute('PRAGMA writable_schema=1')
// const count = (await this.queryRaw(`SELECT * FROM sqlite_master`)).length
// if (count) {
// // IF required to avoid SQLIte Error
// this.execute('DELETE FROM sqlite_master')
// }
// this.execute('PRAGMA user_version=0')
// this.execute('PRAGMA writable_schema=0')
// })
// } else {
await this.instance.close()
const appConfigDirPath = await appConfigDir()
await removeFile(`${appConfigDirPath}${this.path}`)
// // if (this.instance.open) {
// // throw new Error('Could not close database')
// // }

// // if (fs.existsSync(this.path)) {
// // fs.unlinkSync(this.path)
// // }
// // if (fs.existsSync(`${this.path}-wal`)) {
// // fs.unlinkSync(`${this.path}-wal`)
// // }
// // if (fs.existsSync(`${this.path}-shm`)) {
// // fs.unlinkSync(`${this.path}-shm`)
// // }

await this.open()
// }

// TODO Tauri's sqlite plugin doesn't support any way to destroy the db
// Need to take a look later how to achieve this
// Closing it is possible but how to remove the file?
}

isInMemoryDatabase(): any {
return false
}
}

export default Database
Loading