This commit is contained in:
2026-09-24 16:25:22 +08:00
commit 7428184f01
1198 changed files with 314515 additions and 0 deletions
@@ -0,0 +1,4 @@
{
"minSdkVersion": "21",
"dependencies":[]
}
@@ -0,0 +1,362 @@
import xSqliteHelp from 'uts.sdk.modules.utsXsqliteS.xSqliteHelp';
import SQLiteResultByKt from 'uts.sdk.modules.utsXsqliteS.SQLiteResultByKt';
import SQLiteConfigByKt from 'uts.sdk.modules.utsXsqliteS.SQLiteConfigByKt';
import SQLiteExecuteBatchParamsByKt from 'uts.sdk.modules.utsXsqliteS.SQLiteExecuteBatchParamsByKt';
import {SQLiteConfig,SQLiteResult,SQLiteExecuteBatchParams} from '../interface.uts';
import Kotlin from 'kotlin.jvm.internal.Intrinsics.Kotlin';
/**
* SQLite数据库操作类
* 提供SQLite数据库的创建、查询、更新等基本操作,支持加密和事务处理
*/
export class xSqlite {
/** 数据库配置信息 */
config : SQLiteConfig;
private db : xSqliteHelp|null = null;
constructor(config : SQLiteConfig = {}) {
let realCofing:SQLiteConfig = config;
let directory:null|string = realCofing?.defaultDirectory??null
if(typeof directory == 'string' && directory !=null){
directory = UTSAndroid.convert2AbsFullPath(directory)
}
realCofing.defaultDirectory = directory
this.config = realCofing;
this.db = new xSqliteHelp(
UTSAndroid.getAppContext()!,
SQLiteConfigByKt(
password = this.config.password,
encryption = (this.config?.encryption??false),
defaultDirectory = (this.config?.defaultDirectory??null),
)
)
}
private converFormat(result?:SQLiteResultByKt):SQLiteResult{
if(result==null){
return {
rows: [] ,
columns: [] ,
changes: null,
lastInsertRowid: null,
error: null,
};
}
let rows = [] as any[][];
let maps = [] as Map<string,any>[];
let columns = [] as string[];
if(result?.rows!=null){
let cols = result!.columns as ArrayList<string>;
columns = Array.fromNative(cols)
}
if(result?.rows!=null){
let crows = result!.rows as ArrayList<ArrayList<any>>;
for (col in crows) {
rows.push(Array.fromNative(col))
}
}
if(result?.maps!=null){
let cmaps = result!.maps as ArrayList<LinkedHashMap<string,any>>;
for (col in cmaps) {
let item = col as LinkedHashMap<string,any>;
let newmap = new Map<string,any>()
for(key in columns){
newmap.set(key,item.get(key)!)
}
maps.push(newmap)
}
}
return {
rows: rows,
columns: columns,
maps: maps,
changes: result?.changes,
lastInsertRowid: result?.lastInsertRowid,
error: result?.error,
};
}
/**
* 创建数据库
* @param fileName 数据库文件名,如果为null则使用默认名称'sqlite'
* @returns 创建成功返回true,失败返回false
*/
createDb(fileName:string|null = null) : boolean{
if (this.db==null){
return false;
}
const result = this.db!.createDb(fileName)
return result != null;
}
/**
* 执行SQL语句
* @param sql SQL语句
* @param params SQL参数数组
* @returns SQLiteResult 执行结果,包含changes(影响行数)和lastInsertRowid(最后插入行ID)
*/
run(sql: string, params: any[] = []): SQLiteResult {
try {
if (this.db==null){
return {error:'Database not initialized'};
}
const result = this.db!.run(sql, params);
return this.converFormat(result)
} catch (error) {
return { error: error.message };
}
}
/**
* 查询数据
* @param sql 查询SQL语句
* @param params 查询参数数组
* @returns SQLiteResult 查询结果,包含rows(数据行)和columns(列名)
*/
query(sql: string, params: any[] = [] as any[]): SQLiteResult {
if (this.db==null){
return {error:'Database not initialized'};
}
const result = this.db!.query(sql, params.toKotlinList());
return this.converFormat(result)
}
/**
* 插入数据
* @param table 表名
* @param data 要插入的数据对象
* @returns SQLiteResult 插入结果
*/
insert(table: string, data: UTSJSONObject): SQLiteResult {
if (this.db==null){
return {error:'Database not initialized'};
}
const result = this.db!.insert(table, new org.json.JSONObject(data.toJSONString()));
return this.converFormat(result)
}
/**
* 更新数据
* @param table 表名
* @param data 要更新的数据对象
* @param where WHERE条件语句
* @param params WHERE条件参数数组
* @returns SQLiteResult 更新结果
*/
update(table: string, data: UTSJSONObject, where: string, params: any[] = []): SQLiteResult {
if (this.db==null){
return {error:'Database not initialized'};
}
const result = this.db!.update(table,
new org.json.JSONObject(data.toJSONString()),
where,
params.toKotlinList()
);
return this.converFormat(result)
}
/**
* 删除数据
* @param table 表名
* @param where WHERE条件语句
* @param params WHERE条件参数数组
* @returns SQLiteResult 删除结果
*/
delete(table: string, where: string, params: any[] = []): SQLiteResult {
if (this.db==null){
return {error:'Database not initialized'};
}
const result = this.db!.delete(table, where ,params.toKotlinList());
return this.converFormat(result)
}
/**
* 检查表是否存在
* @param tableName 表名
* @returns 表存在返回true,不存在返回false
*/
tableExists(tableName: string): boolean {
if (this.db==null){
return false
}
return this.db!.tableExists(tableName);
}
/**
* 创建数据表
* @param tableName 表名
* @param columns 列定义对象,key为列名,value为列类型定义
* @returns SQLiteResult 创建结果
*/
createTable(tableName: string, columns: UTSJSONObject): SQLiteResult {
try {
if (this.db==null){
return {error:'Database not initialized'};
}
const dataMap = new Map<string,string>();
for(const key in columns){
const item = columns.getString(key)!;
dataMap.set(key,item)
}
const result = this.db!.createTable(tableName, dataMap);
return this.converFormat(result)
} catch (error) {
return { error: error.message };
}
}
/**
* 删除数据表
* @param tableName 要删除的表名
* @returns SQLiteResult 删除结果
*/
dropTable(tableName: string): SQLiteResult {
if (this.db==null){
return {error:'Database not initialized'};
}
const result = this.db!.dropTable(tableName);
return this.converFormat(result)
}
/**
* 关闭数据库连接
* 释放数据库资源,关闭后需要重新创建才能使用
*/
close(): void {
if (this.db!=null) {
this.db!.close();
this.db = null;
}
}
/**
* 开始事务
* 开始一个新的事务,在提交或回滚之前,所有操作都在事务内
* @returns SQLiteResult 事务开始结果
*/
beginTransaction(): SQLiteResult{
if (this.db==null){
return {error:'Database not initialized'};
}
const result = this.db!.beginTransaction();
return this.converFormat(result)
}
/**
* 提交事务
* 提交当前事务的所有操作
* @returns SQLiteResult 事务提交结果
*/
commit(): SQLiteResult {
if (this.db==null){
return {error:'Database not initialized'};
}
const result = this.db!.commit();
return this.converFormat(result)
}
/**
* 回滚事务
* 撤销当前事务中的所有操作
* @returns SQLiteResult 事务回滚结果
*/
rollback(): SQLiteResult {
if (this.db==null){
return {error:'Database not initialized'};
}
const result = this.db!.rollback();
return this.converFormat(result)
}
/**
* 批量执行SQL语句
* @param statements SQL语句数组,每个元素包含sql和params
* @returns SQLiteResult[] 每个语句的执行结果数组
*/
executeBatch(statements: SQLiteExecuteBatchParams[]): SQLiteResult[] {
if (this.db==null){
console.error('Database not initialized')
return [];
}
const list = new ArrayList<SQLiteExecuteBatchParamsByKt>()
for(const item in statements){
list.add(SQLiteExecuteBatchParamsByKt(
sql = item.sql,
params = (item?.params??[]).toKotlinList()
))
}
const result = this.db!.executeBatch(list);
let resultList = [] as SQLiteResult[]
for(const item in result){
resultList.push(this.converFormat(item))
}
return resultList
}
/**
* 保存数据库到本地文件
* @param filename 保存的文件名,可选,默认为'sqlite'
* @returns SQLiteResult 保存结果
*/
saveLocal(filename?: string): SQLiteResult {
if (this.db==null){
return {error:'Database not initialized'};
}
const result = this.db!.saveLocal(filename);
return this.converFormat(result)
}
/**
* 从本地文件加载数据库
* @param filename 要加载的数据库文件名
* @returns SQLiteResult 加载结果
*/
loadLocal(filename:string): SQLiteResult{
const result = this.db!.loadLocal(filename);
return this.converFormat(result)
}
/**
* 获取数据库文件路径
* 获取当前数据库文件的完整路径,获取前会备份到缓存目录
* @returns string|null 数据库文件路径,如果数据库未初始化则返回null
*/
getDatabasePath():string|null{
if (this.db==null){
console.error('Database not initialized')
return null
}
return this.db!.getDatabasePath();
}
/**
* 当前数据库的目录
*/
setDefaultDirectory(directory: string){
if (this.db==null){
console.error('Database not initialized')
return
}
let rdirectory = directory;
if(rdirectory!=''){
rdirectory = UTSAndroid.convert2AbsFullPath(directory)
}
this.db!.setDefaultDirectory(rdirectory);
}
/**
* 设置数据库密码
* 空值或者null即删除密码
*/
setPassword(password: string|null = null){
if (this.db==null){
console.error('Database not initialized')
return
}
this.db!.setPassword(password);
}
}
@@ -0,0 +1,364 @@
package uts.sdk.modules.utsXsqliteS
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import org.json.JSONObject
import java.io.File
import io.dcloud.uts.console
data class SQLiteConfigByKt(
var password: String? = null,
var encryption: Boolean = false,
var locateFile: ((String) -> String)? = null,
var defaultDirectory: String? = null
)
data class SQLiteResultByKt(
val rows: List<List<Any>>? = null,
val columns: List<String>? = null,
val changes: Int? = null,
val lastInsertRowid: Long? = null,
val error: String? = null,
val maps: List<Map<String, Any>>? = null
)
data class SQLiteExecuteBatchParamsByKt(
val sql: String,
val params: List<Any>? = null
)
class xSqliteHelp(private val context: Context, private val config: SQLiteConfigByKt = SQLiteConfigByKt()) {
private var db: SQLiteDatabase? = null
private var isInTransaction: Boolean = false
private var fileURLPath: String? = null
fun createDb(filename: String? = null): SQLiteDatabase? {
val fname = filename ?: "sqlite"
val dbFile = if (config.defaultDirectory != null) {
File(config.defaultDirectory, "$fname.db")
} else {
context.getDatabasePath("$fname.db")
}
try {
if (!dbFile.parentFile?.exists()!!) {
dbFile.parentFile?.mkdirs()
}
db = SQLiteDatabase.openOrCreateDatabase(dbFile, null)
if (config.encryption && config.password != null) {
run("PRAGMA key = ?", listOf(config.password!!))
}
fileURLPath = dbFile.absolutePath
return db
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
// 执行SQL查询
fun run(sql: String, params: List<Any> = emptyList()): SQLiteResultByKt {
return try {
if (db == null) throw Exception("Database not initialized")
val statement = db!!.compileStatement(sql)
params.forEachIndexed { index, param ->
when (param) {
is String -> statement.bindString(index + 1, param)
is Int -> statement.bindLong(index + 1, param.toLong())
is Long -> statement.bindLong(index + 1, param)
is Double -> statement.bindDouble(index + 1, param)
is ByteArray -> statement.bindBlob(index + 1, param)
null -> statement.bindNull(index + 1)
}
}
// 根据SQL语句类型选择合适的执行方法
val sqlUpperCase = sql.trim().uppercase()
val result = if (sqlUpperCase.startsWith("INSERT")) {
// 对于INSERT语句,使用executeInsert获取lastInsertRowid
val lastId = statement.executeInsert()
SQLiteResultByKt(changes = 1, lastInsertRowid = lastId)
} else {
// 对于UPDATE/DELETE/其他语句,使用executeUpdateDelete获取受影响的行数
val changes = statement.executeUpdateDelete()
SQLiteResultByKt(changes = changes, lastInsertRowid = null)
}
result
} catch (e: Exception) {
SQLiteResultByKt(error = e.message)
}
}
// 查询数据
fun query(sql: String, params: List<Any> = emptyList()): SQLiteResultByKt {
return try {
if (db == null) throw Exception("Database not initialized")
val args = params.map { it?.toString() ?: "" }.toTypedArray()
val cursor = db!!.rawQuery(sql, args)
val columns = ArrayList(cursor.columnNames.toList())
val rows = mutableListOf<List<Any>>()
val maps = mutableListOf<Map<String, Any>>()
while (cursor.moveToNext()) {
val row = mutableListOf<Any>()
val map = mutableMapOf<String, Any>()
for (i in 0 until cursor.columnCount) {
val columnName = cursor.getColumnName(i)
val value = when (cursor.getType(i)) {
android.database.Cursor.FIELD_TYPE_STRING -> cursor.getString(i)
android.database.Cursor.FIELD_TYPE_INTEGER -> cursor.getLong(i)
android.database.Cursor.FIELD_TYPE_FLOAT -> cursor.getDouble(i)
android.database.Cursor.FIELD_TYPE_BLOB -> cursor.getBlob(i)
else -> ""
}
row.add(value)
map[columnName] = value
}
rows.add(row)
maps.add(map)
}
cursor.close()
SQLiteResultByKt(rows = rows, columns = columns, maps = maps)
} catch (e: Exception) {
SQLiteResultByKt(error = e.message)
}
}
// 插入数据
fun insert(table: String, data: JSONObject): SQLiteResultByKt {
val keys = mutableListOf<String>()
val values = mutableListOf<Any>()
data.keys().forEach { key ->
keys.add(key)
values.add(data.get(key))
}
val sql = "INSERT INTO $table (${keys.joinToString(",")}) VALUES (${keys.map { "?" }.joinToString(",")})"
return run(sql, values)
}
// 更新数据
fun update(table: String, data: JSONObject, where: String, params: List<Any> = emptyList()): SQLiteResultByKt {
val sets = mutableListOf<String>()
val values = mutableListOf<Any>()
data.keys().forEach { key ->
sets.add("$key = ?")
values.add(data.get(key))
}
values.addAll(params)
val sql = "UPDATE $table SET ${sets.joinToString(",")} WHERE $where"
return run(sql, values)
}
// 删除数据
fun delete(table: String, where: String, params: List<Any> = emptyList()): SQLiteResultByKt {
val sql = "DELETE FROM $table WHERE $where"
return run(sql, params)
}
// 保存数据库到本地
fun saveLocal(filename: String? = null): SQLiteResultByKt {
return try {
if (db == null) throw Exception("Database not initialized")
val fname = filename ?: "sqlite"
// 获取当前数据库文件的实际路径
val dbPath = db!!.path
val dbFile = if (dbPath.isNotEmpty()) File(dbPath) else context.getDatabasePath("sqlite.db")
// 检查源文件是否存在
if (!dbFile.exists()) {
return SQLiteResultByKt(error = "未能找到数据库文件")
}
// 使用配置的默认目录或系统文件目录
val targetDir = if (config.defaultDirectory != null) File(config.defaultDirectory) else context.filesDir
val targetFile = File(targetDir, "$fname.db")
// 确保目标目录存在
targetFile.parentFile?.mkdirs()
if(dbFile.absolutePath != targetFile.absolutePath){
dbFile.copyTo(targetFile, overwrite = true)
}
SQLiteResultByKt()
} catch (e: Exception) {
SQLiteResultByKt(error = e.message)
}
}
// 从本地加载数据库
fun loadLocal(filename: String): SQLiteResultByKt {
return try {
// 使用配置的默认目录或系统文件目录
val sourceDir = if (config.defaultDirectory != null) File(config.defaultDirectory!!) else context.filesDir
val sourceFile = File(sourceDir, "$filename.db")
if (!sourceFile.exists()) {
return SQLiteResultByKt(error = "没有数据库")
}
val dbFile = context.getDatabasePath("sqlite.db")
sourceFile.copyTo(dbFile, overwrite = true)
createDb(filename)
SQLiteResultByKt()
} catch (e: Exception) {
SQLiteResultByKt(error = "数据库损坏")
}
}
// 设置默认目录
fun setDefaultDirectory(directory: String) {
config.defaultDirectory = directory
}
// 设置密码
fun setPassword(password: String?) {
config.password = password
config.encryption = password != null && password.isNotEmpty()
if (db != null) {
if (config.encryption && config.password != null) {
run("PRAGMA rekey = ?", listOf(config.password!!))
} else {
run("PRAGMA rekey = ''", emptyList())
}
}
}
// 检查表是否存在
fun tableExists(tableName: String): Boolean {
val result = query("SELECT name FROM sqlite_master WHERE type='table' AND name=?", listOf(tableName))
return result.rows?.isNotEmpty() == true
}
// 创建数据表
fun createTable(tableName: String, columns: Map<String, String>): SQLiteResultByKt {
val columnDefinitions = columns.entries.joinToString(",") { (name, type) -> "$name $type" }
val sql = "CREATE TABLE IF NOT EXISTS $tableName ($columnDefinitions)"
return run(sql)
}
// 删除数据表
fun dropTable(tableName: String): SQLiteResultByKt {
val sql = "DROP TABLE IF EXISTS $tableName"
return run(sql)
}
// 关闭数据库
fun close() {
db?.close()
db = null
}
// 开始事务
fun beginTransaction(): SQLiteResultByKt {
return try {
if (isInTransaction) {
return SQLiteResultByKt(error = "Transaction already in progress")
}
db?.beginTransaction()
isInTransaction = true
SQLiteResultByKt()
} catch (e: Exception) {
SQLiteResultByKt(error = e.message)
}
}
// 提交事务
fun commit(): SQLiteResultByKt {
return try {
if (!isInTransaction) {
return SQLiteResultByKt(error = "No transaction in progress")
}
db?.setTransactionSuccessful()
db?.endTransaction()
isInTransaction = false
SQLiteResultByKt()
} catch (e: Exception) {
SQLiteResultByKt(error = e.message)
}
}
// 回滚事务
fun rollback(): SQLiteResultByKt {
return try {
if (!isInTransaction) {
return SQLiteResultByKt(error = "No transaction in progress")
}
db?.endTransaction()
isInTransaction = false
SQLiteResultByKt()
} catch (e: Exception) {
SQLiteResultByKt(error = e.message)
}
}
// 批量执行SQL
fun executeBatch(statements: List<SQLiteExecuteBatchParamsByKt>): List<SQLiteResultByKt> {
val results = mutableListOf<SQLiteResultByKt>()
var hasError = false
val wasInTransaction = isInTransaction
if (!wasInTransaction) {
beginTransaction()
}
try {
for (stmt in statements) {
val result = run(stmt.sql, stmt.params ?: emptyList())
results.add(result)
if (result.error != null) {
hasError = true
break
}
}
if (hasError && !wasInTransaction) {
rollback()
} else if (!wasInTransaction) {
commit()
}
} catch (e: Exception) {
if (!wasInTransaction) {
rollback()
}
results.add(SQLiteResultByKt(error = e.message))
}
return results
}
/**
* 获取数据库文件路径获取前会备份到缓存目录
*/
fun getDatabasePath(): String? {
if (db == null) return null
try {
// 获取当前数据库文件
// val dbFile = db!!.path
val dbFile = File(db!!.path)
if (!dbFile.exists() || !dbFile.canRead()) {
return null
}
// 获取缓存目录
val cacheDir = context.cacheDir
val tempFile = File(cacheDir, "tmui4x_xSqlite_DbackTemp.db")
// 如果临时文件存在则删除
if (tempFile.exists()) {
tempFile.delete()
}
// 复制数据库文件到缓存目录
dbFile.copyTo(tempFile, overwrite = true)
return tempFile.absolutePath
} catch (e: Exception) {
return null
}
}
}