commit 2331736738f48b3df98f3a8d2729c5005ab0379d Author: Y7000p Date: Mon May 16 19:56:37 2022 +0800 add ... Signed-off-by: Y7000p diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a1c2a23 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0756766 --- /dev/null +++ b/README.md @@ -0,0 +1,265 @@ +# LiteOrm_Mod +**本项目是基于开源项目LiteOrm进行优化的移植和开发的,可以通过项目标签以及gitee地址(https://gitee.com/hihopeorg/ohos-lite-orm) 追踪到原项目版本** + +#### 项目介绍 + - 项目名称: 高性能数据库框架 + - 所属系列:ohos的第三方组件适配移植 + - 功能: LiteOrm是一个小巧、强大、比系统自带数据库操作性能快1倍的 ORM 框架类库,开发者一行代码实现数据库的增删改查操作,以及实体关系的持久化和自动映射。 + - 项目移植状态:完成 + - 调用差异:无 + - 项目作者和维护人: hihope,田梓萱 + - 联系方式:hihope@hoperun.com,xcl@xuegao-tzx.top + - 原项目Doc地址:https://gitee.com/hihopeorg/ohos-lite-orm + - 原项目基线版本:v1.0.0 + - 编程语言:Java + - 外部库依赖: 无 + +##### 功能特点 + +- 支持多库:每个数据库文件对应一个LiteOrm管理类实例。 +- 自动建表:开发者无需关心数据库以及表细节。 +- 库文件操作:新建、打开、删除、释放一个数据库文件。 +- 独立操作:使用 LiteOrm 的 single 实例,可与 cascade 方式平滑切换,性能高,仅处理该对象数据,其关系、和关联对象忽略; +- 级联操作:使用 LiteOrm 的 cascade 实例,可与 single 方式平滑切换,全递归,该对象数据,及其关系、和关联对象都被处理; +- 关系存储和恢复:真正实现实体关系映射持久化以及恢复,只需在实体的关联属性上标出关系类型即可。 +- 智能列探测:App升级或者Model改变,新加了属性字段,该字段将被探测到并加入数据库中,因此无需担心新字段不被存储。 +- 丰富API支持:save(replace), insert, update, delete, query, mapping, etc。 +- 自动识别类型:分别转化为以sqlite支持的TEXT, REAL, INTEGER, BLOB几种数据类型存储。 +- 自动构建对象,通过反射和探测构造函数参数等hack手法新建对象,大多情况下亦不需要无参构造函数。 +- 更新指定列,可灵活、强制、批量赋值,强制赋值将无视被操作对象的真实值。 +- 存储序列化字段:Date、ArrayList、Vector等各种容器智能保存及读取。 +- 约束性语法支持:NOT NULL, UNIQUE, DEFAULT, COLLATE, CHECK, PRIMARY KEY,支持冲突算法。 +- 灵活的查询和删除:columns, where, roder, limit, having group, etc。 + + +#### 优化点 + +1. 解决了原版无法控制日志的问题 +2. 导入har包即可使用,适配API6和DevEco3.0 +3. 无需读写权限亦可以正常使用 + + +#### 安装教程 + +##### 方案一: + + 直接引入 library.har 依赖即可 + +``` +allprojects { + repositories { + mavenCentral() + } +} +... +dependencies { + ... + implementation 'top.xuegao-tzx:library:1.2.0' + ... +} +``` + +##### 方案二: + +1. 下载依赖库har包 library.har。 +2. 启动 DevEco Studio,将下载的har包,导入工程目录“entry->libs”下。 +3. 在moudle级别下的build.gradle文件中添加依赖,在dependences标签中增加对libs目录下har包的引用。 +``` +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar', '*.har']) + …… +} +``` +4. 在导入的har包上点击右键,选择“Add as Library”对包进行引用,选择需要引用的模块,并点击“OK”即引用成功。 + + +#### 使用说明 +##### 配置网络权限 +由于LiteOrm涉及到文件和网络的操作,因此需要你在config.json文件中添加以下权限 +```config.json +{ + "reqPermissions": [ + { + "name": " com.xcl.demo.DataAbilityShellProvider.PROVIDER", + ... + } + ] +} +``` +##### 快速起步:初始化应保持单例 +一个数据库对应一个LiteOrm的实例,如果一个App只有一个数据库,那么LiteOrm应该是全局单例的。 +如果多次新建LiteOrm实例,系统会提示你应该关闭之前的数据库,也可能会引起其他未知错误。 + +保持单例: +```java +static LiteOrm liteOrm; + +if (liteOrm == null) { + liteOrm = LiteOrm.newSingleInstance(this, "liteorm.db"); +} +liteOrm.setDebugged(true); // open the log +``` +##### 基本注解 +新建一个Test Model,将其作为操作对象: + +```java +@Table("test_model") +public class TestModel { + + // 指定自增,每个对象需要有一个主键 + @PrimaryKey(AssignType.AUTO_INCREMENT) + private int id; + + // 非空字段 + @NotNull + private String name; + + //忽略字段,将不存储到数据库 + @Ignore + private String password; + + // 默认为true,指定列名 + @Default("true") + @Column("login") + private Boolean isLogin; +} +``` + +LiteOrm将为开发者建一个名为“test_model”的数据库表,其字段为:id name login。 +建表语句:CREATE TABLE IF NOT EXISTS test_model (id INTEGER PRIMARY KEY AUTOINCREMENT ,name TEXT, login TEXT DEFAULT true) +。 + +##### 常用操作 + +直接操作对象即可,LiteOrm会为你完成探测、建表等工作。 + +- 保存(插入or更新) +```java +School school = new School("hello"); +liteOrm.save(school); + +``` + +- 插入 +​```java +Book book = new Book("good"); +liteOrm.insert(book, ConflictAlgorithm.Abort); +``` + +- 更新 +​```java +book.setIndex(1988); +book.setAuthor("hehe"); +liteOrm.update(book); +``` + +- 更新指定列 +```java +// 把所有书的author强制批量改为liter +HashMap bookIdMap = new HashMap(); +bookIdMap.put(Book.COL_AUTHOR, "liter"); +liteOrm.update(bookList, new ColumnsValue(bookIdMap), ConflictAlgorithm.Fail); +``` + +```java +// 仅 author 这一列更新为该对象的最新值。 +//liteOrm.update(bookList, new ColumnsValue(new String[]{Book.COL_AUTHOR}, null), ConflictAlgorithm.Fail); +``` + +- 查询 +```java +List list = liteOrm.query(Book.class); +OrmLog.i(TAG, list); +``` + +- 查找 使用WhereBuilder +```java +List list = liteOrm.query(new QueryBuilder(Student.class) + .where(Person.COL_NAME + " LIKE ?", new String[]{"%0"}) + .whereAppendAnd() + .whereAppend(Person.COL_NAME + " LIKE ?", new String[]{"%s%"})); +OrmLog.i(TAG, list); +``` + +- 查询 根据ID +```java +Student student = liteOrm.queryById(student1.getId(), Student.class); +OrmLog.i(TAG, student); +``` + +- 查询 任意 +```java +List books = liteOrm.query(new QueryBuilder(Book.class) + .columns(new String[]{"id", "author", Book.COL_INDEX}) + .distinct(true) + .whereGreaterThan("id", 0) + .whereAppendAnd() + .whereLessThan("id", 10000) + .limit(6, 9) + .appendOrderAscBy(Book.COL_INDEX)); +OrmLog.i(TAG, books); +``` + +- 删除 实体 +```java +// 删除 student-0 +liteOrm.delete(student0); +``` + +- 删除 指定数量 +```java +// 按id升序,删除[2, size-1],结果:仅保留第一个和最后一个 +// 最后一个参数可为null,默认按 id 升序排列 +liteOrm.delete(Book.class, 2, bookList.size() - 1, "id"); +``` + +- 删除 使用WhereBuilder +```java +// 删除 student-1 +liteOrm.delete(new WhereBuilder(Student.class) + .where(Person.COL_NAME + " LIKE ?", new String[]{"%1%"}) + .and() + .greaterThan("id", 0) + .and() + .lessThan("id", 10000)); +``` + +- 删除全部 +```java +// 连同其关联的classes,classes关联的其他对象一带删除 +liteOrm.deleteAll(School.class); +liteOrm.deleteAll(Book.class); + + +// 顺带测试:连库文件一起删掉 +liteOrm.deleteDatabase(); +// 顺带测试:然后重建一个新库 +liteOrm.openOrCreateDatabase(); +// 满血复活 +``` + +---- + +#### 版本迭代 + - v1.1.0 + + > 修改了源项目,使其可以正常使用。 + +----- + +### 开源许可证 +``` +Copyright [2022] [田梓萱] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/library/.gitignore b/library/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/library/.gitignore @@ -0,0 +1 @@ +/build diff --git a/library/build.gradle b/library/build.gradle new file mode 100644 index 0000000..2e2b65b --- /dev/null +++ b/library/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'com.huawei.ohos.library' +ohos { + compileSdkVersion 6 + defaultConfig { + compatibleSdkVersion 5 + } + buildTypes { + release { + proguardOpt { + proguardEnabled true + rulesFiles 'proguard-rules.pro' + } + } + debug { + proguardOpt { + proguardEnabled true + rulesFiles 'proguard-rules.pro' + } + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + testImplementation 'junit:junit:4.13.1' +} diff --git a/library/proguard-rules.pro b/library/proguard-rules.pro new file mode 100644 index 0000000..d875c2c --- /dev/null +++ b/library/proguard-rules.pro @@ -0,0 +1,53 @@ +-dontwarn +# 代码混淆压缩比,在0~7之间 +-optimizationpasses 5 +# 混合时不使用大小写混合,混合后的类名为小写 +-dontusemixedcaseclassnames +# 在读取依赖的库文件时,不要略过那些非public类成员 +-dontskipnonpubliclibraryclassmembers +# 指定不去忽略非公共库的类 +-dontskipnonpubliclibraryclasses +# 不做预校验,preverify是proguard的四个步骤之一,去掉这一步能够加快混淆速度。 +-dontpreverify +-verbose +# google推荐算法 +-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/* +# 保留注解、内部类、泛型、匿名类 +-keepattributes *Annotation*,Exceptions,InnerClasses,Signature,EnclosingMethod +# 重命名抛出异常时的文件名称 +-renamesourcefileattribute SourceFile +# 抛出异常时保留代码行号 +-keepattributes SourceFile,LineNumberTable +-dontwarn javax.annotation.** +# 保留本地native方法不被混淆 +-keepclasseswithmembernames,allowshrinking class * { +native ; +} +# 保留枚举类不被混淆 +-keepclassmembers enum * { +public static **[] values(); +public static ** valueOf(java.lang.String); +} +# 保留自定义类 + +使用了注解的部分 + +# 忽略数据库有关 +-keep class com.litesuits.orm.** +-keepclassmembers class com.litesuits.orm.**{*;} +-keep enum com.litesuits.orm.** +-keepclassmembers enum com.litesuits.orm.**{*;} +-keep interface com.litesuits.orm.** +-keepclassmembers interface com.litesuits.orm.**{*;} +-keep class com.xcl.calculator.DataANet.**{*;} +# 忽略继承 +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} +# 保留配置文件 +-printmapping mapping.txt \ No newline at end of file diff --git a/library/src/main/config.json b/library/src/main/config.json new file mode 100644 index 0000000..946105d --- /dev/null +++ b/library/src/main/config.json @@ -0,0 +1,28 @@ +{ + "app": { + "bundleName": "com.xcl.litesuits.demo", + "vendor": "tzx", + "version": { + "code": 1002000, + "name": "1.1.0" + }, + "apiVersion": { + "compatible": 5, + "target": 6 + } + }, + "deviceConfig": {}, + "module": { + "package": "com.litesuits.library", + "deviceType": [ + "phone", + "wearable", + "tablet" + ], + "distro": { + "deliveryWithInstall": true, + "moduleName": "library", + "moduleType": "har" + } + } +} \ No newline at end of file diff --git a/library/src/main/java/com/litesuits/orm/LiteOrm.java b/library/src/main/java/com/litesuits/orm/LiteOrm.java new file mode 100644 index 0000000..cad6434 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/LiteOrm.java @@ -0,0 +1,650 @@ +/* + * Copyright (C) 2013 litesuits.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.litesuits.orm; + +import com.litesuits.orm.db.DataBase; +import com.litesuits.orm.db.DataBaseConfig; +import com.litesuits.orm.db.TableManager; +import com.litesuits.orm.db.assit.*; +import com.litesuits.orm.db.impl.CascadeSQLiteImpl; +import com.litesuits.orm.db.impl.SingleSQLiteImpl; +import com.litesuits.orm.db.model.*; +import com.litesuits.orm.db.utils.ClassUtil; +import com.litesuits.orm.db.utils.DataUtil; +import com.litesuits.orm.db.utils.FieldUtil; +import com.litesuits.orm.log.Log; +import com.litesuits.orm.log.OrmLog; +import ohos.app.Context; +import ohos.data.DatabaseHelper; +import ohos.data.rdb.RdbStore; +import ohos.data.resultset.ResultSet; +import ohos.data.resultset.ResultSetHook; + +import java.io.File; +import java.io.FileFilter; +import java.util.*; + +/** + * 数据SQLite操作实现 + * 可查阅 SQLite操作指南 + * + * @author mty + * @date 2013 -6-2下午2:32:56 + */ +public abstract class LiteOrm /*extends SQLiteClosable*/ implements DataBase { + + /** + * The constant TAG. + */ + private static final String TAG = LiteOrm.class.getSimpleName(); + /** + * The M config. + */ + private final DataBaseConfig mConfig; + /** + * The M helper. + */ + protected SQLiteHelper mHelper; + /** + * The M table manager. + */ + protected TableManager mTableManager; + /** + * The Other database. + */ + protected LiteOrm otherDatabase; + + /** + * Instantiates a new Lite orm. + * + * @param dataBase the data base + */ + protected LiteOrm(LiteOrm dataBase) { + this.mHelper = dataBase.mHelper; + this.mConfig = dataBase.mConfig; + this.mTableManager = dataBase.mTableManager; + this.otherDatabase = dataBase; + } + + /** + * Instantiates a new Lite orm. + * + * @param config the config + */ + protected LiteOrm(DataBaseConfig config) { + config.context = config.context.getApplicationContext(); + if (config.dbName == null) config.dbName = DataBaseConfig.DEFAULT_DB_NAME; + if (config.dbVersion <= 0) config.dbVersion = DataBaseConfig.DEFAULT_DB_VERSION; + this.mConfig = config; + this.setDebugged(config.debugged); + this.openOrCreateDatabase(); + } + + /** + * get and new a single model operator based on SQLite + * + * @param context app context + * @param dbName database name + * @return {@link SingleSQLiteImpl} + */ + public static LiteOrm newSingleInstance(Context context, String dbName) { + return newSingleInstance(new DataBaseConfig(context, dbName)); + } + + /** + * get and new a single model operator based on SQLite + * + * @param config lite-orm config + * @return {@link CascadeSQLiteImpl} + */ + private synchronized static LiteOrm newSingleInstance(DataBaseConfig config) { + return SingleSQLiteImpl.newInstance(config); + } + + /** + * get and new a cascade model operator based on SQLite + * + * @param context app context + * @param dbName database name + * @return {@link SingleSQLiteImpl} + */ + public static LiteOrm newCascadeInstance(Context context, String dbName) { + return newCascadeInstance(new DataBaseConfig(context, dbName)); + } + + /** + * get and new a cascade model operator based on SQLite + * + * @param config lite-orm config + * @return {@link CascadeSQLiteImpl} + */ + private synchronized static LiteOrm newCascadeInstance(DataBaseConfig config) { + return CascadeSQLiteImpl.newInstance(config); + } + + /** + * Attempts to release memory that SQLite holds but does not require to + * operate properly. Typically this memory will come from the page cache. + * + * @return the number of bytes actually released + */ + public static int releaseMemory() { + return DatabaseHelper.releaseRdbMemory();//SQLiteDatabase.releaseMemory(); + } + + /** + * Open or create database rdb store. + * + * @param path the path + * @param factory the factory + * @return the rdb store + */ + @Override + public RdbStore openOrCreateDatabase(String path, ResultSetHook factory) { + Log.w("LiteOrm", "openOrCreateDatabase path:" + path); + return null; + } + + /** + * Open or create database rdb store. + * + * @return the rdb store + */ + @Override + public RdbStore openOrCreateDatabase() { + this.initDatabasePath(this.mConfig.dbName); + if (this.mHelper != null) this.justRelease(); + this.mHelper = new SQLiteHelper(this.mConfig.context, this.mConfig.dbName, this.mConfig.dbVersion, this.mConfig.onUpdateListener); + RdbStore rdbStore = this.mHelper.getRdbStore(); + this.mTableManager = new TableManager(this.mConfig.dbName, rdbStore); + return rdbStore; + } + + /** + * Init database path. + * + * @param path the path + */ + private void initDatabasePath(String path) { + OrmLog.i(TAG, "create database path: " + path); + /* + 鸿蒙获取的是dir 需要验证dir下是否有db文件 + path = mConfig.context.getDataDir().getDatabasePath(mConfig.dbName).getPath(); + */ + File dataDir = this.mConfig.context.getDatabaseDir(); + path = new File(dataDir, this.mConfig.dbName).getPath(); + OrmLog.i(TAG, "context database path: " + path); + File dbp = new File(path).getParentFile(); + if (dbp != null && !dbp.exists()) { + boolean mks = dbp.mkdirs(); + OrmLog.i(TAG, "create database, parent file mkdirs: " + mks + " path:" + dbp.getAbsolutePath()); + } + } + + /** + * get a single data operator based on SQLite + * + * @return {@link CascadeSQLiteImpl} + */ + public abstract LiteOrm single(); + + /** + * get a cascade data operator based on SQLite + * + * @return {@link CascadeSQLiteImpl} + */ + public abstract LiteOrm cascade(); + + /** + * when debugged is true, the {@link OrmLog} is opened. + * + * @param debugged true if debugged + */ + public void setDebugged(boolean debugged) { + this.mConfig.debugged = debugged; + OrmLog.isPrint = debugged;//田梓萱22.02.07修改增加日志可控 + } + + /** + * Query relation array list. + * + * @param class1 the class 1 + * @param class2 the class 2 + * @param key1List the key 1 list + * @return the array list + */ + @Override + public ArrayList queryRelation(Class class1, Class class2, List key1List) { + ArrayList rList = new ArrayList(); + try { + EntityTable table1 = TableManager.getTable(class1); + EntityTable table2 = TableManager.getTable(class2); + if (this.mTableManager.isSQLMapTableCreated(table1.name, table2.name)) + CollSpliter.split(key1List, SQLStatement.IN_TOP_LIMIT, new CollSpliter.Spliter() { + + @Override + public int oneSplit(ArrayList list) throws Exception { + SQLStatement stmt = SQLBuilder.buildQueryRelationSql(class1, class2, key1List); + Querier.doQuery(LiteOrm.this.mHelper.getRdbStore()/*.getReadableDatabase()*/, stmt, new Querier.CursorParser() { + + @Override + public void parseEachCursor(RdbStore db, ResultSet c) throws Exception { + RelationKey relation = new RelationKey(); + relation.key1 = c.getString(c.getColumnIndexForName(table1.name)); + relation.key2 = c.getString(c.getColumnIndexForName(table2.name)); + rList.add(relation); + } + + }); + return 0; + + } + }); + } catch (Exception e) { + e.printStackTrace(); + } finally { +// releaseReference(); + } + return rList; + } + + /** + * Mapping boolean. + * + * @param the type parameter + * @param the type parameter + * @param col1 the col 1 + * @param col2 the col 2 + * @return the boolean + */ + @Override + public boolean mapping(Collection col1, Collection col2) { + if (Checker.isEmpty(col1) || Checker.isEmpty(col2)) return false; +// acquireReference(); + try { + return this.keepMapping(col1, col2) | this.keepMapping(col2, col1); + } catch (Exception e) { + e.printStackTrace(); + } finally { +// releaseReference(); + } + return false; + } + + /** + * Create sql statement sql statement. + * + * @param sql the sql + * @param bindArgs the bind args + * @return the sql statement + */ + @Override + public SQLStatement createSQLStatement(String sql, Object[] bindArgs) { + return new SQLStatement(sql, bindArgs); + } + + /** + * Execute boolean. + * + * @param db the db + * @param statement the statement + * @return the boolean + */ + @Override + public boolean execute(RdbStore db, SQLStatement statement) { +// acquireReference(); + try { + if (statement != null) return statement.execute(db); + } catch (Exception e) { + e.printStackTrace(); + } finally { +// releaseReference(); + } + return false; + + } + + /** + * Drop table boolean. + * + * @param entity the entity + * @return the boolean + */ + @Override + @Deprecated + public boolean dropTable(Object entity) { + return this.dropTable(entity.getClass()); + } + + /** + * Drop table boolean. + * + * @param claxx the claxx + * @return the boolean + */ + @Override + public boolean dropTable(Class claxx) { + return this.dropTable(TableManager.getTable(claxx, false).name); + } + + /** + * Drop table boolean. + * + * @param tableName the table name + * @return the boolean + */ + @Override + public boolean dropTable(String tableName) { +// acquireReference(); + try { + return SQLBuilder.buildDropTable(tableName).execute(this.mHelper.getRdbStore()); + } catch (Exception e) { + e.printStackTrace(); + } finally { +// releaseReference(); + } + return false; + } + + /** + * Query count long. + * + * @param the type parameter + * @param claxx the claxx + * @return the long + */ + @Override + public long queryCount(Class claxx) { + return this.queryCount(new QueryBuilder(claxx)); + } + + /** + * Query count long. + * + * @param qb the qb + * @return the long + */ + @Override + public long queryCount(QueryBuilder qb) { +// acquireReference(); + try { + if (this.mTableManager.isSQLTableCreated(qb.getTableName())) { + RdbStore db = this.mHelper.getRdbStore(); + SQLStatement stmt = qb.createStatementForCount(); + return stmt.queryForLong(db); + } else return 0; + } catch (Exception e) { + e.printStackTrace(); + } finally { +// releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Update int. + * + * @param where the where + * @param cvs the cvs + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int update(WhereBuilder where, ColumnsValue cvs, ConflictAlgorithm conflictAlgorithm) { +// acquireReference(); + try { + RdbStore db = this.mHelper.getRdbStore();//.getWritableDatabase(); + SQLStatement stmt = SQLBuilder.buildUpdateSql(where, cvs, conflictAlgorithm); + return stmt.execUpdate(db); + } catch (Exception e) { + e.printStackTrace(); + } finally { +// releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Gets readable database. + * + * @return the readable database + */ + @Override + public synchronized RdbStore getReadableDatabase() { + return this.mHelper.getRdbStore();//.getReadableDatabase(); + } + + /** + * Gets writable database. + * + * @return the writable database + */ + @Override + public synchronized RdbStore getWritableDatabase() { + return this.mHelper.getRdbStore();//.getWritableDatabase(); + } + + /** + * Gets table manager. + * + * @return the table manager + */ + @Override + public TableManager getTableManager() { + return this.mTableManager; + } + + /** + * Gets sq lite helper. + * + * @return the sq lite helper + */ + @Override + public SQLiteHelper getSQLiteHelper() { + return this.mHelper; + } + +// @Override +// public RdbStore openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory) { +//// path = mConfig.context.getDatabasePath(mConfig.dbName).getPath(); +// File databaseDir = mConfig.context.getDatabaseDir(); +// path = new File(databaseDir,mConfig.dbName).getPath(); +// return SQLiteDatabase.openOrCreateDatabase(path, factory); +// +// } + + /** + * Gets data base config. + * + * @return the data base config + */ + @Override + public DataBaseConfig getDataBaseConfig() { + return this.mConfig; + } + + /** + * Delete database boolean. + * + * @return the boolean + */ + @Override + public boolean deleteDatabase() { + String path = this.mHelper.getRdbStore().getPath();//.getWritableDatabase().getPath(); + this.justRelease(); + OrmLog.i(TAG, "data has cleared. delete Database path: " + path); + return this.deleteDatabase(new File(path)); + } + + /** + * Delete database boolean. + * + * @param file the file + * @return the boolean + */ + @Override + public boolean deleteDatabase(File file) { +// acquireReference(); + try { + if (file == null) throw new IllegalArgumentException("file must not be null"); + boolean deleted = file.delete(); + deleted |= new File(file.getPath() + "-journal").delete(); + deleted |= new File(file.getPath() + "-shm").delete(); + deleted |= new File(file.getPath() + "-wal").delete(); + + File dir = file.getParentFile(); + if (dir != null) { + String prefix = file.getName() + "-mj"; + FileFilter filter = new FileFilter() { + @Override + public boolean accept(File candidate) { + return candidate.getName().startsWith(prefix); + } + }; + for (File masterJournal : dir.listFiles(filter)) deleted |= masterJournal.delete(); + } + return deleted; + } catch (Exception e) { + e.printStackTrace(); + } finally { +// releaseReference(); + } + return false; + } + + /** + * Close. + */ + @Override + public synchronized void close() { +// releaseReference(); + } + + /** + * refCountIsZero 降到0时自动触发释放各种资源 + */ +// @Override + protected void onAllReferencesReleased() { + this.justRelease(); + } + + /** + * Just release. + */ + private void justRelease() { + if (this.mHelper != null) { + this.mHelper.getRdbStore().close(); +// mHelper.close(); + this.mHelper = null; + } + if (this.mTableManager != null) { + this.mTableManager.release(); + this.mTableManager = null; + } + } + + /** + * Keep mapping boolean. + * + * @param the type parameter + * @param the type parameter + * @param col1 the col 1 + * @param col2 the col 2 + * @return the boolean + * @throws IllegalAccessException the illegal access exception + * @throws InstantiationException the instantiation exception + */ + /* -------------------------------- 私有方法 -------------------------------- */ + private boolean keepMapping(Collection col1, + Collection col2) throws IllegalAccessException, InstantiationException { + Class claxx1 = col1.iterator().next().getClass(); + Class claxx2 = col2.iterator().next().getClass(); + EntityTable table1 = TableManager.getTable(claxx1); + EntityTable table2 = TableManager.getTable(claxx2); + if (table1.mappingList != null) for (MapProperty mp : table1.mappingList) { + Class itemClass; + Class fieldClass = mp.field.getType(); + // N对多关系 + if (mp.isToMany()) + if (ClassUtil.isCollection(fieldClass)) itemClass = FieldUtil.getGenericType(mp.field); + else if (fieldClass.isArray()) itemClass = FieldUtil.getComponentType(mp.field); + else + throw new RuntimeException( + "OneToMany and ManyToMany Relation, Must use collection or array object"); + else + itemClass = fieldClass; + if (itemClass == claxx2) { + ArrayList key1List = new ArrayList(); + HashMap map1 = new HashMap(); + // 构建第1个集合对象的key集合以及value映射 + for (Object o1 : col1) + if (o1 != null) { + Object key1 = FieldUtil.get(table1.key.field, o1); + if (key1 != null) { + key1List.add(key1.toString()); + map1.put(key1.toString(), o1); + } + } + ArrayList relationKeys = this.queryRelation(claxx1, claxx2, key1List); + if (!Checker.isEmpty(relationKeys)) { + HashMap map2 = new HashMap(); + // 构建第2个对象的value映射 + for (Object o2 : col2) + if (o2 != null) { + Object key2 = FieldUtil.get(table2.key.field, o2); + if (key2 != null) map2.put(key2.toString(), o2); + } + HashMap collMap = new HashMap(); + for (RelationKey m : relationKeys) { + Object obj1 = map1.get(m.key1); + Object obj2 = map2.get(m.key2); + if (obj1 != null && obj2 != null) if (mp.isToMany()) { + // N对多关系 + ArrayList col = collMap.get(obj1); + if (col == null) { + col = new ArrayList(); + collMap.put(obj1, col); + } + col.add(obj2); + } else FieldUtil.set(mp.field, obj1, obj2); + } + // N对多关系,查出来的数组 + if (!Checker.isEmpty(collMap)) for (Map.Entry entry : collMap.entrySet()) { + Object obj1 = entry.getKey(); + Collection tempColl = entry.getValue(); + if (ClassUtil.isCollection(itemClass)) { + Collection col = (Collection) FieldUtil.get(mp.field, obj1); + if (col == null) FieldUtil.set(mp.field, obj1, tempColl); + else col.addAll(tempColl); + } else if (ClassUtil.isArray(itemClass)) { + Object[] tempArray = (Object[]) ClassUtil.newArray(itemClass, tempColl.size()); + tempColl.toArray(tempArray); + Object[] array = (Object[]) FieldUtil.get(mp.field, obj1); + if (array == null) FieldUtil.set(mp.field, obj1, tempArray); + else { + Object[] newArray = DataUtil.concat(array, tempArray); + FieldUtil.set(mp.field, obj1, newArray); + } + } + } + return true; + } + } + } + return false; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/DataBase.java b/library/src/main/java/com/litesuits/orm/db/DataBase.java new file mode 100644 index 0000000..d2be584 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/DataBase.java @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2013 litesuits.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.litesuits.orm.db; + +import com.litesuits.orm.db.assit.QueryBuilder; +import com.litesuits.orm.db.assit.SQLStatement; +import com.litesuits.orm.db.assit.SQLiteHelper; +import com.litesuits.orm.db.assit.WhereBuilder; +import com.litesuits.orm.db.model.ColumnsValue; +import com.litesuits.orm.db.model.ConflictAlgorithm; +import com.litesuits.orm.db.model.RelationKey; +import ohos.data.rdb.RdbStore; +import ohos.data.resultset.ResultSetHook; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * data base operation interface + * + * @author mty + * @date 2013 -6-2上午2:37:56 + */ +public interface DataBase { + + /** + * Open or create database rdb store. + * + * @return true if create successfully. + */ + RdbStore openOrCreateDatabase(); + + /** + * save: insert or update a single entity + * + * @param entity the entity + * @return the number of rows affected by this SQL statement execution. + */ + long save(Object entity); + + /** + * save: insert or update a collection + * + * @param the type parameter + * @param collection the collection + * @return the number of affected rows + */ + int save(Collection collection); + + /** + * insert a single entity + * + * @param entity the entity + * @return the number of rows affected by this SQL statement execution. + */ + long insert(Object entity); + + + /** + * insert a single entity with conflict algorithm + * + * @param entity the entity + * @param conflictAlgorithm the conflict algorithm + * @return the number of rows affected by this SQL statement execution. + */ + long insert(Object entity, ConflictAlgorithm conflictAlgorithm); + + /** + * insert a collection + * + * @param the type parameter + * @param collection the collection + * @return the number of affected rows + */ + int insert(Collection collection); + + /** + * insert a collection with conflict algorithm + * + * @param the type parameter + * @param collection the collection + * @param conflictAlgorithm the conflict algorithm + * @return the number of affected rows + */ + int insert(Collection collection, ConflictAlgorithm conflictAlgorithm); + + /** + * update a single entity + * + * @param entity the entity + * @return number of affected rows + */ + int update(Object entity); + + /** + * update a single entity with conflict algorithm + * + * @param entity the entity + * @param conflictAlgorithm the conflict algorithm + * @return number of affected rows + */ + int update(Object entity, ConflictAlgorithm conflictAlgorithm); + + /** + * update a single entity with conflict algorithm, and only update columns in {@link ColumnsValue} + * if param {@link ColumnsValue} is null, update all columns. + * + * @param entity the entity + * @param cvs the cvs + * @param conflictAlgorithm the conflict algorithm + * @return the number of affected rows + */ + int update(Object entity, ColumnsValue cvs, ConflictAlgorithm conflictAlgorithm); + + /** + * update a collection + * + * @param the type parameter + * @param collection the collection + * @return the number of affected rows + */ + int update(Collection collection); + + /** + * update a collection with conflict algorithm + * + * @param the type parameter + * @param collection the collection + * @param conflictAlgorithm the conflict algorithm + * @return number of affected rows + */ + int update(Collection collection, ConflictAlgorithm conflictAlgorithm); + + /** + * update a collection with conflict algorithm, and only update columns in {@link ColumnsValue} + * if param {@link ColumnsValue} is null, update all columns. + * + * @param the type parameter + * @param collection the collection + * @param cvs the cvs + * @param conflictAlgorithm the conflict algorithm + * @return number of affected rows + */ + int update(Collection collection, ColumnsValue cvs, ConflictAlgorithm conflictAlgorithm); + + /** + * update model use custom where clause. + * + * @param builder the builder + * @param cvs the cvs + * @param conflictAlgorithm the conflict algorithm + * @return number of affected rows + */ + int update(WhereBuilder builder, ColumnsValue cvs, ConflictAlgorithm conflictAlgorithm); + + /** + * delete a single entity + * + * @param entity the entity + * @return the number of affected rows + */ + int delete(Object entity); + + /** + * delete all rows + * + * @param the type parameter + * @param claxx the claxx + * @return the number of affected rows + */ + int delete(Class claxx); + + /** + * delete all rows + * + * @param the type parameter + * @param claxx the claxx + * @return the number of affected rows + */ + int deleteAll(Class claxx); + + /** + * start must >=0 and smaller than end + *

delete from start to the end, [start,end]. + *

set end={@link Integer#MAX_VALUE} will delete all rows from the start + * + * @param the type parameter + * @param claxx the claxx + * @param start the start + * @param end the end + * @param orderAscColu the order asc colu + * @return the number of affected rows + */ + int delete(Class claxx, long start, long end, String orderAscColu); + + /** + * delete a collection + * + * @param the type parameter + * @param collection the collection + * @return the number of affected rows + */ + int delete(Collection collection); + + /** + * delete by custem where syntax + * + * @param the type parameter + * @param claxx the claxx + * @param where the where + * @return the number of affected rows + * @deprecated use {@link #delete(WhereBuilder)} instead. + */ + int delete(Class claxx, WhereBuilder where); + + /** + * delete by custem where syntax + * + * @param where the where + * @return the number of affected rows + */ + int delete(WhereBuilder where); + + /** + * query all data of this type + * + * @param the type parameter + * @param claxx the claxx + * @return the query result list + */ + ArrayList query(Class claxx); + + /** + * custom query + * + * @param the type parameter + * @param qb the qb + * @return the query result list + */ + ArrayList query(QueryBuilder qb); + + /** + * query entity by long id + * + * @param the type parameter + * @param id the id + * @param clazz the clazz + * @return the query result + */ + T queryById(long id, Class clazz); + + /** + * query entity by string id + * + * @param the type parameter + * @param id the id + * @param clazz the clazz + * @return the query result + */ + T queryById(String id, Class clazz); + + /** + * query count of table rows and return + * + * @param the type parameter + * @param claxx the claxx + * @return the count of query result + */ + long queryCount(Class claxx); + + /** + * query count of your sql query result rows and return + * + * @param qb the qb + * @return the count of query result + */ + long queryCount(QueryBuilder qb); + + /** + * build a sql statement with sql and args. + * + * @param sql the sql + * @param bindArgs the bind args + * @return the sql statement + */ + SQLStatement createSQLStatement(String sql, Object[] bindArgs); + + /** + * Execute this SQL statement, if it is not a SELECT / INSERT / DELETE / UPDATE, for example + * CREATE / DROP table, view, trigger, index etc. + * + * @param db the db + * @param statement the statement + * @return the boolean + */ + boolean execute(RdbStore db, SQLStatement statement); + + /** + * drop a table + * + * @param entity the entity + * @return true if droped successfully. + * @deprecated + */ + @Deprecated + boolean dropTable(Object entity); + + /** + * drop a table + * + * @param claxx the claxx + * @return true if droped successfully. + */ + boolean dropTable(Class claxx); + + /** + * drop a table + * + * @param tableName the table name + * @return true if droped successfully. + */ + boolean dropTable(String tableName); + + /** + * find and return relation between two diffirent collection. + * + * @param class1 the class 1 + * @param class2 the class 2 + * @param key1List the key 1 list + * @return the relation list of class1 and class2; + */ + ArrayList queryRelation(Class class1, Class class2, List key1List); + + /** + * auto entity relation mapping + * + * @param the type parameter + * @param the type parameter + * @param col1 the col 1 + * @param col2 the col 2 + * @return the boolean + */ + boolean mapping(Collection col1, Collection col2); + + /** + * get readable database + * + * @return the readable database + */ + RdbStore getReadableDatabase(); + + /** + * get writable database + * + * @return the writable database + */ + RdbStore getWritableDatabase(); + + /** + * get {@link TableManager} + * + * @return the table manager + */ + TableManager getTableManager(); + + /** + * get {@link SQLiteHelper} + * + * @return the sq lite helper + */ + SQLiteHelper getSQLiteHelper(); + + /** + * get {@link DataBaseConfig} + * + * @return the data base config + */ + DataBaseConfig getDataBaseConfig(); + + /** + * Open or create database rdb store. + * + * @param path the path + * @param factory the factory + * @return the rdb store + */ + RdbStore openOrCreateDatabase(String path, ResultSetHook factory); + + /** + * Delete database boolean. + * + * @return the boolean + */ + boolean deleteDatabase(); + + /** + * Delete database boolean. + * + * @param file the file + * @return true if delete successfully. + */ + boolean deleteDatabase(File file); + + /** + * 关闭数据库,清空缓存。 + */ + void close(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/DataBaseConfig.java b/library/src/main/java/com/litesuits/orm/db/DataBaseConfig.java new file mode 100644 index 0000000..2a7fd35 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/DataBaseConfig.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2013 litesuits.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.litesuits.orm.db; + +import com.litesuits.orm.db.assit.Checker; +import com.litesuits.orm.db.assit.SQLiteHelper.OnUpdateListener; +import ohos.app.Context; + +/** + * 数据操作配置 + * + * @author MaTianyu 2013-6-2下午4:36:16 + */ +public class DataBaseConfig { + /** + * The constant DEFAULT_DB_NAME. + */ + public static final String DEFAULT_DB_NAME = "liteorm.db"; + /** + * The constant DEFAULT_DB_VERSION. + */ + public static final int DEFAULT_DB_VERSION = 1; + + /** + * The Context. + */ + public Context context; + /** + * The Debugged. + */ + public boolean debugged = false; + /** + * The Db name. + */ + public String dbName = DEFAULT_DB_NAME; + /** + * The Db version. + */ + public int dbVersion = DEFAULT_DB_VERSION; + /** + * The On update listener. + */ + public OnUpdateListener onUpdateListener; + + /** + * Instantiates a new Data base config. + * + * @param context the context + */ + public DataBaseConfig(Context context) { + this(context, DEFAULT_DB_NAME); + } + + /** + * Instantiates a new Data base config. + * + * @param context the context + * @param dbName the db name + */ + public DataBaseConfig(Context context, String dbName) { + this(context, dbName, false, DEFAULT_DB_VERSION, null); + } + + /** + * Instantiates a new Data base config. + * + * @param context the context + * @param dbName the db name + * @param debugged the debugged + * @param dbVersion the db version + * @param onUpdateListener the on update listener + */ + private DataBaseConfig(Context context, String dbName, boolean debugged, + int dbVersion, OnUpdateListener onUpdateListener) { + this.context = context.getApplicationContext(); + if (!Checker.isEmpty(dbName)) this.dbName = dbName; + if (dbVersion > 1) this.dbVersion = dbVersion; + this.debugged = debugged; + this.onUpdateListener = onUpdateListener; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "DataBaseConfig [mContext=" + this.context + ", mDbName=" + this.dbName + ", mDbVersion=" + + this.dbVersion + ", mOnUpdateListener=" + this.onUpdateListener + "]"; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/TableManager.java b/library/src/main/java/com/litesuits/orm/db/TableManager.java new file mode 100644 index 0000000..4d445e2 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/TableManager.java @@ -0,0 +1,568 @@ +/* + * Copyright (C) 2013 litesuits.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.litesuits.orm.db; + + +import com.litesuits.orm.db.annotation.Column; +import com.litesuits.orm.db.annotation.Mapping; +import com.litesuits.orm.db.annotation.PrimaryKey; +import com.litesuits.orm.db.annotation.Table; +import com.litesuits.orm.db.assit.*; +import com.litesuits.orm.db.enums.AssignType; +import com.litesuits.orm.db.model.*; +import com.litesuits.orm.db.utils.DataUtil; +import com.litesuits.orm.db.utils.FieldUtil; +import com.litesuits.orm.log.OrmLog; +import ohos.data.rdb.RdbStore; +import ohos.data.resultset.ResultSet; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; + +/** + * 表管理 + * + * @author MaTianyu + * @date 2013 -6-16上午12:27:32 + */ +public final class TableManager { + /** + * The constant TAG. + */ + private static final String TAG = TableManager.class.getSimpleName(); + /** + * The constant ID. + */ + private static final String[] ID = new String[]{"id", "_id"}; + /** + * 这里放的是类的实体信息表(主键、属性、关系映射...) + * 全局单例 + * key : Class Name + * value: {@link EntityTable} + */ + private final static HashMap mEntityTableMap = new HashMap(); + /** + * 这里放的是数据库表信息(表名、字段、建表语句...) + * 每个数据库对应一个 + * key : Class Name + * value: {@link EntityTable} + */ + private final HashMap mSqlTableMap = new HashMap(); + /** + * 数据库表信息 + */ + private String dbName = ""; + + /** + * Instantiates a new Table manager. + * + * @param dbName the db name + * @param db the db + */ + public TableManager(String dbName, RdbStore db) { + this.dbName = dbName; + this.initSqlTable(db); + } + + /** + * 获取缓存实体表信息 + * + * @param name the name + * @return the entity table + */ + private static EntityTable getEntityTable(String name) { + return mEntityTableMap.get(name); + } + + /** + * 缓存的实体表信息 + * + * @param tableName the table name + * @param entity the entity + * @return 返回前一个和此Key相同的Value ,没有则返回null。 + */ + private static EntityTable putEntityTable(String tableName, EntityTable entity) { + return mEntityTableMap.put(tableName, entity); + } + + /** + * 根据实体生成表信息,一定需要PrimaryKey + * + * @param entity the entity + * @return the table + */ + public static EntityTable getTable(Object entity) { + return getTable(entity.getClass(), true); + } + + /** + * 根据类生成表信息,一定需要PrimaryKey + * + * @param claxx the claxx + * @return the table + */ + public static EntityTable getTable(Class claxx) { + return getTable(claxx, true); + } + + /** + * 获取实体表信息(Entity Table) + * 注意映射表存储在MAP中,key 为 class name, value 为 entity table。 + * + * @param claxx the claxx + * @param needPK the need pk + * @return {@link EntityTable} + */ + public static synchronized EntityTable getTable(Class claxx, boolean needPK) { + EntityTable table = getEntityTable(claxx.getName()); + //if(OrmLog.isPrint)OrmLog.i(TAG, "table : " + table + " , claxx: " + claxx); + if (table == null) { + table = new EntityTable(); + table.claxx = claxx; + table.name = getTableName(claxx); + table.pmap = new LinkedHashMap(); + List fields = FieldUtil.getAllDeclaredFields(claxx); + for (Field f : fields) { + if (FieldUtil.isInvalid(f)) continue; + + // 获取列名,每个属性都有,没有注解默认取属性名 + Column col = f.getAnnotation(Column.class); + String column = col != null ? col.value() : f.getName(); + Property p = new Property(column, f); + + + // 主键判断 + PrimaryKey key = f.getAnnotation(PrimaryKey.class); + if (key != null) { + // 主键不加入属性Map + table.key = new Primarykey(p, key.value()); + // 主键为系统分配,对类型有要求 + checkPrimaryKey(table.key); + } else { + //ORM handle + Mapping mapping = f.getAnnotation(Mapping.class); + if (mapping != null) table.addMapping(new MapProperty(p, mapping.value())); + else + table.pmap.put(p.column, p); + } + } + if (table.key == null) for (String col : table.pmap.keySet()) { + for (String id : ID) + if (id.equalsIgnoreCase(col)) { + Property p = table.pmap.get(col); + if (p.field.getType() == String.class) { + // 主键移除属性Map + table.pmap.remove(col); + table.key = new Primarykey(p, AssignType.BY_MYSELF); + break; + } else if (FieldUtil.isNumber(p.field.getType())) { + // 主键移除属性Map + table.pmap.remove(col); + table.key = new Primarykey(p, AssignType.AUTO_INCREMENT); + break; + } + + } + if (table.key != null) break; + } + if (needPK && table.key == null) throw new RuntimeException( + "你必须为[" + table.claxx.getSimpleName() + "]设置主键(you must set the primary key...)" + + "\n 提示:在对象的属性上加PrimaryKey注解来设置主键。"); + putEntityTable(claxx.getName(), table); + } + return table; + } + + /** + * Check primary key. + * + * @param key the key + */ + private static void checkPrimaryKey(Primarykey key) { + if (key.isAssignedBySystem()) { + if (!FieldUtil.isNumber(key.field.getType())) throw new RuntimeException( + AssignType.AUTO_INCREMENT + + " Auto increment primary key must be a number ...\n " + + "错误提示:自增主键必须设置为数字类型"); + } else if (key.isAssignedByMyself()) { + if (String.class != key.field.getType() && !FieldUtil.isNumber(key.field.getType())) + throw new RuntimeException( + AssignType.BY_MYSELF + + " Custom primary key must be string or number ...\n " + + "错误提示:自定义主键值必须为String或者Number类型"); + } else throw new RuntimeException( + " Primary key without Assign Type ...\n " + + "错误提示:主键无类型"); + } + + /** + * 根据类自动生成表名字 + * + * @param claxx the claxx + * @return the table name + */ + public static String getTableName(Class claxx) { + Table anno = claxx.getAnnotation(Table.class); + if (anno != null) return anno.value(); + else return claxx.getName().replaceAll("\\.", "_"); + } + + /** + * Gets map table name. + * + * @param c1 the c 1 + * @param c2 the c 2 + * @return the map table name + */ + public static String getMapTableName(Class c1, Class c2) { + return getMapTableName(getTableName(c1), getTableName(c2)); + } + + /** + * Gets map table name. + * + * @param t1 the t 1 + * @param t2 the t 2 + * @return the map table name + */ + public static String getMapTableName(EntityTable t1, EntityTable t2) { + return getMapTableName(t1.name, t2.name); + } + + /** + * Gets map table name. + * + * @param tableName1 the table name 1 + * @param tableName2 the table name 2 + * @return the map table name + */ + private static String getMapTableName(String tableName1, String tableName2) { + if (tableName1.compareTo(tableName2) < 0) return tableName1 + "_" + tableName2; + else + return tableName2 + "_" + tableName1; + } + + /** + * 插入新列 + * + * @param db the db + * @param tableName the table name + * @param columns the columns + * @return the int + */ + private static int insertNewColunms(RdbStore db, String tableName, List columns) { + Integer size = null; + if (!Checker.isEmpty(columns)) size = Transaction.execute(db, new Transaction.Worker() { + @Override + public Integer doTransaction(RdbStore db) { + for (String c : columns) { + SQLStatement stmt = SQLBuilder.buildAddColumnSql(tableName, c); + stmt.execute(db); + } + return columns.size(); + } + }); + return size == null ? 0 : size; + } + + /** + * 建立新表 + * + * @param db the db + * @param table the table + * @return the boolean + */ + private static boolean createTable(RdbStore db, EntityTable table) { + return SQLBuilder.buildCreateTable(table).execute(db); + } + + /** + * 数据库分析 + * 通过读数据库得到一张表的全部列名 + * + * @param db the db + * @param tableName the table name + * @return the all columns from sq lite + */ + private static ArrayList getAllColumnsFromSQLite(RdbStore db, String tableName) { + EntityTable table = getTable(SQLiteColumn.class, false); + ArrayList list = new ArrayList(); + + SQLStatement st = SQLBuilder.buildColumnsObtainAll(tableName); + Querier.doQuery(db, st, new Querier.CursorParser() { + @Override + public void parseEachCursor(RdbStore db, ResultSet c) throws Exception { + SQLiteColumn col = new SQLiteColumn(); + DataUtil.injectDataToObject(c, col, table); + list.add(col.name); + } + }); + + return list; + } + + /** + * 语义分析 + * 依据表的sql“CREATE TABLE”建表语句得到一张表的全部列名。 + * + * @param sql the sql + * @return the array list + */ + private static ArrayList transformSqlToColumns(String sql) { + if (sql != null) { + int start = sql.indexOf("("); + int end = sql.lastIndexOf(")"); + if (start > 0 && end > 0) { + sql = sql.substring(start + 1, end); + String[] cloumns = sql.split(","); + ArrayList colList = new ArrayList(); + for (String col : cloumns) { + col = col.trim(); + int endS = col.indexOf(" "); + if (endS > 0) col = col.substring(0, endS); + colList.add(col); + } + OrmLog.e(TAG, "降级:语义分析表结构(" + colList + " , Origin SQL is: " + sql); + return colList; + } + } + return null; + } + + /** + * Init sql table. + * + * @param db the db + */ + private void initSqlTable(RdbStore db) { + // 关键点:初始化全部数据库表 + this.initAllTablesFromSQLite(db); + } + + /* —————————————————————————— 静态私有方法 ———————————————————————— */ + + /** + * Clear sql table. + */ + private void clearSqlTable() { + synchronized (this.mSqlTableMap) { + this.mSqlTableMap.clear(); + } + } + + /** + * 清空数据 + */ + public void release() { + this.clearSqlTable(); + mEntityTableMap.clear(); + } + + /** + * 检测表是否建立,没有则建一张新表。 + * + * @param db the db + * @param entity the entity + * @return the entity table + */ + public EntityTable checkOrCreateTable(RdbStore db, Object entity) { + return this.checkOrCreateTable(db, entity.getClass()); + } + /* —————————————————————————— 静态公共方法 ———————————————————————— */ + + /** + * 检测[数据库表]是否建立,没有则建一张新表。 + * + * @param db the db + * @param claxx the claxx + * @return the entity table + */ + private synchronized EntityTable checkOrCreateTable(RdbStore db, Class claxx) { + // 关键点1:获取[实体表] + EntityTable table = getTable(claxx); + // 关键点2: 判断[数据库表]是否存在,是否需要新加列。 + // 关键点3:新建[数据库表]并加入表队列 + if (!this.checkExistAndColumns(db, table)) + if (TableManager.createTable(db, table)) this.putNewSqlTableIntoMap(table); + return table; + } + + /** + * 检测[映射表]是否建立,没有则建一张新表。 + * + * @param db the db + * @param tableName the table name + * @param column1 the column 1 + * @param column2 the column 2 + */ + public synchronized void checkOrCreateMappingTable(RdbStore db, String tableName, + String column1, String column2) { + // 关键点1:获取[实体表] + EntityTable table = this.getMappingTable(tableName, column1, column2); + // 关键点2: 判断[数据库表]是否存在,是否需要新加列。 + // 关键点3:新建[数据库表]并加入表队列 + if (!this.checkExistAndColumns(db, table)) + if (TableManager.createTable(db, table)) this.putNewSqlTableIntoMap(table); + } + + /** + * 仅仅检测[数据库表]是否建立 + * + * @param tableName1 the table name 1 + * @param tableName2 the table name 2 + * @return the boolean + */ + public boolean isSQLMapTableCreated(String tableName1, String tableName2) { + return this.mSqlTableMap.get(getMapTableName(tableName1, tableName2)) != null; + } + + /** + * 仅仅检测[数据库表]是否建立 + * + * @param tableName the table name + * @return the boolean + */ + public boolean isSQLTableCreated(String tableName) { + return this.mSqlTableMap.get(tableName) != null; + } + + /** + * 检查表是否存在,存在的话检查是否需要改动,添加列字段。 + * 注:sqlite仅仅支持表改名、表添加列两种alter方式。表中修改、刪除列是不被直接支持的。 + * 不能新加主键:The column may not have a PRIMARY KEY or UNIQUE constraint. + *

http://www.sqlite.org/lang_altertable.html + * + * @param db the db + * @param entityTable the entity table + * @return the boolean + */ + private boolean checkExistAndColumns(RdbStore db, EntityTable entityTable) { + SQLiteTable sqlTable = this.mSqlTableMap.get(entityTable.name); + if (sqlTable != null) { + if (OrmLog.isPrint) OrmLog.d(TAG, "Table [" + entityTable.name + "] Exist"); + if (!sqlTable.isTableChecked) { + // 表仅进行一次检查,检验是否有新字段加入。 + sqlTable.isTableChecked = true; + if (OrmLog.isPrint) OrmLog.i(TAG, "Table [" + entityTable.name + "] check column now."); + if (entityTable.key != null) if (sqlTable.columns.get(entityTable.key.column) == null) { + SQLStatement stmt = SQLBuilder.buildDropTable(sqlTable.name); + stmt.execute(db); + if (OrmLog.isPrint) OrmLog.i(TAG, "Table [" + entityTable.name + "] Primary Key has changed, " + + "so drop and recreate it later."); + return false; + } + if (entityTable.pmap != null) { + ArrayList newColumns = new ArrayList(); + for (String col : entityTable.pmap.keySet()) + if (sqlTable.columns.get(col) == null) newColumns.add(col); + if (!Checker.isEmpty(newColumns)) { + for (String col : newColumns) sqlTable.columns.put(col, 1); + int sum = TableManager.insertNewColunms(db, entityTable.name, newColumns); + if (OrmLog.isPrint) if (sum > 0) OrmLog.i(TAG, + "Table [" + entityTable.name + "] add " + sum + " new column : " + newColumns); + else + OrmLog.e(TAG, + "Table [" + entityTable.name + "] add " + sum + " new column error : " + + newColumns); + } + } + } + return true; + } + if (OrmLog.isPrint) OrmLog.d(TAG, "Table [" + entityTable.name + "] Not Exist"); + return false; + } + + /** + * 将Sql Table放入存储集合 + * + * @param table the table + */ + private void putNewSqlTableIntoMap(EntityTable table) { + if (OrmLog.isPrint) OrmLog.i(TAG, "Table [" + table.name + "] Create Success"); + SQLiteTable sqlTable = new SQLiteTable(); + sqlTable.name = table.name; + sqlTable.columns = new HashMap(); + if (table.key != null) sqlTable.columns.put(table.key.column, 1); + if (table.pmap != null) for (String col : table.pmap.keySet()) sqlTable.columns.put(col, 1); + // 第一次建表,不用检查 + sqlTable.isTableChecked = true; + this.mSqlTableMap.put(sqlTable.name, sqlTable); + } + + /** + * 初始化全部表及其列名,初始化失败,则无法进行下去。 + * + * @param db the db + */ + private void initAllTablesFromSQLite(RdbStore db) { + synchronized (this.mSqlTableMap) { + if (Checker.isEmpty(this.mSqlTableMap)) { + if (OrmLog.isPrint) OrmLog.i(TAG, "Initialize SQL table start--------------------->"); + SQLStatement st = SQLBuilder.buildTableObtainAll(); + EntityTable table = getTable(SQLiteTable.class, false); + Querier.doQuery(db, st, new Querier.CursorParser() { + @Override + public void parseEachCursor(RdbStore db, ResultSet c) throws Exception { + SQLiteTable sqlTable = new SQLiteTable(); + DataUtil.injectDataToObject(c, sqlTable, table); + ArrayList colS = TableManager.getAllColumnsFromSQLite(db, sqlTable.name); + if (Checker.isEmpty(colS)) { + // 如果读数据库失败了,那么解析建表语句 + OrmLog.e(TableManager.TAG, "读数据库失败了,开始解析建表语句"); + colS = TableManager.transformSqlToColumns(sqlTable.sql); + } + sqlTable.columns = new HashMap(); + for (String col : colS) sqlTable.columns.put(col, 1); + if (OrmLog.isPrint) { + OrmLog.i(TableManager.TAG, "Find One SQL Table: " + sqlTable); + OrmLog.i(TableManager.TAG, "Table Column: " + colS); + } + TableManager.this.mSqlTableMap.put(sqlTable.name, sqlTable); + } + }); + if (OrmLog.isPrint) + OrmLog.i(TAG, "Initialize SQL table end ---------------------> " + this.mSqlTableMap.size()); + } + } + } + + /** + * 获取映射表信息(Entity Table) + * 注意映射表存储在MAP中,key 为 database name + table name, value 为 entity table。 + * + * @param tableName the table name + * @param column1 the column 1 + * @param column2 the column 2 + * @return {@link EntityTable} + */ + private EntityTable getMappingTable(String tableName, String column1, String column2) { + EntityTable table = getEntityTable(this.dbName + tableName); + if (table == null) { + table = new EntityTable(); + table.name = tableName; + table.pmap = new LinkedHashMap(); + table.pmap.put(column1, null); + table.pmap.put(column2, null); + TableManager.putEntityTable(this.dbName + tableName, table); + } + return table; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/Check.java b/library/src/main/java/com/litesuits/orm/db/annotation/Check.java new file mode 100644 index 0000000..c5c5ac8 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/Check.java @@ -0,0 +1,20 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 校验 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Check { + /** + * Value string. + * + * @return the string + */ + String value(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/Collate.java b/library/src/main/java/com/litesuits/orm/db/annotation/Collate.java new file mode 100644 index 0000000..ac58e91 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/Collate.java @@ -0,0 +1,25 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * collate可应用于数据库定义或列定义以定义排序规则,或应用于字符串表达式以应用排序规则投影。 + * When SQLite compares two strings, it uses a collating sequence or collating function (two words for the same thing) to determine which string is greater or if the two strings are equal. SQLite has three built-in collating functions: BINARY, NOCASE, and RTRIM. + *

+ * BINARY - Compares string data using memcmp(), regardless of text encoding. + * NOCASE - The same as binary, except the 26 upper case characters of ASCII are folded to their lower case equivalents before the comparison is performed. Note that only ASCII characters are case folded. SQLite does not attempt to do full UTF case folding due to the size of the tables required. + * RTRIM - The same as binary, except that trailing space characters are ignored. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Collate { + /** + * Value string. + * + * @return the string + */ + String value(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/Column.java b/library/src/main/java/com/litesuits/orm/db/annotation/Column.java new file mode 100644 index 0000000..ee96658 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/Column.java @@ -0,0 +1,21 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Column Name.. + * 为属性命名“列名”,如果没有设置,将以属性名字命名它在表中的“列名”; + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Column { + /** + * Table Name + * + * @return the string + */ + String value(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/Conflict.java b/library/src/main/java/com/litesuits/orm/db/annotation/Conflict.java new file mode 100644 index 0000000..ca793fb --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/Conflict.java @@ -0,0 +1,19 @@ +package com.litesuits.orm.db.annotation; + +import com.litesuits.orm.db.enums.Strategy; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * 冲突策略 + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface Conflict { + /** + * Value strategy. + * + * @return the strategy + */ + Strategy value(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/Default.java b/library/src/main/java/com/litesuits/orm/db/annotation/Default.java new file mode 100644 index 0000000..e310feb --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/Default.java @@ -0,0 +1,20 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 设置默认值,如果是其他基础类型,可用String.valueOf(ooxx) + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Default { + /** + * Value string. + * + * @return the string + */ + String value(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/Ignore.java b/library/src/main/java/com/litesuits/orm/db/annotation/Ignore.java new file mode 100644 index 0000000..c649f0c --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/Ignore.java @@ -0,0 +1,14 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 忽略字段,如果属性被设置忽略,那么将在增、改的时候忽略它。 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Ignore { +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/MapCollection.java b/library/src/main/java/com/litesuits/orm/db/annotation/MapCollection.java new file mode 100644 index 0000000..eac0921 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/MapCollection.java @@ -0,0 +1,20 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The interface Map collection. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface MapCollection { + /** + * Value class. + * + * @return the class + */ + Class value(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/Mapping.java b/library/src/main/java/com/litesuits/orm/db/annotation/Mapping.java new file mode 100644 index 0000000..2e96b7c --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/Mapping.java @@ -0,0 +1,22 @@ +package com.litesuits.orm.db.annotation; + +import com.litesuits.orm.db.enums.Relation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 关系映射 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Mapping { + /** + * Value relation. + * + * @return the relation + */ + Relation value(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/NotNull.java b/library/src/main/java/com/litesuits/orm/db/annotation/NotNull.java new file mode 100644 index 0000000..c980dbd --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/NotNull.java @@ -0,0 +1,14 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 非空约束 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface NotNull { +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/PrimaryKey.java b/library/src/main/java/com/litesuits/orm/db/annotation/PrimaryKey.java new file mode 100644 index 0000000..92c14ac --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/PrimaryKey.java @@ -0,0 +1,25 @@ +package com.litesuits.orm.db.annotation; + +import com.litesuits.orm.db.enums.AssignType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 主键,这是一个模型里必须有的,是对象的唯一标识。 + * 没有主键将会报错,一个表只有一个主关键字,它有两种类型: + * 1.主键值自定义,适用于已有唯一ID的对象。 + * 2.主键值系统定义,适用于没有唯一ID的对象,将使用递增的数字作为值賦予它。 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface PrimaryKey { + /** + * Value assign type. + * + * @return the assign type + */ + AssignType value(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/Table.java b/library/src/main/java/com/litesuits/orm/db/annotation/Table.java new file mode 100644 index 0000000..f24ab64 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/Table.java @@ -0,0 +1,20 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 为对象命名“表名”,如果没有设置,将以对象类名命名表。 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Table { + /** + * Table Name + * + * @return the string + */ + String value(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/Temporary.java b/library/src/main/java/com/litesuits/orm/db/annotation/Temporary.java new file mode 100644 index 0000000..5949ec6 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/Temporary.java @@ -0,0 +1,14 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 临时性 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Temporary { +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/Unique.java b/library/src/main/java/com/litesuits/orm/db/annotation/Unique.java new file mode 100644 index 0000000..572fa1f --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/Unique.java @@ -0,0 +1,14 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 唯一性约束 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Unique { +} diff --git a/library/src/main/java/com/litesuits/orm/db/annotation/UniqueCombine.java b/library/src/main/java/com/litesuits/orm/db/annotation/UniqueCombine.java new file mode 100644 index 0000000..5c4e1f2 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/annotation/UniqueCombine.java @@ -0,0 +1,20 @@ +package com.litesuits.orm.db.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 联合唯一性约束 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface UniqueCombine { + /** + * 使用相同int值将归为一组[联合唯一]属性 + * + * @return the int + */ + int value(); +} diff --git a/library/src/main/java/com/litesuits/orm/db/assit/Checker.java b/library/src/main/java/com/litesuits/orm/db/assit/Checker.java new file mode 100644 index 0000000..0f304db --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/assit/Checker.java @@ -0,0 +1,63 @@ +package com.litesuits.orm.db.assit; + +import java.util.Collection; +import java.util.Map; + +/** + * 辅助判断 + * + * @author mty + * @date 2013 -6-10下午5:50:57 + */ +public class Checker { + + /** + * Is empty boolean. + * + * @param str the str + * @return the boolean + */ + public static boolean isEmpty(CharSequence str) { + return isNull(str) || str.length() == 0; + } + + /** + * Is empty boolean. + * + * @param os the os + * @return the boolean + */ + public static boolean isEmpty(Object[] os) { + return isNull(os) || os.length == 0; + } + + /** + * Is empty boolean. + * + * @param l the l + * @return the boolean + */ + public static boolean isEmpty(Collection l) { + return isNull(l) || l.isEmpty(); + } + + /** + * Is empty boolean. + * + * @param m the m + * @return the boolean + */ + public static boolean isEmpty(Map m) { + return isNull(m) || m.isEmpty(); + } + + /** + * Is null boolean. + * + * @param o the o + * @return the boolean + */ + private static boolean isNull(Object o) { + return o == null; + } +} diff --git a/library/src/main/java/com/litesuits/orm/db/assit/CollSpliter.java b/library/src/main/java/com/litesuits/orm/db/assit/CollSpliter.java new file mode 100644 index 0000000..7dbe697 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/assit/CollSpliter.java @@ -0,0 +1,64 @@ +package com.litesuits.orm.db.assit; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * 辅助事务 + * + * @author mty + * @date 2013 -6-15下午11:09:15 + */ +public class CollSpliter { + + /** + * 将 collection 拆分成 N 组ArrayList,每组 perSize 个元素,最后一组元素数量未知。 + *

+ * {@link Spliter#oneSplit(ArrayList)}将被调用N次,N >= 1. + * + * @param the type parameter + * @param collection the collection + * @param perSize the per size + * @param spliter the spliter + * @return sum of {@link Spliter#oneSplit(ArrayList)} + * @throws Exception the exception + */ + public static int split(Collection collection, int perSize, Spliter spliter) throws Exception { + ArrayList list = new ArrayList(); + int count = 0; + if (collection.size() <= perSize) { + list.addAll(collection); + count += spliter.oneSplit(list); + } else { + int i = 0, j = 1; + for (T data : collection) { + if (i < j * perSize) list.add(data); + else { + count += spliter.oneSplit(list); + j++; + list.clear(); + list.add(data); + } + i++; + } + if (list.size() > 0) count += spliter.oneSplit(list); + } + return count; + } + + /** + * The interface Spliter. + * + * @param the type parameter + */ + public interface Spliter { + /** + * One split int. + * + * @param list the list + * @return the int + * @throws Exception the exception + */ + int oneSplit(ArrayList list) throws Exception; + } +} \ No newline at end of file diff --git a/library/src/main/java/com/litesuits/orm/db/assit/Querier.java b/library/src/main/java/com/litesuits/orm/db/assit/Querier.java new file mode 100644 index 0000000..92b0cbb --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/assit/Querier.java @@ -0,0 +1,103 @@ +package com.litesuits.orm.db.assit; + +import com.litesuits.orm.log.OrmLog; +import ohos.data.rdb.RdbException; +import ohos.data.rdb.RdbStore; +import ohos.data.resultset.ResultSet; + +/** + * 辅助查询 + * + * @author MaTianyu + * @date 2013 -6-15下午11:11:02 + */ +public class Querier { + /** + * The constant TAG. + */ + private static final String TAG = Querier.class.getSimpleName(); + + /** + * 因为每个查询都不一样,但又有相同的结构,这种形式维持代码的统一性,也可以个性化解析。 + * + * @param the type parameter + * @param db the db + * @param st the st + * @param parser the parser + * @return the t + */ + public static T doQuery(RdbStore db, SQLStatement st, CursorParser parser) { + if (OrmLog.isPrint) OrmLog.d(TAG, "----> Query Start: " + st.toString()); +// Cursor cursor = db.rawQuery(st.sql, (String[]) st.bindArgs); + ResultSet cursor = null; + try { + cursor = db.querySql(st.sql, (String[]) st.bindArgs); + } catch (RdbException e) { + e.printStackTrace(); + } + if (cursor != null) { + parser.process(db, cursor); + if (OrmLog.isPrint) OrmLog.d(TAG, "<---- Query End , cursor size : " + cursor.getRowCount()); + } else if (OrmLog.isPrint) OrmLog.e(TAG, "<---- Query End : cursor is null"); + return parser.returnResult(); + } + + /** + * A simple cursor parser + * + * @param the type parameter + * @author MaTianyu + */ + public static abstract class CursorParser { + /** + * The Parse. + */ + private boolean parse = true; + + /** + * Process. + * + * @param db the db + * @param cursor the cursor + */ + final void process(RdbStore db, ResultSet cursor) { + try { + + boolean gotoSuccess = cursor.goToFirstRow();//.moveToFirst(); + while (this.parse && gotoSuccess && !cursor.isEnded()) { + this.parseEachCursor(db, cursor); + gotoSuccess = cursor.goToNextRow();//.moveToNext(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (cursor != null) cursor.close(); + } + } + + /** + * Stop parse. + */ + protected final void stopParse() { + this.parse = false; + } + + /** + * Return result t. + * + * @return the t + */ + public T returnResult() { + return null; + } + + /** + * Parse each cursor. + * + * @param db the db + * @param c the c + * @throws Exception the exception + */ + public abstract void parseEachCursor(RdbStore db, ResultSet c) throws Exception; + } +} diff --git a/library/src/main/java/com/litesuits/orm/db/assit/QueryBuilder.java b/library/src/main/java/com/litesuits/orm/db/assit/QueryBuilder.java new file mode 100644 index 0000000..f48b3fd --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/assit/QueryBuilder.java @@ -0,0 +1,549 @@ +package com.litesuits.orm.db.assit; + +import com.litesuits.orm.db.TableManager; + +import java.util.regex.Pattern; + +/** + * 查询构建 + * + * @param the type parameter + * @author mty + * @date 2013 -6-14下午3:47:16 + */ +public class QueryBuilder { + /** + * The constant AND. + */ + public static final String AND = " AND "; + /** + * The constant OR. + */ + public static final String OR = " OR "; + /** + * The constant EQUAL_HOLDER. + */ + public static final String EQUAL_HOLDER = "=?"; + /** + * The constant ASC. + */ + private static final String ASC = " ASC"; + /** + * The constant DESC. + */ + private static final String DESC = " DESC"; + /** + * The constant GROUP_BY. + */ + private static final String GROUP_BY = " GROUP BY "; + /** + * The constant HAVING. + */ + private static final String HAVING = " HAVING "; + /** + * The constant ORDER_BY. + */ + private static final String ORDER_BY = " ORDER BY "; + /** + * The constant LIMIT. + */ + private static final String LIMIT = " LIMIT "; + /** + * The constant SELECT_COUNT. + */ + private static final String SELECT_COUNT = "SELECT COUNT(*) FROM "; + /** + * The constant SELECT. + */ + private static final String SELECT = "SELECT "; + /** + * The constant DISTINCT. + */ + private static final String DISTINCT = " DISTINCT "; + /** + * The constant ASTERISK. + */ + private static final String ASTERISK = "*"; + /** + * The constant FROM. + */ + private static final String FROM = " FROM "; + /** + * The constant COMMA_HOLDER. + */ + private static final String COMMA_HOLDER = ",?"; + /** + * The constant COMMA. + */ + private static final String COMMA = ","; + /** + * The constant limitPattern. + */ + private static final Pattern limitPattern = Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?"); + /** + * The Clazz. + */ + private final Class clazz; + /** + * The Columns. + */ + protected String[] columns; + /** + * The Where builder. + */ + protected WhereBuilder whereBuilder; + /** + * The Clazz mapping. + */ + private Class clazzMapping; + /** + * The Distinct. + */ + private boolean distinct; + /** + * The Group. + */ + private String group; + /** + * The Having. + */ + private String having; + /** + * The Order. + */ + private String order; + /** + * The Limit. + */ + private String limit; + + /** + * Instantiates a new Query builder. + * + * @param claxx the claxx + */ + public QueryBuilder(Class claxx) { + this.clazz = claxx; + this.whereBuilder = new WhereBuilder(claxx); + } + + /** + * Create query builder. + * + * @param the type parameter + * @param claxx the claxx + * @return the query builder + */ + public static QueryBuilder create(Class claxx) { + return new QueryBuilder(claxx); + } + + /** + * 添加条件 + * + * @param s the s + * @param name the name + * @param clause the clause + */ + private static void appendClause(StringBuilder s, String name, String clause) { + if (!Checker.isEmpty(clause)) { + s.append(name); + s.append(clause); + } + } + + /** + * 添加列,逗号分隔 + * + * @param s the s + * @param columns the columns + */ + private static void appendColumns(StringBuilder s, String[] columns) { + int n = columns.length; + + for (int i = 0; i < n; i++) { + String column = columns[i]; + + if (column != null) { + if (i > 0) s.append(","); + s.append(column); + } + } + s.append(" "); + } + + /** + * Build where in string. + * + * @param column the column + * @param num the num + * @return the string + */ + private static String buildWhereIn(String column, int num) { + StringBuilder sb = new StringBuilder(column).append(" IN (?"); + for (int i = 1; i < num; i++) sb.append(COMMA_HOLDER); + return sb.append(")").toString(); + } + + /** + * Gets query class. + * + * @return the query class + */ + public Class getQueryClass() { + return this.clazz; + } + + /** + * Where query builder. + * + * @param builder the builder + * @return the query builder + */ + public QueryBuilder where(WhereBuilder builder) { + this.whereBuilder = builder; + return this; + } + + /** + * Gets builder. + * + * @return the builder + */ + public WhereBuilder getwhereBuilder() { + return this.whereBuilder; + } + + /** + * Where query builder. + * + * @param where "id = ?"; "id in(?,?,?)"; "id LIKE %?" + * @param whereArgs new String[]{"",""}; new Integer[]{1,2} + * @return the query builder + */ + public QueryBuilder where(String where, Object... whereArgs) { + this.whereBuilder.where(where, whereArgs); + return this; + } + + /** + * Where append query builder. + * + * @param where "id = ?"; "id in(?,?,?)"; "id LIKE %?" + * @param whereArgs new String[]{"",""}; new Integer[]{1,2} + * @return the query builder + */ + public QueryBuilder whereAppend(String where, Object... whereArgs) { + this.whereBuilder.append(null, where, whereArgs); + return this; + } + + /** + * build as " AND " + where + * + * @param where "id = ?"; "id in(?,?,?)"; "id LIKE %?" + * @param whereArgs new String[]{"",""}; new Integer[]{1,2} + * @return the query builder + */ + public QueryBuilder whereAnd(String where, Object... whereArgs) { + this.whereBuilder.and(where, whereArgs); + return this; + } + + /** + * build as " OR " + where + * + * @param where "id = ?"; "id in(?,?,?)"; "id LIKE %?" + * @param whereArgs new String[]{"",""}; new Integer[]{1,2} + * @return the query builder + */ + public QueryBuilder whereOr(String where, Object... whereArgs) { + this.whereBuilder.or(where, whereArgs); + return this; + } + + /** + * build as where+" AND " + * + * @return the query builder + */ + public QueryBuilder whereAppendAnd() { + this.whereBuilder.and(); + return this; + } + + /** + * build as where+" OR " + * + * @return the query builder + */ + public QueryBuilder whereAppendOr() { + this.whereBuilder.or(); + return this; + } + + /** + * build as where+" NOT " + * + * @return the query builder + */ + public QueryBuilder whereAppendNot() { + this.whereBuilder.not(); + return this; + } + + /** + * build as where+" column != ? " + * + * @param column the column + * @param value the value + * @return the query builder + */ + public QueryBuilder whereNoEquals(String column, Object value) { + this.whereBuilder.noEquals(column, value); + return this; + } + + /** + * build as where+" column > ? " + * + * @param column the column + * @param value the value + * @return the query builder + */ + public QueryBuilder whereGreaterThan(String column, Object value) { + this.whereBuilder.greaterThan(column, value); + return this; + } + + /** + * build as where+" column < ? " + * + * @param column the column + * @param value the value + * @return the query builder + */ + public QueryBuilder whereLessThan(String column, Object value) { + this.whereBuilder.lessThan(column, value); + return this; + } + + /** + * build as where+" column = ? " + * + * @param column the column + * @param value the value + * @return the query builder + */ + public QueryBuilder whereEquals(String column, Object value) { + this.whereBuilder.equals(column, value); + return this; + } + + /** + * build as where+" column IN(?, ?, ?...)" + * + * @param column the column + * @param values the values + * @return the query builder + */ + public QueryBuilder whereIn(String column, Object... values) { + this.whereBuilder.in(column, values); + return this; + } + + /** + * 需要返回的列,不填写默认全部,即select * 。 + * + * @param columns 列名,注意不是对象的属性名。 + * @return the query builder + */ + public QueryBuilder columns(String[] columns) { + this.columns = columns; + return this; + } + + /** + * 累积需要返回的列,不填写默认全部,即select * 。 + * + * @param columns 列名,注意不是对象的属性名。 + * @return the query builder + */ + public QueryBuilder appendColumns(String[] columns) { + if (this.columns != null) { + String[] newCols = new String[this.columns.length + columns.length]; + System.arraycopy(this.columns, 0, newCols, 0, this.columns.length); + System.arraycopy(columns, 0, newCols, this.columns.length, columns.length); + this.columns = newCols; + } else this.columns = columns; + return this; + } + + /** + * 唯一性保证 + * + * @param distinct the distinct + * @return the query builder + */ + public QueryBuilder distinct(boolean distinct) { + this.distinct = distinct; + return this; + } + + /** + * GROUP BY 语句用于结合合计函数,根据一个或多个列对结果集进行分组。 + * + * @param group the group + * @return the query builder + */ + public QueryBuilder groupBy(String group) { + this.group = group; + return this; + } + + /** + * 在 SQL 中增加 HAVING 子句原因是,WHERE 关键字无法与合计函数一起使用。 + * + * @param having the having + * @return the query builder + */ + public QueryBuilder having(String having) { + this.having = having; + return this; + } + + /** + * Order by query builder. + * + * @param order the order + * @return the query builder + */ + public QueryBuilder orderBy(String order) { + this.order = order; + return this; + } + + /** + * Append order asc by query builder. + * + * @param column the column + * @return the query builder + */ + public QueryBuilder appendOrderAscBy(String column) { + if (this.order == null) this.order = column + ASC; + else this.order += ", " + column + ASC; + return this; + } + + /** + * Append order desc by query builder. + * + * @param column the column + * @return the query builder + */ + public QueryBuilder appendOrderDescBy(String column) { + if (this.order == null) this.order = column + DESC; + else this.order += ", " + column + DESC; + return this; + } + + /** + * Limit query builder. + * + * @param limit the limit + * @return the query builder + */ + public QueryBuilder limit(String limit) { + this.limit = limit; + return this; + } + + /** + * Limit query builder. + * + * @param start the start + * @param length the length + * @return the query builder + */ + public QueryBuilder limit(int start, int length) { + this.limit = start + COMMA + length; + return this; + } + + /** + * Query mapping info query builder. + * + * @param clazzMapping the clazz mapping + * @return the query builder + */ + QueryBuilder queryMappingInfo(Class clazzMapping) { + this.clazzMapping = clazzMapping; + return this; + } + + /** + * 构建查询语句 + * + * @return the sql statement + */ + public SQLStatement createStatement() { + if (this.clazz == null) + throw new IllegalArgumentException("U Must Set A Query Entity Class By queryWho(Class) or " + + "QueryBuilder(Class)"); + if (Checker.isEmpty(this.group) && !Checker.isEmpty(this.having)) throw new IllegalArgumentException( + "HAVING仅允许在有GroupBy的时候使用(HAVING clauses are only permitted when using a groupBy clause)"); + if (!Checker.isEmpty(this.limit) && !limitPattern.matcher(this.limit).matches()) + throw new IllegalArgumentException( + "invalid LIMIT clauses:" + this.limit); + + StringBuilder query = new StringBuilder(120); + + query.append(SELECT); + if (this.distinct) query.append(DISTINCT); + if (!Checker.isEmpty(this.columns)) appendColumns(query, this.columns); + else query.append(ASTERISK); + query.append(FROM).append(this.getTableName()); + + query.append(this.whereBuilder.createWhereString()); + + appendClause(query, GROUP_BY, this.group); + appendClause(query, HAVING, this.having); + appendClause(query, ORDER_BY, this.order); + appendClause(query, LIMIT, this.limit); + + SQLStatement stmt = new SQLStatement(); + stmt.sql = query.toString(); + stmt.bindArgs = this.whereBuilder.transToStringArray(); + return stmt; + } + + /** + * Build a statement that returns a 1 by 1 table with a numeric value. + * SELECT COUNT(*) FROM table; + * + * @return the sql statement + */ + public SQLStatement createStatementForCount() { + StringBuilder query = new StringBuilder(120); + query.append(SELECT_COUNT).append(this.getTableName()); + SQLStatement stmt = new SQLStatement(); + if (this.whereBuilder != null) { + query.append(this.whereBuilder.createWhereString()); + stmt.bindArgs = this.whereBuilder.transToStringArray(); + } + stmt.sql = query.toString(); + return stmt; + } + + /** + * Gets table name. + * + * @return the table name + */ + public String getTableName() { + if (this.clazzMapping == null) return TableManager.getTableName(this.clazz); + else + return TableManager.getMapTableName(this.clazz, this.clazzMapping); + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/assit/SQLBuilder.java b/library/src/main/java/com/litesuits/orm/db/assit/SQLBuilder.java new file mode 100644 index 0000000..8ae5d05 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/assit/SQLBuilder.java @@ -0,0 +1,1147 @@ +package com.litesuits.orm.db.assit; + +import com.litesuits.orm.db.TableManager; +import com.litesuits.orm.db.annotation.*; +import com.litesuits.orm.db.enums.AssignType; +import com.litesuits.orm.db.model.*; +import com.litesuits.orm.db.model.MapInfo.MapTable; +import com.litesuits.orm.db.utils.ClassUtil; +import com.litesuits.orm.db.utils.DataUtil; +import com.litesuits.orm.db.utils.FieldUtil; +import ohos.utils.PlainArray; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.Map.Entry; + +/** + * The type Sql builder. + */ +public class SQLBuilder { + + /** + * The constant TYPE_UPDATE. + */ + public static final int TYPE_UPDATE = 3; + /** + * The constant DESC. + */ + public static final String DESC = " DESC "; + /** + * The constant COMMA. + */ + public static final String COMMA = ","; + /** + * The constant OR. + */ + public static final String OR = " OR "; + /** + * The constant NOT. + */ + public static final String NOT = " NOT "; + /** + * The constant ASTERISK. + */ + public static final String ASTERISK = "*"; + /** + * The constant TYPE_INSERT. + */ + private static final int TYPE_INSERT = 1; + /** + * The constant TYPE_REPLACE. + */ + private static final int TYPE_REPLACE = 2; + /** + * The constant DELETE_FROM. + */ + private static final String DELETE_FROM = "DELETE FROM "; + /** + * The constant SELECT_TABLES. + */ + private static final String SELECT_TABLES = "SELECT * FROM sqlite_master WHERE type='table' ORDER BY name"; + /** + * The constant PRAGMA_TABLE_INFO. + */ + private static final String PRAGMA_TABLE_INFO = "PRAGMA table_info("; + /** + * The constant PARENTHESES_LEFT. + */ + private static final String PARENTHESES_LEFT = "("; + /** + * The constant PARENTHESES_RIGHT. + */ + private static final String PARENTHESES_RIGHT = ")"; + /** + * The constant IN. + */ + private static final String IN = " IN "; + /** + * The constant SELECT_MAX. + */ + private static final String SELECT_MAX = "SELECT MAX "; + /** + * The constant SELECT_ANY_FROM. + */ + private static final String SELECT_ANY_FROM = "SELECT * FROM "; + /** + * The constant SELECT. + */ + private static final String SELECT = "SELECT "; + /** + * The constant FROM. + */ + private static final String FROM = " FROM "; + /** + * The constant ORDER_BY. + */ + private static final String ORDER_BY = " ORDER BY "; + /** + * The constant ASC. + */ + private static final String ASC = " ASC "; + /** + * The constant LIMIT. + */ + private static final String LIMIT = " LIMIT "; + /** + * The constant DROP_TABLE. + */ + private static final String DROP_TABLE = "DROP TABLE "; + /** + * The constant CREATE. + */ + private static final String CREATE = "CREATE "; + /** + * The constant TEMP. + */ + private static final String TEMP = "TEMP "; + /** + * The constant TABLE_IF_NOT_EXISTS. + */ + private static final String TABLE_IF_NOT_EXISTS = "TABLE IF NOT EXISTS "; + /** + * The constant PRIMARY_KEY_AUTOINCREMENT. + */ + private static final String PRIMARY_KEY_AUTOINCREMENT = "PRIMARY KEY AUTOINCREMENT "; + /** + * The constant PRIMARY_KEY. + */ + private static final String PRIMARY_KEY = "PRIMARY KEY "; + /** + * The constant TWO_HOLDER. + */ + private static final String TWO_HOLDER = "(?,?)"; + /** + * The constant BLANK. + */ + private static final String BLANK = " "; + /** + * The constant NOT_NULL. + */ + private static final String NOT_NULL = "NOT NULL "; + /** + * The constant DEFAULT. + */ + private static final String DEFAULT = "DEFAULT "; + /** + * The constant UNIQUE. + */ + private static final String UNIQUE = "UNIQUE "; + /** + * The constant ON_CONFLICT. + */ + private static final String ON_CONFLICT = "ON CONFLICT "; + /** + * The constant CHECK. + */ + private static final String CHECK = "CHECK "; + /** + * The constant COLLATE. + */ + private static final String COLLATE = "COLLATE "; + /** + * The constant COMMA_HOLDER. + */ + private static final String COMMA_HOLDER = ",?"; + /** + * The constant EQUALS_HOLDER. + */ + private static final String EQUALS_HOLDER = "=?"; + /** + * The constant HOLDER. + */ + private static final String HOLDER = "?"; + /** + * The constant INSERT. + */ + private static final String INSERT = "INSERT "; + /** + * The constant REPLACE. + */ + private static final String REPLACE = "REPLACE "; + /** + * The constant INTO. + */ + private static final String INTO = "INTO "; + /** + * The constant VALUES. + */ + private static final String VALUES = "VALUES"; + /** + * The constant UPDATE. + */ + private static final String UPDATE = "UPDATE "; + /** + * The constant SET. + */ + private static final String SET = " SET "; + /** + * The constant WHERE. + */ + private static final String WHERE = " WHERE "; + /** + * The constant AND. + */ + private static final String AND = " AND "; + + /** + * 构建【获取SQLite全部表】sql语句 + * + * @return the sql statement + */ + public static SQLStatement buildTableObtainAll() { + return new SQLStatement(SELECT_TABLES, null); + } + + /** + * 构建【获取SQLite全部表】sql语句 + * + * @param table the table + * @return the sql statement + */ + public static SQLStatement buildColumnsObtainAll(String table) { + return new SQLStatement(PRAGMA_TABLE_INFO + table + PARENTHESES_RIGHT, null); + } + + /** + * 构建【获取最新插入的数据的主键】sql语句 + * + * @param table the table + * @return the sql statement + */ + public static SQLStatement buildGetLastRowId(EntityTable table) { + return new SQLStatement(SELECT_MAX + PARENTHESES_LEFT + table.key.column + + PARENTHESES_RIGHT + FROM + table.name, null); + } + + /** + * 构建【表删除】sql语句 + * + * @param table the table + * @return the sql statement + */ + public static SQLStatement buildDropTable(EntityTable table) { + return new SQLStatement(DROP_TABLE + table.name, null); + } + + /** + * 构建【表删除】sql语句 + * + * @param tableName the table name + * @return the sql statement + */ + public static SQLStatement buildDropTable(String tableName) { + return new SQLStatement(DROP_TABLE + tableName, null); + } + + /** + * 构建【表】sql语句 + *

+ * create [temp] table if not exists (table-name) (co1 TEXT, co2 TEXT, UNIQUE (co1, co2)) + *

+ * such as : CREATE TABLE IF NOT EXISTS table-name (_id INTEGER PRIMARY KEY AUTOINCREMENT ,xx TEXT) + * + * @param table the table + * @return the sql statement + */ + public static SQLStatement buildCreateTable(EntityTable table) { + StringBuilder sb = new StringBuilder(); + sb.append(CREATE); + if (table.getAnnotation(Temporary.class) != null) sb.append(TEMP); + sb.append(TABLE_IF_NOT_EXISTS).append(table.name).append(PARENTHESES_LEFT); + boolean hasKey = false; + if (table.key != null) { + hasKey = true; + if (table.key.assign == AssignType.AUTO_INCREMENT) + sb.append(table.key.column).append(DataUtil.INTEGER).append(PRIMARY_KEY_AUTOINCREMENT); + else + sb.append(table.key.column).append(DataUtil.getSQLDataType(table.key.classType)).append(PRIMARY_KEY); + } + if (!Checker.isEmpty(table.pmap)) { + if (hasKey) sb.append(COMMA); + boolean needComma = false; + PlainArray> combineUniqueMap = null; + for (Entry en : table.pmap.entrySet()) { + if (needComma) sb.append(COMMA); + else needComma = true; + String key = en.getKey(); + sb.append(key); + if (en.getValue() == null) sb.append(DataUtil.TEXT); + else { + Field f = en.getValue().field; + sb.append(DataUtil.getSQLDataType(en.getValue().classType)); + + if (f.getAnnotation(NotNull.class) != null) sb.append(NOT_NULL); + if (f.getAnnotation(Default.class) != null) { + sb.append(DEFAULT); + sb.append(f.getAnnotation(Default.class).value()); + sb.append(BLANK); + } + if (f.getAnnotation(Unique.class) != null) sb.append(UNIQUE); + if (f.getAnnotation(Conflict.class) != null) { + sb.append(ON_CONFLICT); + sb.append(f.getAnnotation(Conflict.class).value().getSql()); + sb.append(BLANK); + } + + if (f.getAnnotation(Check.class) != null) { + sb.append(CHECK + PARENTHESES_LEFT); + sb.append(f.getAnnotation(Check.class).value()); + sb.append(PARENTHESES_RIGHT); + sb.append(BLANK); + } + if (f.getAnnotation(Collate.class) != null) { + sb.append(COLLATE); + sb.append(f.getAnnotation(Collate.class).value()); + sb.append(BLANK); + } + UniqueCombine uc = f.getAnnotation(UniqueCombine.class); + if (uc != null) { + if (combineUniqueMap == null) combineUniqueMap = new PlainArray>(); + Optional> strings = combineUniqueMap.get(uc.value()); + ArrayList list;// = (ArrayList) strings; + + if (strings.isPresent()) list = strings.get(); + else { + list = new ArrayList(); + combineUniqueMap.put(uc.value(), list); + } + list.add(key); + } + + } + } + if (combineUniqueMap != null) for (int i = 0, nsize = combineUniqueMap.size(); i < nsize; i++) { + ArrayList list = combineUniqueMap.valueAt(i); + if (list.size() > 1) { + sb.append(COMMA).append(UNIQUE).append(PARENTHESES_LEFT); + for (int j = 0, size = list.size(); j < size; j++) { + if (j != 0) sb.append(COMMA); + sb.append(list.get(j)); + } + sb.append(PARENTHESES_RIGHT); + } + } + } + sb.append(PARENTHESES_RIGHT); + return new SQLStatement(sb.toString(), null); + } + + /** + * 构建 insert 语句 + * + * @param entity the entity + * @param algorithm the algorithm + * @return the sql statement + */ + public static SQLStatement buildInsertSql(Object entity, ConflictAlgorithm algorithm) { + return buildInsertSql(entity, true, TYPE_INSERT, algorithm); + } + + /** + * 构建批量 insert all 语句,sql不绑定值,执行时时会遍历绑定值。 + * + * @param entity the entity + * @param algorithm the algorithm + * @return the sql statement + */ + public static SQLStatement buildInsertAllSql(Object entity, ConflictAlgorithm algorithm) { + return buildInsertSql(entity, false, TYPE_INSERT, algorithm); + } + + /** + * 构建 replace 语句 + * + * @param entity the entity + * @return the sql statement + */ + public static SQLStatement buildReplaceSql(Object entity) { + return buildInsertSql(entity, true, TYPE_REPLACE, null); + } + + /** + * 构建批量 replace all 语句,sql不绑定值,执行时时会遍历绑定值。 + * + * @param entity the entity + * @return the sql statement + */ + public static SQLStatement buildReplaceAllSql(Object entity) { + return buildInsertSql(entity, false, TYPE_REPLACE, null); + } + + /** + * 构建 insert SQL 语句 + * insert(replace) [algorithm] into {table} (key,col...) values (?,?...) + * + * @param entity 实体 + * @param needValue 构建批量sql不需要赋值,执行时临时遍历赋值 + * @param type {@link #TYPE_INSERT} or {@link #TYPE_REPLACE} + * @param algorithm {@link ConflictAlgorithm} + * @return the sql statement + */ + private static SQLStatement buildInsertSql(Object entity, boolean needValue, int type, + ConflictAlgorithm algorithm) { + SQLStatement stmt = new SQLStatement(); + try { + EntityTable table = TableManager.getTable(entity); + StringBuilder sql = new StringBuilder(128); + switch (type) { + case TYPE_REPLACE: + sql.append(REPLACE).append(INTO); + break; + case TYPE_INSERT: + default: + sql.append(INSERT); + if (algorithm != null) sql.append(algorithm.getAlgorithm()).append(INTO); + else sql.append(INTO); + break; + } + sql.append(table.name); + sql.append(PARENTHESES_LEFT); + sql.append(table.key.column); + // 分两部分构建SQL语句,用一个for循环完成SQL构建和值的反射获取,以提高效率。 + StringBuilder value = new StringBuilder(); + value.append(PARENTHESES_RIGHT).append(VALUES).append(PARENTHESES_LEFT).append(HOLDER); + int size = 1, i = 0; + if (!Checker.isEmpty(table.pmap)) size += table.pmap.size(); + Object[] args = null; + if (needValue) { + args = new Object[size]; + args[i++] = FieldUtil.getAssignedKeyObject(table.key, entity); + } + if (!Checker.isEmpty(table.pmap)) for (Entry en : table.pmap.entrySet()) { + // 后构造列名和占位符 + sql.append(COMMA).append(en.getKey()); + value.append(COMMA_HOLDER); + // 构造列值 + if (needValue) args[i] = FieldUtil.get(en.getValue().field, entity); + i++; + } + sql.append(value).append(PARENTHESES_RIGHT); + stmt.bindArgs = args; + stmt.sql = sql.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return stmt; + } + + /** + * 获取 insert 语句被存储对象的参数 + * + * @param entity the entity + * @return the object [ ] + * @throws IllegalAccessException the illegal access exception + */ + public static Object[] buildInsertSqlArgsOnly(Object entity) throws IllegalAccessException { + EntityTable table = TableManager.getTable(entity); + int size = 1, i = 0; + if (!Checker.isEmpty(table.pmap)) size += table.pmap.size(); + Object[] args = new Object[size]; + args[i++] = FieldUtil.getAssignedKeyObject(table.key, entity); + // 后构造列名和占位符 + if (!Checker.isEmpty(table.pmap)) + for (Property p : table.pmap.values()) args[i++] = FieldUtil.get(p.field, entity); + return args; + } + + /** + * 构建 update 语句 + * + * @param entity the entity + * @param cvs the cvs + * @param algorithm the algorithm + * @return the sql statement + */ + public static SQLStatement buildUpdateSql(Object entity, ColumnsValue cvs, ConflictAlgorithm algorithm) { + return buildUpdateSql(entity, cvs, algorithm, true); + } + + /** + * 构建批量 update all 语句,sql不绑定值,执行时时会遍历绑定值。 + * + * @param entity the entity + * @param cvs the cvs + * @param algorithm the algorithm + * @return the sql statement + */ + public static SQLStatement buildUpdateAllSql(Object entity, ColumnsValue cvs, ConflictAlgorithm algorithm) { + return buildUpdateSql(entity, cvs, algorithm, false); + } + + /** + * 构建 update SQL语句 + * update [algorithm] {table} set col=?,... where key=value + * + * @param entity 实体 + * @param cvs 更新的列,为NULL则更新全部 + * @param algorithm {@link ConflictAlgorithm} + * @param needValue 构建批量sql不需要赋值,执行时临时遍历赋值(批量更新时,仅构建sql语句,插入操作时循环赋值) + * @return the sql statement + */ + private static SQLStatement buildUpdateSql(Object entity, ColumnsValue cvs, + ConflictAlgorithm algorithm, boolean needValue) { + SQLStatement stmt = new SQLStatement(); + try { + EntityTable table = TableManager.getTable(entity); + StringBuilder sql = new StringBuilder(128); + sql.append(UPDATE); + if (algorithm != null) sql.append(algorithm.getAlgorithm()); + sql.append(table.name); + sql.append(SET); + // 分两部分构建SQL语句,用一个for循环完成SQL构建和值的反射获取,以提高效率。 + int size = 1, i = 0; + Object[] args = null; + if (cvs != null && cvs.checkColumns()) { + if (needValue) { + size += cvs.columns.length; + args = new Object[size]; + } + for (; i < cvs.columns.length; i++) { + if (i > 0) sql.append(COMMA); + sql.append(cvs.columns[i]).append(EQUALS_HOLDER); + if (needValue) { + args[i] = cvs.getValue(cvs.columns[i]); + if (args[i] == null) args[i] = FieldUtil.get(table.pmap.get(cvs.columns[i]).field, entity); + } + } + } else if (!Checker.isEmpty(table.pmap)) { + if (needValue) { + size += table.pmap.size(); + args = new Object[size]; + } + for (Entry en : table.pmap.entrySet()) { + if (i > 0) sql.append(COMMA); + sql.append(en.getKey()).append(EQUALS_HOLDER); + if (needValue) args[i] = FieldUtil.get(en.getValue().field, entity); + i++; + } + } else if (needValue) args = new Object[size]; + if (needValue) args[size - 1] = FieldUtil.getAssignedKeyObject(table.key, entity); + sql.append(WHERE).append(table.key.column).append(EQUALS_HOLDER); + stmt.sql = sql.toString(); + stmt.bindArgs = args; + } catch (Exception e) { + e.printStackTrace(); + } + return stmt; + } + + /** + * 获取 insert 语句被存储对象的参数 + * + * @param entity the entity + * @param cvs the cvs + * @return the object [ ] + * @throws IllegalAccessException the illegal access exception + */ + public static Object[] buildUpdateSqlArgsOnly(Object entity, ColumnsValue cvs) throws IllegalAccessException { + EntityTable table = TableManager.getTable(entity); + // 分两部分构建SQL语句,用一个for循环完成SQL构建和值的反射获取,以提高效率。 + int size = 1, i = 0; + Object[] args = null; + if (cvs != null && cvs.checkColumns()) { + size += cvs.columns.length; + args = new Object[size]; + for (; i < cvs.columns.length; i++) { + args[i] = cvs.getValue(cvs.columns[i]); + if (args[i] == null) args[i] = FieldUtil.get(table.pmap.get(cvs.columns[i]).field, entity); + } + } else if (!Checker.isEmpty(table.pmap)) { + size += table.pmap.size(); + args = new Object[size]; + for (Entry en : table.pmap.entrySet()) { + args[i] = FieldUtil.get(en.getValue().field, entity); + i++; + } + } else args = new Object[size]; + args[size - 1] = FieldUtil.getAssignedKeyObject(table.key, entity); + return args; + } + + /** + * 构建 update SQL语句 + * update [algorithm] {table} set col1=?, col2=? where ... + * + * @param where 更新语句 + * @param cvs 更新的列,为NULL则更新全部 + * @param algorithm {@link ConflictAlgorithm} + * @return the sql statement + */ + public static SQLStatement buildUpdateSql(WhereBuilder where, ColumnsValue cvs, ConflictAlgorithm algorithm) { + SQLStatement stmt = new SQLStatement(); + try { + EntityTable table = TableManager.getTable(where.getTableClass()); + StringBuilder sql = new StringBuilder(128); + sql.append(UPDATE); + if (algorithm != null) sql.append(algorithm.getAlgorithm()); + sql.append(table.name); + sql.append(SET); + // 分两部分构建SQL语句,用一个for循环完成SQL构建和值的反射获取,以提高效率。 + Object[] args; + if (cvs != null && cvs.checkColumns()) { + Object[] wArgs = where.getWhereArgs(); + if (wArgs != null) args = new Object[cvs.columns.length + wArgs.length]; + else + args = new Object[cvs.columns.length]; + int i = 0; + for (; i < cvs.columns.length; i++) { + if (i > 0) sql.append(COMMA); + sql.append(cvs.columns[i]).append(EQUALS_HOLDER); + args[i] = cvs.getValue(cvs.columns[i]); + } + if (wArgs != null) for (Object o : wArgs) args[i++] = o; + } else args = where.getWhereArgs(); + sql.append(where.createWhereString()); + stmt.sql = sql.toString(); + stmt.bindArgs = args; + } catch (Exception e) { + e.printStackTrace(); + } + return stmt; + } + + /** + * 构建删除sql语句 + * delete from [table] where key=? + * + * @param entity the entity + * @return the sql statement + */ + public static SQLStatement buildDeleteSql(Object entity) { + SQLStatement stmt = new SQLStatement(); + try { + EntityTable table = TableManager.getTable(entity); + if (table.key != null) { + stmt.sql = DELETE_FROM + table.name + WHERE + table.key.column + EQUALS_HOLDER; + stmt.bindArgs = new String[]{String.valueOf(FieldUtil.get(table.key.field, entity))}; + } else if (!Checker.isEmpty(table.pmap)) { + StringBuilder sb = new StringBuilder(); + sb.append(DELETE_FROM).append(table.name).append(WHERE); + Object[] args = new Object[table.pmap.size()]; + int i = 0; + for (Entry en : table.pmap.entrySet()) { + if (i == 0) sb.append(en.getKey()).append(EQUALS_HOLDER); + else + sb.append(AND).append(en.getKey()).append(EQUALS_HOLDER); + args[i++] = FieldUtil.get(en.getValue().field, entity); + } + stmt.sql = sb.toString(); + stmt.bindArgs = args; + } + } catch (Exception e) { + e.printStackTrace(); + } + return stmt; + } + + /** + * 构建批量删除sql语句 + * delete from [table] where [key] in (?,?) + *

+ * 注意:collection 数量不能超过999 + * + * @param collection the collection + * @return the sql statement + */ + public static SQLStatement buildDeleteSql(Collection collection) { + SQLStatement stmt = new SQLStatement(); + try { + StringBuilder sb = new StringBuilder(256); + EntityTable table = null; + Object[] args = new Object[collection.size()]; + int i = 0; + for (Object entity : collection) { + if (i == 0) { + table = TableManager.getTable(entity); + sb.append(DELETE_FROM).append(table.name).append(WHERE) + .append(table.key.column).append(IN).append(PARENTHESES_LEFT).append(HOLDER); + } else sb.append(COMMA_HOLDER); + args[i++] = FieldUtil.get(table.key.field, entity); + } + sb.append(PARENTHESES_RIGHT); + stmt.sql = sb.toString(); + stmt.bindArgs = args; + } catch (Exception e) { + e.printStackTrace(); + } + return stmt; + } + + /** + * 构建全部删除sql语句 + * delete from {table} + * + * @param claxx the claxx + * @return the sql statement + */ + public static SQLStatement buildDeleteAllSql(Class claxx) { + SQLStatement stmt = new SQLStatement(); + EntityTable table = TableManager.getTable(claxx); + stmt.sql = DELETE_FROM + table.name; + return stmt; + } + + /** + * 构建部分删除sql语句 + * delete form {table} where {key} in (select {key} from {table} order by {col} ASC limit {start},{end}) ) + * + * @param claxx the claxx + * @param start the start + * @param end the end + * @param orderAscColumn the order asc column + * @return the sql statement + */ + public static SQLStatement buildDeleteSql(Class claxx, long start, long end, String orderAscColumn) { + SQLStatement stmt = new SQLStatement(); + EntityTable table = TableManager.getTable(claxx); + String key = table.key.column; + String orderBy = Checker.isEmpty(orderAscColumn) ? key : orderAscColumn; + StringBuilder sb = new StringBuilder(); + sb.append(DELETE_FROM).append(table.name).append(WHERE).append(key) + .append(IN).append(PARENTHESES_LEFT) + .append(SELECT).append(key) + .append(FROM).append(table.name) + .append(ORDER_BY).append(orderBy) + .append(ASC).append(LIMIT).append(start).append(COMMA).append(end).append(PARENTHESES_RIGHT); + stmt.sql = sb.toString(); + return stmt; + } + + /** + * 构建添加列语句 + * alter {table} add column {col} + * + * @param tableName the table name + * @param column the column + * @return the sql statement + */ + public static SQLStatement buildAddColumnSql(String tableName, String column) { + SQLStatement stmt = new SQLStatement(); + stmt.sql = "ALTER TABLE " + tableName + " ADD COLUMN " + column; + return stmt; + } + + /** + * 构建添加主键列语句 + * + * @param tableName + * @param column + * @return + */ + //public static SQLStatement buildAddPrimaryKeySql(String tableName, String column, boolean autoIncrement) { + // SQLStatement stmt = new SQLStatement(); + // if (autoIncrement) { + // stmt.sql = "ALTER TABLE " + tableName + " ADD COLUMN " + column + " INTEGER UNIQUE AUTOINCREMENT"; + // } else { + // stmt.sql = "ALTER TABLE " + tableName + " ADD COLUMN " + column + " TEXT UNIQUE"; + // } + // return stmt; + //} + + /** + * 构建关系映射语句 + * + * @param claxx the claxx + * @return the map info + */ + public static MapInfo buildDelAllMappingSql(Class claxx) { + EntityTable table1 = TableManager.getTable(claxx); + if (!Checker.isEmpty(table1.mappingList)) try { + MapInfo mapInfo = new MapInfo(); + for (MapProperty map : table1.mappingList) { + EntityTable table2 = TableManager.getTable(getTypeByRelation(map)); + // add map table info + String mapTableName = TableManager.getMapTableName(table1, table2); + MapTable mi = new MapTable(mapTableName, table1.name, table2.name); + mapInfo.addTable(mi); + + // add delete mapping sql to map info + SQLStatement st = buildMappingDeleteAllSql(table1, table2); + mapInfo.addDelOldRelationSQL(st); + } + return mapInfo; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 构建关系映射语句 + * 1. 如果是插入或更新数据,先删除旧映射,再建立新映射。 + * 2. 如果是删除,直接删除就映射即可。 + * + * @param entity the entity + * @param insertNew the insert new + * @param tableManager the table manager + * @return the map info + */ + static MapInfo buildMappingInfo(Object entity, boolean insertNew, TableManager tableManager) { + EntityTable table1 = TableManager.getTable(entity); + if (!Checker.isEmpty(table1.mappingList)) try { + Object key1 = FieldUtil.get(table1.key.field, entity); + if (key1 == null) return null; + MapInfo mapInfo = new MapInfo(); + for (MapProperty map : table1.mappingList) { + EntityTable table2 = TableManager.getTable(getTypeByRelation(map)); + // add map table info + String mapTableName = TableManager.getMapTableName(table1, table2); + MapTable mi = new MapTable(mapTableName, table1.name, table2.name); + mapInfo.addTable(mi); + if (tableManager.isSQLMapTableCreated(table1.name, table2.name)) { + // add delete mapping sql to map info + SQLStatement st = buildMappingDeleteSql(key1, table1, table2); + mapInfo.addDelOldRelationSQL(st); + } + + if (insertNew) { + // also insert new mapping relation + Object mapObject = FieldUtil.get(map.field, entity); + if (mapObject != null) if (map.isToMany()) { + ArrayList sqlList; + SQLStatement addSql; + //addSql = buildMappingToManySqlFragment(key1, table1, table2, + // (Collection) mapObject); + if (mapObject instanceof Collection) + sqlList = buildMappingToManySql(key1, table1, table2, (Collection) mapObject); + else //addSql = buildMappingToManySqlFragment(key1, table1, table2, + // Arrays.asList((Object[]) mapObject)); + if (mapObject instanceof Object[]) + sqlList = buildMappingToManySql(key1, table1, table2, + Arrays.asList((Object[]) mapObject)); + else + throw new RuntimeException("OneToMany and ManyToMany Relation," + + " You must use array or collection object"); + if (Checker.isEmpty(sqlList)) mapInfo.addNewRelationSQL(sqlList); + //if (addSql != null) { + // mapInfo.addNewRelationSQL(addSql); + //} + } else { + SQLStatement st = buildMappingToOneSql(key1, table1, table2, mapObject); + if (st != null) mapInfo.addNewRelationSQL(st); + } + } + } + return mapInfo; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * Gets type by relation. + * + * @param mp the mp + * @return the type by relation + */ + private static Class getTypeByRelation(MapProperty mp) { + Class calxx; + if (mp.isToMany()) { + Class c = mp.field.getType(); + if (ClassUtil.isCollection(c)) calxx = FieldUtil.getGenericType(mp.field); + else if (ClassUtil.isArray(c)) calxx = FieldUtil.getComponentType(mp.field); + else + throw new RuntimeException( + "OneToMany and ManyToMany Relation, you must use collection or array object"); + } else calxx = mp.field.getType(); + return calxx; + } + + /** + * 构建删除全部映射关系数据语句 + * delete from {map table} + * + * @param table1 the table 1 + * @param table2 the table 2 + * @return the sql statement + * @throws IllegalArgumentException the illegal argument exception + * @throws IllegalAccessException the illegal access exception + */ + private static SQLStatement buildMappingDeleteAllSql(EntityTable table1, + EntityTable table2) throws IllegalArgumentException, IllegalAccessException { + if (table2 != null) { + String mapTableName = TableManager.getMapTableName(table1, table2); + SQLStatement stmt = new SQLStatement(); + stmt.sql = DELETE_FROM + mapTableName; + return stmt; + } + return null; + } + + /** + * 构建SQL语句:删除Key1的全部映射关系数据 + * delete from {map table} where {key1=?} + * + * @param key1 the key 1 + * @param table1 the table 1 + * @param table2 the table 2 + * @return the sql statement + * @throws IllegalArgumentException the illegal argument exception + * @throws IllegalAccessException the illegal access exception + */ + private static SQLStatement buildMappingDeleteSql(Object key1, EntityTable table1, + EntityTable table2) throws IllegalArgumentException, IllegalAccessException { + if (table2 != null) { + String mapTableName = TableManager.getMapTableName(table1, table2); + return buildMappingDeleteSql(mapTableName, key1, table1); + } + return null; + } + + /** + * 构建SQL语句:删除Key1的全部映射关系数据 + * delete from {map table} where {key1=?} + * + * @param mapTableName the map table name + * @param key1 the key 1 + * @param table1 the table 1 + * @return the sql statement + * @throws IllegalArgumentException the illegal argument exception + * @throws IllegalAccessException the illegal access exception + */ + public static SQLStatement buildMappingDeleteSql(String mapTableName, Object key1, + EntityTable table1) throws IllegalArgumentException, IllegalAccessException { + if (mapTableName != null) { + SQLStatement stmt = new SQLStatement(); + stmt.sql = DELETE_FROM + mapTableName + WHERE + table1.name + EQUALS_HOLDER; + stmt.bindArgs = new Object[]{key1}; + return stmt; + } + return null; + } + + /** + * 构建N对多关系SQL + * replace into {table} (col1=?,col2=?) values (v1,v2),(va,vb)... + * + * @param the type parameter + * @param key1 the key 1 + * @param table1 the table 1 + * @param table2 the table 2 + * @param coll the coll + * @return the array list + * @throws Exception the exception + */ + public static ArrayList buildMappingToManySql(Object key1, + EntityTable table1, EntityTable table2, + Collection coll) throws Exception { + ArrayList sqlList = new ArrayList(); + // this will take 2 "?" holders + CollSpliter.split(coll, SQLStatement.IN_TOP_LIMIT / 2, new CollSpliter.Spliter() { + @Override + public int oneSplit(ArrayList list) throws Exception { + SQLStatement sql = SQLBuilder.buildMappingToManySqlFragment(key1, table1, table2, list); + if (sql != null) sqlList.add(sql); + return 0; + } + }); + return sqlList; + } + + /** + * 构建N对多关系SQL + * replace into {table} (col1=?,col2=?) values (v1,v2),(va,vb)... + * (注意:collection 数量) + * + * @param key1 the key 1 + * @param table1 the table 1 + * @param table2 the table 2 + * @param coll the coll + * @return the sql statement + * @throws IllegalArgumentException the illegal argument exception + * @throws IllegalAccessException the illegal access exception + */ + private static SQLStatement buildMappingToManySqlFragment(Object key1, EntityTable table1, + EntityTable table2, + Collection coll) throws IllegalArgumentException, IllegalAccessException { + String mapTableName = TableManager.getMapTableName(table1, table2); + if (!Checker.isEmpty(coll)) { + boolean isF = true; + StringBuilder values = new StringBuilder(128); + ArrayList list = new ArrayList(); + String key1Str = String.valueOf(key1); + for (Object o : coll) { + Object key2 = FieldUtil.getAssignedKeyObject(table2.key, o); + if (key2 != null) { + if (isF) { + values.append(TWO_HOLDER); + isF = false; + } else values.append(COMMA).append(TWO_HOLDER); + list.add(key1Str); + list.add(String.valueOf(key2)); + } + } + + Object[] args = list.toArray(new String[list.size()]); + if (!Checker.isEmpty(args)) { + SQLStatement stmt = new SQLStatement(); + stmt.sql = REPLACE + INTO + mapTableName + PARENTHESES_LEFT + table1.name + COMMA + table2.name + PARENTHESES_RIGHT + VALUES + values; + stmt.bindArgs = args; + return stmt; + } + } + return null; + } + + /** + * 构建N对一关系存储语句 + * insert into {table} (key1,key2) values (?,?) + * + * @param key1 the key 1 + * @param table1 the table 1 + * @param table2 the table 2 + * @param obj the obj + * @return the sql statement + * @throws IllegalArgumentException the illegal argument exception + * @throws IllegalAccessException the illegal access exception + */ + private static SQLStatement buildMappingToOneSql(Object key1, EntityTable table1, EntityTable table2, + Object obj) throws IllegalArgumentException, IllegalAccessException { + Object key2 = FieldUtil.getAssignedKeyObject(table2.key, obj); + if (key2 != null) { + String mapTableName = TableManager.getMapTableName(table1, table2); + return buildMappingToOneSql(mapTableName, key1, key2, table1, table2); + } + return null; + } + + /** + * 构建N对一关系存储语句 + * insert into {table} (key1,key2) values (?,?) + * + * @param mapTableName the map table name + * @param key1 the key 1 + * @param key2 the key 2 + * @param table1 the table 1 + * @param table2 the table 2 + * @return the sql statement + * @throws IllegalArgumentException the illegal argument exception + * @throws IllegalAccessException the illegal access exception + */ + public static SQLStatement buildMappingToOneSql(String mapTableName, Object key1, Object key2, + EntityTable table1, EntityTable table2) + throws IllegalArgumentException, IllegalAccessException { + if (key2 != null) { + StringBuilder sql = new StringBuilder(128); + sql.append(INSERT).append(INTO).append(mapTableName) + .append(PARENTHESES_LEFT).append(table1.name) + .append(COMMA).append(table2.name) + .append(PARENTHESES_RIGHT).append(VALUES).append(TWO_HOLDER); + SQLStatement stmt = new SQLStatement(); + stmt.sql = sql.toString(); + stmt.bindArgs = new Object[]{key1, key2}; + return stmt; + } + return null; + } + + /** + * 构建查询关系映射语句 + * select * from {map table} where {key1} in (?,?...) and {key2} in (?,?...) + * 注意:key1List数量不能超过999 + * + * @param class1 the class 1 + * @param class2 the class 2 + * @param key1List the key 1 list + * @return the sql statement + */ + public static SQLStatement buildQueryRelationSql(Class class1, Class class2, List key1List) { + return buildQueryRelationSql(class1, class2, key1List, null); + } + + /** + * 构建查询关系映射语句 + * select * from {map table} where {key1} in (?,?...) and {key2} in (?,?...) + * 注意:keyList 数量不能超过999 + * + * @param class1 the class 1 + * @param class2 the class 2 + * @param key1List the key 1 list + * @param key2List the key 2 list + * @return the sql statement + */ + private static SQLStatement buildQueryRelationSql(Class class1, Class class2, + List key1List, List key2List) { + EntityTable table1 = TableManager.getTable(class1); + EntityTable table2 = TableManager.getTable(class2); + QueryBuilder builder = new QueryBuilder(class1).queryMappingInfo(class2); + ArrayList keyList = new ArrayList(); + StringBuilder sb = null; + if (!Checker.isEmpty(key1List)) { + sb = new StringBuilder(); + sb.append(table1.name).append(IN).append(PARENTHESES_LEFT); + for (int i = 0, size = key1List.size(); i < size; i++) + if (i == 0) sb.append(HOLDER); + else sb.append(COMMA_HOLDER); + sb.append(PARENTHESES_RIGHT); + keyList.addAll(key1List); + } + if (!Checker.isEmpty(key2List)) { + if (sb == null) sb = new StringBuilder(); + else sb.append(AND); + + sb.append(table2.name).append(IN).append(PARENTHESES_LEFT); + for (int i = 0, size = key2List.size(); i < size; i++) + if (i == 0) sb.append(HOLDER); + else sb.append(COMMA_HOLDER); + sb.append(PARENTHESES_RIGHT); + keyList.addAll(key2List); + } + if (sb != null) builder.where(sb.toString(), (Object[]) keyList.toArray(new String[keyList.size()])); + return builder.createStatement(); + } + + /** + * 构建查询关系映射语句 + * + * @param table1 the table 1 + * @param table2 the table 2 + * @param key1 the key 1 + * @return the sql statement + */ + public static SQLStatement buildQueryRelationSql(EntityTable table1, EntityTable table2, Object key1) { + SQLStatement sqlStatement = new SQLStatement(); + sqlStatement.sql = SELECT_ANY_FROM + TableManager.getMapTableName(table1, table2) + + WHERE + table1.name + EQUALS_HOLDER; + sqlStatement.bindArgs = new String[]{String.valueOf(key1)}; + return sqlStatement; + } + + /** + * 构建查询关系映射语句 + * select * from table2 where key2 = key2; + * + * @param table2 the table 2 + * @param key2 the key 2 + * @return the sql statement + */ + public static SQLStatement buildQueryMapEntitySql(EntityTable table2, Object key2) { + SQLStatement sqlStatement = new SQLStatement(); + sqlStatement.sql = SELECT_ANY_FROM + table2.name + WHERE + table2.key.column + EQUALS_HOLDER; + sqlStatement.bindArgs = new String[]{String.valueOf(key2)}; + return sqlStatement; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/assit/SQLStatement.java b/library/src/main/java/com/litesuits/orm/db/assit/SQLStatement.java new file mode 100644 index 0000000..b98cd58 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/assit/SQLStatement.java @@ -0,0 +1,591 @@ +package com.litesuits.orm.db.assit; + +import com.litesuits.orm.db.TableManager; +import com.litesuits.orm.db.assit.Querier.CursorParser; +import com.litesuits.orm.db.model.ColumnsValue; +import com.litesuits.orm.db.model.EntityTable; +import com.litesuits.orm.db.model.MapInfo; +import com.litesuits.orm.db.model.MapInfo.MapTable; +import com.litesuits.orm.db.model.Property; +import com.litesuits.orm.db.utils.ClassUtil; +import com.litesuits.orm.db.utils.DataUtil; +import com.litesuits.orm.db.utils.FieldUtil; +import com.litesuits.orm.log.OrmLog; +import ohos.data.rdb.RdbStore; +import ohos.data.rdb.Statement; +import ohos.data.resultset.ResultSet; + +import java.io.IOException; +import java.io.Serializable; +import java.util.*; + +/** + * sql语句构造与执行 + * + * @author mty + * @date 2013 -6-14下午7:48:34 + */ +public class SQLStatement implements Serializable { + /** + * The constant NONE. + */ + public static final short NONE = -1; + /** + * The constant NORMAL. + */ + public static final short NORMAL = 0; + /** + * The constant IN_TOP_LIMIT. + */ + public static final int IN_TOP_LIMIT = 999; + /** + * The constant serialVersionUID. + */ + private static final long serialVersionUID = -3790876762607683712L; + /** + * The constant TAG. + */ + private static final String TAG = SQLStatement.class.getSimpleName(); + /** + * sql语句 + */ + public String sql; + /** + * sql语句中占位符对应的参数 + */ + public Object[] bindArgs; + /** + * sql语句执行者,私有(private)。 + */ + private Statement mStatement; + + /** + * Instantiates a new Sql statement. + */ + public SQLStatement() { + } + + /** + * Instantiates a new Sql statement. + * + * @param sql the sql + * @param args the args + */ + public SQLStatement(String sql, Object[] args) { + this.sql = sql; + this.bindArgs = args; + } + + /** + * 重新映射关系到数据库 + * + * @param entity the entity + * @param insertNew 仅在执行删除该实体时,此值为false + * @param tableCheck the table check + * @param db the db + * @param tableManager the table manager + */ + private static void mapRelationToDb(Object entity, boolean insertNew, + boolean tableCheck, RdbStore db, + TableManager tableManager) { + // 插入关系映射 + MapInfo mapTable = SQLBuilder.buildMappingInfo(entity, insertNew, tableManager); + if (mapTable != null && !mapTable.isEmpty()) Transaction.execute(db, new Transaction.Worker() { + @Override + public Boolean doTransaction(RdbStore db) throws Exception { + if (insertNew && tableCheck) for (MapTable table : mapTable.tableList) + tableManager.checkOrCreateMappingTable(db, table.name, table.column1, table.column2); + if (mapTable.delOldRelationSQL != null) for (SQLStatement st : mapTable.delOldRelationSQL) { + long rowId = st.execDelete(db); + if (OrmLog.isPrint) + OrmLog.v(SQLStatement.TAG, "Exec delete mapping success, nums: " + rowId); + } + if (insertNew && mapTable.mapNewRelationSQL != null) + for (SQLStatement st : mapTable.mapNewRelationSQL) { + long rowId = st.execInsert(db); + if (OrmLog.isPrint) OrmLog.v(SQLStatement.TAG, "Exec save mapping success, nums: " + rowId); + } + return true; + } + }); + } + + /** + * 给sql语句的占位符(?)按序绑定值 + * + * @param i The 1-based index to the parameter to bind null to + * @param o the o + * @throws IOException the io exception + */ + private void bind(int i, Object o) throws IOException { + if (o == null) this.mStatement.setNull(i);//.bindNull(i); + else if (o instanceof CharSequence || o instanceof Boolean || o instanceof Character) + this.mStatement.setString(i, String.valueOf(o)); + else if (o instanceof Float || o instanceof Double) this.mStatement.setDouble(i, ((Number) o).doubleValue()); + else if (o instanceof Number) this.mStatement.setLong(i, ((Number) o).longValue()); + else if (o instanceof Date) this.mStatement.setLong(i, ((Date) o).getTime()); + else if (o instanceof byte[]) this.mStatement.setBlob(i, (byte[]) o); + else if (o instanceof Serializable) this.mStatement.setBlob(i, DataUtil.objectToByte(o)); + else + this.mStatement.setNull(i); + } + + /** + * 插入数据,未传入实体所以不可以为之注入ID。 + * + * @param db the db + * @return the long + * @throws IOException the io exception + * @throws IllegalAccessException the illegal access exception + */ + public long execInsert(RdbStore db) throws IOException, IllegalAccessException { + return this.execInsertWithMapping(db, null, null); + } + + /** + * 插入数据,并为实体对象为之注入ID(如果需要)。 + * + * @param db the db + * @param entity the entity + * @return the long + * @throws IOException the io exception + * @throws IllegalAccessException the illegal access exception + */ + public long execInsert(RdbStore db, Object entity) throws IOException, IllegalAccessException { + return this.execInsertWithMapping(db, entity, null); + } + + /** + * 插入数据,为其注入ID(如果需要),关系表也一并处理。 + * + * @param db the db + * @param entity the entity + * @param tableManager the table manager + * @return the long + * @throws IllegalAccessException the illegal access exception + * @throws IOException the io exception + */ + private long execInsertWithMapping(RdbStore db, Object entity, TableManager tableManager) + throws IllegalAccessException, IOException { + this.printSQL(); + this.mStatement = db.buildStatement(this.sql);//.compileStatement(sql); + Object keyObj = null; + if (!Checker.isEmpty(this.bindArgs)) { + keyObj = this.bindArgs[0]; + for (int i = 0; i < this.bindArgs.length; i++) this.bind(i + 1, this.bindArgs[i]); + } + //OrmLog.i(TAG, "SQL Execute bind over "); + long rowID = NONE; + try { + rowID = this.mStatement.executeAndGetLastInsertRowId();//.executeInsert(); + } finally { + this.realease(); + } + //OrmLog.i(TAG, "SQL Execute insert over "); + if (OrmLog.isPrint) OrmLog.i(TAG, "SQL Execute Insert RowID --> " + rowID + " sql: " + this.sql); + if (entity != null) FieldUtil.setKeyValueIfneed(entity, TableManager.getTable(entity).key, keyObj, rowID); + if (tableManager != null) SQLStatement.mapRelationToDb(entity, true, true, db, tableManager); + return rowID; + } + + /** + * 执行批量插入 + * + * @param db the db + * @param list the list + * @return the int + */ + public int execInsertCollection(RdbStore db, Collection list) { + return this.execInsertCollectionWithMapping(db, list, null); + } + + /** + * Exec insert collection with mapping int. + * + * @param db the db + * @param list the list + * @param tableManager the table manager + * @return the int + */ + private int execInsertCollectionWithMapping(RdbStore db, Collection list, TableManager tableManager) { + this.printSQL(); + db.beginTransaction(); + if (OrmLog.isPrint) OrmLog.i(TAG, "----> BeginTransaction[insert col]"); + EntityTable table = null; + try { + this.mStatement = db.buildStatement(this.sql);//.compileStatement(sql); + Iterator it = list.iterator(); + boolean mapTableCheck = true; + while (it.hasNext()) { + this.mStatement.clearValues();//.clearBindings(); + Object obj = it.next(); + + if (table == null) table = TableManager.getTable(obj); + + int j = 1; + Object keyObj = null; + if (table.key != null) { + keyObj = FieldUtil.getAssignedKeyObject(table.key, obj); + this.bind(j++, keyObj); + } + // 第一个是主键。其他属性从2开始。 + if (!Checker.isEmpty(table.pmap)) + for (Property p : table.pmap.values()) this.bind(j++, FieldUtil.get(p.field, obj)); + long rowID = this.mStatement.executeAndGetLastInsertRowId();//.executeInsert(); + FieldUtil.setKeyValueIfneed(obj, table.key, keyObj, rowID); + if (tableManager != null) { + SQLStatement.mapRelationToDb(obj, true, mapTableCheck, db, tableManager); + mapTableCheck = false; + } + } + if (OrmLog.isPrint) OrmLog.i(TAG, "Exec insert [" + list.size() + "] rows , SQL: " + this.sql); + db.markAsCommit();//.setTransactionSuccessful(); + if (OrmLog.isPrint) OrmLog.i(TAG, "----> BeginTransaction[insert col] Successful"); + return list.size(); + } catch (Exception e) { + if (OrmLog.isPrint) OrmLog.e(TAG, "----> BeginTransaction[insert col] Failling"); + e.printStackTrace(); + } finally { + this.realease(); + db.endTransaction(); + } + return NONE; + } + + /** + * 执行更新单个数据,返回受影响的行数 + * + * @param db the db + * @return the int + * @throws IOException the io exception + */ + public int execUpdate(RdbStore db) throws IOException { + return this.execUpdateWithMapping(db, null, null); + } + + /** + * 执行更新单个数据,返回受影响的行数 + * + * @param db the db + * @param entity the entity + * @param tableManager the table manager + * @return the int + * @throws IOException the io exception + */ + private int execUpdateWithMapping(RdbStore db, Object entity, TableManager tableManager) throws IOException { + this.printSQL(); + this.mStatement = db.buildStatement(this.sql);//.compileStatement(sql); + if (!Checker.isEmpty(this.bindArgs)) + for (int i = 0; i < this.bindArgs.length; i++) this.bind(i + 1, this.bindArgs[i]); + int rows = NONE; + /*if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + mStatement.execute(); + rows = NORMAL; + } else */ + { + rows = this.mStatement.executeAndGetChanges();//.executeUpdateDelete(); + } + this.realease(); + if (OrmLog.isPrint) OrmLog.i(TAG, "SQL Execute update, changed rows --> " + rows); + if (tableManager != null && entity != null) SQLStatement.mapRelationToDb(entity, true, true, db, tableManager); + return rows; + } + + /** + * 执行批量更新 + * + * @param db the db + * @param list the list + * @param cvs the cvs + * @return the int + */ + public int execUpdateCollection(RdbStore db, Collection list, ColumnsValue cvs) { + return this.execUpdateCollectionWithMapping(db, list, cvs, null); + } + + /** + * 执行批量更新 + * + * @param db the db + * @param list the list + * @param cvs the cvs + * @param tableManager the table manager + * @return the int + */ + private int execUpdateCollectionWithMapping(RdbStore db, Collection list, + ColumnsValue cvs, TableManager tableManager) { + this.printSQL(); + db.beginTransaction(); + if (OrmLog.isPrint) OrmLog.d(TAG, "----> BeginTransaction[update col]"); + try { + this.mStatement = db.buildStatement(this.sql);//.compileStatement(sql); + Iterator it = list.iterator(); + boolean mapTableCheck = true; + EntityTable table = null; + while (it.hasNext()) { + this.mStatement.clearValues();//.clearBindings(); + Object obj = it.next(); + if (table == null) table = TableManager.getTable(obj); + this.bindArgs = SQLBuilder.buildUpdateSqlArgsOnly(obj, cvs); + if (!Checker.isEmpty(this.bindArgs)) + for (int i = 0; i < this.bindArgs.length; i++) this.bind(i + 1, this.bindArgs[i]); + this.mStatement.execute(); + if (tableManager != null) { + SQLStatement.mapRelationToDb(obj, true, mapTableCheck, db, tableManager); + mapTableCheck = false; + } + } + if (OrmLog.isPrint) OrmLog.i(TAG, "Exec update [" + list.size() + "] rows , SQL: " + this.sql); + db.markAsCommit();//.setTransactionSuccessful(); + if (OrmLog.isPrint) OrmLog.d(TAG, "----> BeginTransaction[update col] Successful"); + return list.size(); + } catch (Exception e) { + if (OrmLog.isPrint) OrmLog.e(TAG, "----> BeginTransaction[update col] Failling"); + e.printStackTrace(); + } finally { + this.realease(); + db.endTransaction(); + } + return NONE; + } + + /** + * 删除语句执行,返回受影响的行数 + * + * @param db the db + * @return the int + * @throws IOException the io exception + */ + public int execDelete(RdbStore db) throws IOException { + return this.execDeleteWithMapping(db, null, null); + } + + /** + * 执行删操作.(excute delete ...),返回受影响的行数 + * 并将关系映射删除 + * + * @param db the db + * @param entity the entity + * @param tableManager the table manager + * @return the int + * @throws IOException the io exception + */ + private int execDeleteWithMapping(RdbStore db, Object entity, TableManager tableManager) + throws IOException { + this.printSQL(); + this.mStatement = db.buildStatement(this.sql);//.compileStatement(sql); + if (this.bindArgs != null) for (int i = 0; i < this.bindArgs.length; i++) this.bind(i + 1, this.bindArgs[i]); + int nums = NONE; + /*if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + mStatement.execute(); + nums = NORMAL; + } else */ + { + nums = this.mStatement.executeAndGetChanges();//.executeUpdateDelete(); + } + if (OrmLog.isPrint) OrmLog.v(TAG, "SQL execute delete, changed rows--> " + nums); + this.realease(); + // 删除关系映射 + if (tableManager != null && entity != null) + SQLStatement.mapRelationToDb(entity, false, false, db, tableManager); + return nums; + } + + /** + * 执行删操作.(excute delete ...),返回受影响的行数 + * 并将关系映射删除 + * + * @param db the db + * @param collection the collection + * @return the int + * @throws IOException the io exception + */ + public int execDeleteCollection(RdbStore db, Collection collection) throws IOException { + return this.execDeleteCollectionWithMapping(db, collection, null); + } + + /** + * 执行删操作.(excute delete ...),返回受影响的行数 + * 并将关系映射删除 + * + * @param db the db + * @param collection the collection + * @param tableManager the table manager + * @return the int + * @throws IOException the io exception + */ + private int execDeleteCollectionWithMapping(RdbStore db, Collection collection, + TableManager tableManager) throws IOException { + this.printSQL(); + // 删除全部数据 + this.mStatement = db.buildStatement(this.sql);//.compileStatement(sql); + if (this.bindArgs != null) for (int i = 0; i < this.bindArgs.length; i++) this.bind(i + 1, this.bindArgs[i]); + int nums; + /* if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + mStatement.execute(); + nums = collection.size(); + } else */ + { + nums = this.mStatement.executeAndGetChanges();//.executeUpdateDelete(); + } + if (OrmLog.isPrint) OrmLog.v(TAG, "SQL execute delete, changed rows --> " + nums); + this.realease(); + if (tableManager != null) { + // 删除关系映射 + Boolean suc = Transaction.execute(db, new Transaction.Worker() { + @Override + public Boolean doTransaction(RdbStore db) throws Exception { + boolean mapTableCheck = true; + for (Object o : collection) { + // 删除关系映射 + SQLStatement.mapRelationToDb(o, false, mapTableCheck, db, tableManager); + mapTableCheck = false; + } + return true; + } + }); + if (OrmLog.isPrint) + OrmLog.i(TAG, "Exec delete collection mapping: " + ((suc != null && suc) ? "成功" : "失败")); + } + return nums; + } + + /** + * 执行create,drop table 等 + * + * @param db the db + * @return the boolean + */ + public boolean execute(RdbStore db) { + this.printSQL(); + try { + this.mStatement = db.buildStatement(this.sql);//.compileStatement(sql); + if (this.bindArgs != null) + for (int i = 0; i < this.bindArgs.length; i++) this.bind(i + 1, this.bindArgs[i]); + this.mStatement.execute(); + return true; + } catch (Exception e) { + e.printStackTrace(); + } finally { + this.realease(); + } + return false; + } + + /** + * Execute a statement that returns a 1 by 1 table with a numeric value. + * For example, SELECT COUNT(*) FROM table; + * + * @param db the db + * @return the long + */ + public long queryForLong(RdbStore db) { + this.printSQL(); + long count = 0; + try { + this.mStatement = db.buildStatement(this.sql);//.compileStatement(sql); + if (this.bindArgs != null) + for (int i = 0; i < this.bindArgs.length; i++) this.bind(i + 1, this.bindArgs[i]); + count = this.mStatement.executeAndGetLong();//.simpleQueryForLong(); + if (OrmLog.isPrint) OrmLog.i(TAG, "SQL execute query for count --> " + count); + } catch (Exception e) { + e.printStackTrace(); + } finally { + this.realease(); + } + return count; + } + + /** + * 执行查询 + * 根据类信息读取数据库,取出全部本类的对象。 + * + * @param the type parameter + * @param db the db + * @param claxx the claxx + * @return the array list + */ + public ArrayList query(RdbStore db, Class claxx) { + this.printSQL(); + ArrayList list = new ArrayList(); + try { + EntityTable table = TableManager.getTable(claxx, false); + Querier.doQuery(db, this, new CursorParser() { + @Override + public void parseEachCursor(RdbStore db, ResultSet c) throws Exception { + //long start = System.nanoTime(); + T t = ClassUtil.newInstance(claxx); + //Log.i(TAG, "parse new after " + ((System.nanoTime() - start)/1000)); + //start = System.nanoTime(); + DataUtil.injectDataToObject(c, t, table); + //Log.i(TAG, "parse inject after " + ((System.nanoTime() - start)/1000)); + list.add(t); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + return list; + } + + /** + * 执行查询 + * 根据类信息读取数据库,取出本类的对象。 + * + * @param the type parameter + * @param db the db + * @param claxx the claxx + * @return the t + */ + public T queryOneEntity(RdbStore db, Class claxx) { + this.printSQL(); + EntityTable table = TableManager.getTable(claxx, false); + T t = Querier.doQuery(db, this, new CursorParser() { + T t; + + @Override + public void parseEachCursor(RdbStore db, ResultSet c) throws Exception { + this.t = ClassUtil.newInstance(claxx); + DataUtil.injectDataToObject(c, this.t, table); + this.stopParse(); + } + + @Override + public T returnResult() { + return this.t; + } + }); + return t; + } + /*------------------------------ 私有方法 ------------------------------*/ + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "SQLStatement [sql=" + this.sql + ", bindArgs=" + Arrays.toString(this.bindArgs) + ", mStatement=" + this.mStatement + + "]"; + } + + /** + * Print sql. + */ + private void printSQL() { + if (OrmLog.isPrint) OrmLog.d(TAG, "SQL Execute: [" + this.sql + "] ARGS--> " + Arrays.toString(this.bindArgs)); + } + + /** + * Realease. + */ + private void realease() { + if (this.mStatement != null) this.mStatement.close(); + //sql = null; + this.bindArgs = null; + this.mStatement = null; + } + + +} diff --git a/library/src/main/java/com/litesuits/orm/db/assit/SQLiteHelper.java b/library/src/main/java/com/litesuits/orm/db/assit/SQLiteHelper.java new file mode 100644 index 0000000..3e8f039 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/assit/SQLiteHelper.java @@ -0,0 +1,89 @@ +package com.litesuits.orm.db.assit; + +import com.litesuits.orm.log.Log; +import ohos.app.Context; +import ohos.data.DatabaseHelper; +import ohos.data.rdb.RdbOpenCallback; +import ohos.data.rdb.RdbStore; +import ohos.data.rdb.StoreConfig; + +/** + * SQLite辅助类 + * + * @author mty + * @date 2013 -6-2下午4:42:47 + */ +public class SQLiteHelper extends DatabaseHelper { + + /** + * The On update listener. + */ + private final OnUpdateListener onUpdateListener; + /** + * The Config. + */ + private final StoreConfig config; + /** + * The Version. + */ + private final int version; + + /** + * Instantiates a new Sq lite helper. + * + * @param context the context + * @param name the name + * @param version the version + * @param onUpdateListener the on update listener + */ + public SQLiteHelper(Context context, String name, int version, OnUpdateListener onUpdateListener) { + super(context); + Log.println("new SQLiteHelper name:%s", name); + this.onUpdateListener = onUpdateListener; + this.version = version; + this.config = StoreConfig.newDefaultConfig(name); + + } + + /** + * Gets rdb store. + * + * @return the rdb store + */ + public RdbStore getRdbStore() { + return this.getRdbStore(this.config, this.version, new RdbOpenCallback() { + @Override + public void onCreate(RdbStore rdbStore) { + Log.println("getRdbStore - onCreate"); + try { + rdbStore.executeSql("CREATE TABLE IF NOT EXISTS Categories (Id INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT);"); + } catch (Exception e) { + Log.println("getRdbStore - onCreate Exception"); + e.printStackTrace(); + } + } + + @Override + public void onUpgrade(RdbStore db, int oldVersion, int newVersion) { + if (SQLiteHelper.this.onUpdateListener != null) + SQLiteHelper.this.onUpdateListener.onUpdate(db, oldVersion, newVersion); + } + }); + } + + /** + * The interface On update listener. + */ + public interface OnUpdateListener { + /** + * On update. + * + * @param db the db + * @param oldVersion the old version + * @param newVersion the new version + */ + void onUpdate(RdbStore db, int oldVersion, int newVersion); + } + + +} \ No newline at end of file diff --git a/library/src/main/java/com/litesuits/orm/db/assit/Transaction.java b/library/src/main/java/com/litesuits/orm/db/assit/Transaction.java new file mode 100644 index 0000000..34d2b85 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/assit/Transaction.java @@ -0,0 +1,58 @@ +package com.litesuits.orm.db.assit; + +import com.litesuits.orm.log.OrmLog; +import ohos.data.rdb.RdbStore; + +/** + * 辅助事务 + * + * @author mty + * @date 2013 -6-15下午11:09:15 + */ +public class Transaction { + /** + * The constant TAG. + */ + private static final String TAG = Transaction.class.getSimpleName(); + + /** + * 因为每个具体事物都不一样,但又有相同的结构,既要维持代码的统一性,也要可以个性化解析。 + * + * @param the type parameter + * @param db the db + * @param worker the worker + * @return the t + */ + public static T execute(RdbStore db, Worker worker) { + db.beginTransaction(); + OrmLog.i(TAG, "----> BeginTransaction"); + T data = null; + try { + data = worker.doTransaction(db); + db.markAsCommit();//.setTransactionSuccessful(); + if (OrmLog.isPrint) OrmLog.i(TAG, "----> Transaction Successful"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + db.endTransaction(); + } + return data; + } + + /** + * The interface Worker. + * + * @param the type parameter + */ + public interface Worker { + /** + * Do transaction t. + * + * @param db the db + * @return the t + * @throws Exception the exception + */ + T doTransaction(RdbStore db) throws Exception; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/assit/WhereBuilder.java b/library/src/main/java/com/litesuits/orm/db/assit/WhereBuilder.java new file mode 100644 index 0000000..adb1b6b --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/assit/WhereBuilder.java @@ -0,0 +1,413 @@ +package com.litesuits.orm.db.assit; + +import com.litesuits.orm.db.TableManager; + +/** + * The type Where builder. + * + * @author MaTianyu + * @date 2015 -03-18 + */ +public class WhereBuilder { + /** + * The constant NOTHING. + */ + private static final String NOTHING = ""; + /** + * The constant WHERE. + */ + private static final String WHERE = " WHERE "; + /** + * The constant EQUAL_HOLDER. + */ + private static final String EQUAL_HOLDER = "=?"; + /** + * The constant NOT_EQUAL_HOLDER. + */ + private static final String NOT_EQUAL_HOLDER = "!=?"; + /** + * The constant GREATER_THAN_HOLDER. + */ + private static final String GREATER_THAN_HOLDER = ">?"; + /** + * The constant LESS_THAN_HOLDER. + */ + private static final String LESS_THAN_HOLDER = " ? " + * + * @param column the column + * @param value the value + * @return the where builder + */ + public WhereBuilder greaterThan(String column, Object value) { + return this.append(null, column + GREATER_THAN_HOLDER, value); + } + + /** + * build as " column < ? " + * + * @param column the column + * @param value the value + * @return the where builder + */ + public WhereBuilder lessThan(String column, Object value) { + return this.append(null, column + LESS_THAN_HOLDER, value); + } + + /** + * build as " column = ? " + * + * @param column the column + * @param value the value + * @return the where builder + */ + public WhereBuilder equals(String column, Object value) { + return this.append(null, column + EQUAL_HOLDER, value); + } + + /** + * build as " or column = ? " + * + * @param column the column + * @param value the value + * @return the where builder + */ + public WhereBuilder orEquals(String column, Object value) { + return this.append(OR, column + EQUAL_HOLDER, value); + } + + /** + * build as " and column = ? " + * + * @param column the column + * @param value the value + * @return the where builder + */ + public WhereBuilder andEquals(String column, Object value) { + return this.append(AND, column + EQUAL_HOLDER, value); + } + + /** + * build as " column in(?,?...) " + * + * @param column the column + * @param values the values + * @return the where builder + */ + public WhereBuilder in(String column, Object... values) { + return this.append(null, WhereBuilder.buildWhereIn(column, values.length), values); + } + + /** + * build as " or column in(?,?...) " + * + * @param column the column + * @param values the values + * @return the where builder + */ + public WhereBuilder orIn(String column, Object... values) { + return this.append(OR, WhereBuilder.buildWhereIn(column, values.length), values); + } + + /** + * build as " and column in(?,?...) " + * + * @param column the column + * @param values the values + * @return the where builder + */ + public WhereBuilder andIn(String column, Object... values) { + return this.append(AND, WhereBuilder.buildWhereIn(column, values.length), values); + } + + /** + * Append where builder. + * + * @param connect NULL or " AND " or " OR " or " NOT " + * @param whereString "id = ?"; or "id in(?,?,?)"; or "id LIKE %?"; ... + * @param value new String[]{"",""}; or new Integer[]{1,2}; ... + * @return this where builder + */ + public WhereBuilder append(String connect, String whereString, Object... value) { + if (this.where == null) { + this.where = whereString; + this.whereArgs = value; + } else { + if (connect != null) this.where += connect; + this.where += whereString; + if (this.whereArgs == null) this.whereArgs = value; + else { + Object[] newWhere = new Object[this.whereArgs.length + value.length]; + System.arraycopy(this.whereArgs, 0, newWhere, 0, this.whereArgs.length); + System.arraycopy(value, 0, newWhere, this.whereArgs.length, value.length); + this.whereArgs = newWhere; + } + } + return this; + } + + /** + * Trans to string array string [ ]. + * + * @return the string [ ] + */ + String[] transToStringArray() { + if (this.whereArgs != null && this.whereArgs.length > 0) { + if (this.whereArgs instanceof String[]) return (String[]) this.whereArgs; + String[] arr = new String[this.whereArgs.length]; + for (int i = 0; i < arr.length; i++) arr[i] = String.valueOf(this.whereArgs[i]); + return arr; + } + return null; + } + + /** + * Create where string string. + * + * @return the string + */ + String createWhereString() { + if (this.where != null) return WHERE + this.where; + else return NOTHING; + } + + /** + * Create statement delete sql statement. + * + * @return the sql statement + */ + public SQLStatement createStatementDelete() { + SQLStatement stmt = new SQLStatement(); + stmt.sql = DELETE + TableManager.getTableName(this.tableClass) + this.createWhereString(); + stmt.bindArgs = this.transToStringArray(); + return stmt; + } + + /** + * Gets where. + * + * @return the where + */ + public String getWhere() { + return this.where; + } + + /** + * Sets where. + * + * @param where the where + */ + public void setWhere(String where) { + this.where = where; + } + + /** + * Get where args object [ ]. + * + * @return the object [ ] + */ + Object[] getWhereArgs() { + return this.whereArgs; + } + + /** + * Sets where args. + * + * @param whereArgs the where args + */ + public void setWhereArgs(Object[] whereArgs) { + this.whereArgs = whereArgs; + } +} diff --git a/library/src/main/java/com/litesuits/orm/db/enums/AssignType.java b/library/src/main/java/com/litesuits/orm/db/enums/AssignType.java new file mode 100644 index 0000000..4b8c4b9 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/enums/AssignType.java @@ -0,0 +1,19 @@ +package com.litesuits.orm.db.enums; + +/** + * The enum Assign type. + * + * @author MaTianyu + * @date 2014 -08-16 + */ +public enum AssignType { + /** + * 主键值自己来指定。 + */ + BY_MYSELF, + /** + * 主键值由系统分配,系统将使用自动递增整数赋值给主键。 + * 系统将从1开始递增分配,每次在上一条最大ID上+1 。 + */ + AUTO_INCREMENT +} \ No newline at end of file diff --git a/library/src/main/java/com/litesuits/orm/db/enums/Relation.java b/library/src/main/java/com/litesuits/orm/db/enums/Relation.java new file mode 100644 index 0000000..6a25654 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/enums/Relation.java @@ -0,0 +1,23 @@ +package com.litesuits.orm.db.enums; + +/** + * The enum Relation. + */ +public enum Relation { + /** + * Many to many relation. + */ + ManyToMany, + /** + * One to many relation. + */ + OneToMany, + /** + * Many to one relation. + */ + ManyToOne, + /** + * One to one relation. + */ + OneToOne +} \ No newline at end of file diff --git a/library/src/main/java/com/litesuits/orm/db/enums/Strategy.java b/library/src/main/java/com/litesuits/orm/db/enums/Strategy.java new file mode 100644 index 0000000..de1ddc5 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/enums/Strategy.java @@ -0,0 +1,50 @@ +package com.litesuits.orm.db.enums; + +/** + * The enum Strategy. + */ +public enum Strategy { + /** + * Rollback strategy. + */ + ROLLBACK(" ROLLBACK "), + /** + * Abort strategy. + */ + ABORT(" ABORT "), + /** + * Fail strategy. + */ + FAIL(" FAIL "), + /** + * Ignore strategy. + */ + IGNORE(" IGNORE "), + /** + * Replace strategy. + */ + REPLACE(" REPLACE "); + + /** + * The Sql. + */ + public String sql; + + /** + * Instantiates a new Strategy. + * + * @param sql the sql + */ + Strategy(String sql) { + this.sql = sql; + } + + /** + * Gets sql. + * + * @return the sql + */ + public String getSql() { + return this.sql; + } +} \ No newline at end of file diff --git a/library/src/main/java/com/litesuits/orm/db/impl/CascadeSQLiteImpl.java b/library/src/main/java/com/litesuits/orm/db/impl/CascadeSQLiteImpl.java new file mode 100644 index 0000000..5c093a7 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/impl/CascadeSQLiteImpl.java @@ -0,0 +1,1194 @@ +package com.litesuits.orm.db.impl; + +import com.litesuits.orm.LiteOrm; +import com.litesuits.orm.db.DataBaseConfig; +import com.litesuits.orm.db.TableManager; +import com.litesuits.orm.db.assit.*; +import com.litesuits.orm.db.assit.Transaction.Worker; +import com.litesuits.orm.db.model.*; +import com.litesuits.orm.db.utils.ClassUtil; +import com.litesuits.orm.db.utils.DataUtil; +import com.litesuits.orm.db.utils.FieldUtil; +import ohos.data.rdb.RdbStore; +import ohos.data.resultset.ResultSet; + +import java.lang.reflect.Field; +import java.util.*; + +/** + * 数据SQLite操作关联实现 + * 可查阅 SQLite操作指南 + * + * @author MaTianyu + * @date 2015 -03-13 + */ +public final class CascadeSQLiteImpl extends LiteOrm { + + /** + * The constant TAG. + */ + public static final String TAG = CascadeSQLiteImpl.class.getSimpleName(); + /** + * The constant TYPE_INSERT. + */ + /* -------------------------------- 私有方法:增删改相关 -------------------------------- */ + private static final int TYPE_INSERT = 1; + /** + * The constant TYPE_UPDATE. + */ + private static final int TYPE_UPDATE = 2; + /** + * The constant TYPE_DELETE. + */ + private static final int TYPE_DELETE = 3; + + /** + * Instantiates a new Cascade sq lite. + * + * @param dataBase the data base + */ + CascadeSQLiteImpl(LiteOrm dataBase) { + super(dataBase); + } + + /** + * Instantiates a new Cascade sq lite. + * + * @param config the config + */ + private CascadeSQLiteImpl(DataBaseConfig config) { + super(config); + } + + /** + * New instance lite orm. + * + * @param config the config + * @return the lite orm + */ + public synchronized static LiteOrm newInstance(DataBaseConfig config) { + return new CascadeSQLiteImpl(config); + } + + /** + * 获取被删除对象的参数 + * + * @param entity the entity + * @return the object [ ] + * @throws IllegalAccessException the illegal access exception + */ + private static Object[] getDeleteStatementArgs(Object entity) throws IllegalAccessException { + EntityTable table = TableManager.getTable(entity); + if (table.key != null) return new String[]{String.valueOf(FieldUtil.get(table.key.field, entity))}; + else if (!Checker.isEmpty(table.pmap)) { + Object[] args = new Object[table.pmap.size()]; + int i = 0; + for (Property p : table.pmap.values()) args[i++] = FieldUtil.get(p.field, entity); + return args; + } + return null; + } + + /** + * Single lite orm. + * + * @return the lite orm + */ + @Override + public LiteOrm single() { + if (this.otherDatabase == null) this.otherDatabase = new SingleSQLiteImpl(this); + return this.otherDatabase; + } + + /** + * Cascade lite orm. + * + * @return the lite orm + */ + @Override + public LiteOrm cascade() { + return this; + } + + /** + * Save long. + * + * @param entity the entity + * @return the long + */ + @Override + public long save(Object entity) { +// acquireReference(); + try { +// SQLiteDatabase db = mHelper.getWritableDatabase(); + RdbStore db = this.mHelper.getRdbStore(); + Long rowID = Transaction.execute(db, new Worker() { + @Override + public Long doTransaction(RdbStore db) throws Exception { + HashMap handleMap = new HashMap(); + return CascadeSQLiteImpl.this.checkTableAndSaveRecursive(entity, db, handleMap); + } + }); + return rowID == null ? SQLStatement.NONE : rowID; + } finally { +// releaseReference(); + } + } + + /** + * Save int. + * + * @param the type parameter + * @param collection the collection + * @return the int + */ + @Override + public int save(Collection collection) { +// acquireReference(); + try { + return this.saveCollection(collection); + } finally { +// releaseReference(); + } + } + + /** + * Insert long. + * + * @param entity the entity + * @return the long + */ + @Override + public long insert(Object entity) { + return this.insert(entity, null); + } + + /** + * Insert long. + * + * @param entity the entity + * @param conflictAlgorithm the conflict algorithm + * @return the long + */ + @Override + public long insert(Object entity, ConflictAlgorithm conflictAlgorithm) { +// acquireReference(); + try { + RdbStore db = this.mHelper.getRdbStore();//.getWritableDatabase(); + Long rowID = Transaction.execute(db, new Worker() { + @Override + public Long doTransaction(RdbStore db) throws Exception { + CascadeSQLiteImpl.this.mTableManager.checkOrCreateTable(db, entity); + return CascadeSQLiteImpl.this.insertRecursive(SQLBuilder.buildInsertSql(entity, conflictAlgorithm), + entity, db, new HashMap()); + } + }); + return rowID == null ? SQLStatement.NONE : rowID; + } catch (Exception e) { + e.printStackTrace(); + } finally { +// releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Insert int. + * + * @param the type parameter + * @param collection the collection + * @return the int + */ + @Override + public int insert(Collection collection) { + return this.insert(collection, null); + } + + /** + * Insert int. + * + * @param the type parameter + * @param collection the collection + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int insert(Collection collection, ConflictAlgorithm conflictAlgorithm) { + //acquireReference(); + try { + return this.insertCollection(collection, conflictAlgorithm); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Update int. + * + * @param entity the entity + * @return the int + */ + @Override + public int update(Object entity) { + return this.update(entity, null, null); + } + + /** + * Update int. + * + * @param entity the entity + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int update(Object entity, ConflictAlgorithm conflictAlgorithm) { + return this.update(entity, null, conflictAlgorithm); + } + + /** + * Update int. + * + * @param entity the entity + * @param cvs the cvs + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int update(Object entity, ColumnsValue cvs, ConflictAlgorithm conflictAlgorithm) { + //acquireReference(); + try { + RdbStore db = this.mHelper.getRdbStore(); + Integer rowID = Transaction.execute(db, new Worker() { + @Override + public Integer doTransaction(RdbStore db) throws Exception { + HashMap handleMap = new HashMap(); + SQLStatement stmt = SQLBuilder.buildUpdateSql(entity, cvs, conflictAlgorithm); + CascadeSQLiteImpl.this.mTableManager.checkOrCreateTable(db, entity); + return CascadeSQLiteImpl.this.updateRecursive(stmt, entity, db, handleMap); + } + }); + return rowID == null ? SQLStatement.NONE : rowID; + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Update int. + * + * @param the type parameter + * @param collection the collection + * @return the int + */ + @Override + public int update(Collection collection) { + return this.update(collection, null, null); + } + + /** + * Update int. + * + * @param the type parameter + * @param collection the collection + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int update(Collection collection, ConflictAlgorithm conflictAlgorithm) { + return this.update(collection, null, conflictAlgorithm); + } + + /** + * Update int. + * + * @param the type parameter + * @param collection the collection + * @param cvs the cvs + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int update(Collection collection, ColumnsValue cvs, ConflictAlgorithm conflictAlgorithm) { + //acquireReference(); + try { + return this.updateCollection(collection, cvs, conflictAlgorithm); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * 主动删除其mapping数据 + * + * @param entity the entity + * @return the int + */ + @Override + public int delete(Object entity) { + //acquireReference(); + try { + RdbStore db = this.mHelper.getRdbStore(); + Integer rowID = Transaction.execute(db, new Worker() { + @Override + public Integer doTransaction(RdbStore db) throws Exception { + HashMap handleMap = new HashMap(); + return CascadeSQLiteImpl.this.checkTableAndDeleteRecursive(entity, db, handleMap); + } + }); + if (rowID != null) return rowID; + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Delete int. + * + * @param the type parameter + * @param claxx the claxx + * @return the int + */ + @Override + public int delete(Class claxx) { + return this.deleteAll(claxx); + } + + /** + * Delete int. + * + * @param the type parameter + * @param collection the collection + * @return the int + */ + @Override + public int delete(Collection collection) { + //acquireReference(); + try { + return this.deleteCollectionIfTableHasCreated(collection); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Delete int. + * + * @param the type parameter + * @param claxx the claxx + * @param where the where + * @return the int + */ + @Override + public int delete(Class claxx, WhereBuilder where) { + //acquireReference(); + try { + EntityTable table = TableManager.getTable(claxx); + List list = this.query(QueryBuilder.create(claxx).columns(new String[]{table.key.column}).where(where)); + this.delete(list); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Delete int. + * + * @param where the where + * @return the int + */ + @Override + public int delete(WhereBuilder where) { + //acquireReference(); + try { + EntityTable table = TableManager.getTable(where.getTableClass()); + List list = this.query(QueryBuilder + .create(where.getTableClass()) + .columns(new String[]{table.key.column}) + .where(where)); + this.deleteCollectionIfTableHasCreated(list); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Delete all int. + * + * @param the type parameter + * @param claxx the claxx + * @return the int + */ + @Override + public int deleteAll(Class claxx) { + //acquireReference(); + try { + EntityTable table = TableManager.getTable(claxx); + List list = this.query(QueryBuilder.create(claxx).columns(new String[]{table.key.column})); + return this.delete(list); + } finally { + //releaseReference(); + } + } + + /** + * 删除从[start,end]的数据 + * 此方法暂不会删除关联映射表里的关系数据 + * + * @param the type parameter + * @param claxx the claxx + * @param start the start + * @param end the end + * @param orderAscColumn the order asc column + * @return the int + */ + @Override + public int delete(Class claxx, long start, long end, String orderAscColumn) { + //acquireReference(); + try { + if (start < 0 || end < start) throw new RuntimeException("start must >=0" + + " and smaller than end"); + if (start != 0) start -= 1; + end = end == Integer.MAX_VALUE ? -1 : end - start; + EntityTable table = TableManager.getTable(claxx); + List list = this.query(QueryBuilder + .create(claxx) + .limit(start + SQLBuilder.COMMA + end) + .appendOrderAscBy(orderAscColumn) + .columns(new String[]{table.key.column})); + return this.delete(list); + } finally { + //releaseReference(); + } + } + + /* -------------------------------- 私有方法: 查询相关 -------------------------------- */ + + /** + * Query array list. + * + * @param the type parameter + * @param claxx the claxx + * @return the array list + */ + @Override + public ArrayList query(Class claxx) { + return this.checkTableAndQuery(claxx, new QueryBuilder(claxx)); + } + + /** + * Query array list. + * + * @param the type parameter + * @param qb the qb + * @return the array list + */ + @Override + public ArrayList query(QueryBuilder qb) { + return this.checkTableAndQuery(qb.getQueryClass(), qb); + } + + /** + * Query by id t. + * + * @param the type parameter + * @param id the id + * @param claxx the claxx + * @return the t + */ + @Override + public T queryById(long id, Class claxx) { + return this.queryById(String.valueOf(id), claxx); + } + + /** + * Query by id t. + * + * @param the type parameter + * @param id the id + * @param claxx the claxx + * @return the t + */ + @Override + public T queryById(String id, Class claxx) { + EntityTable table = TableManager.getTable(claxx); + ArrayList list = this.checkTableAndQuery(claxx, new QueryBuilder(claxx) + .whereEquals(table.key.column, String.valueOf(id))); + if (!Checker.isEmpty(list)) return list.get(0); + return null; + } + + /* -------------------------------- 私有方法: 集合操作相关 -------------------------------- */ + + /** + * 过程: + *

+ * 1. 根据条件查找符合条件的所有当前对象 + * 2. 遍历所有当前对象,遍历其所有关联对象,读取关系表 map: + * 3. 如果是多对一,根据map查找key2的关联对象,赋给obj1 + * 4. 如果是一对多,根据map查找key2的关联对象,反射实例化obj1的容器,关联对象放入。 + * 5. 并对关联对象递归此过程 + * + * @param the type parameter + * @param claxx the claxx + * @param builder the builder + * @return the array list + */ + private ArrayList checkTableAndQuery(Class claxx, QueryBuilder builder) { + //acquireReference(); + ArrayList list = new ArrayList(); + try { + EntityTable table = TableManager.getTable(claxx, false); + if (this.mTableManager.isSQLTableCreated(table.name)) { + HashMap entityMap = new HashMap(); + HashMap queryMap = new HashMap(); + RdbStore db = this.mHelper.getRdbStore();//.getReadableDatabase(); + Querier.doQuery(db, builder.createStatement(), new Querier.CursorParser() { + @Override + public void parseEachCursor(RdbStore db, ResultSet c) throws Exception { + T t = ClassUtil.newInstance(claxx); + DataUtil.injectDataToObject(c, t, table); + list.add(t); + entityMap.put(table.name + FieldUtil.get(table.key.field, t), t); + } + }); + for (T t : list) this.queryForMappingRecursive(t, db, queryMap, entityMap); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return list; + } + + /** + * 循环遍历查找当前实体的关联实体 + * + * @param obj1 the obj 1 + * @param db the db + * @param queryMap the query map + * @param entityMap the entity map + * @throws IllegalAccessException the illegal access exception + * @throws InstantiationException the instantiation exception + */ + private void queryForMappingRecursive(Object obj1, RdbStore db, HashMap queryMap, + HashMap entityMap) + throws IllegalAccessException, InstantiationException { + EntityTable table1 = TableManager.getTable(obj1); + Object key1 = FieldUtil.getAssignedKeyObject(table1.key, obj1); + String key = table1.name + key1; + if (queryMap.get(key) == null) { + queryMap.put(key, 1); + if (table1.mappingList != null) for (MapProperty mp : table1.mappingList) + if (mp.isToOne()) this.queryMapToOne(table1, key1, obj1, mp.field, db, queryMap, entityMap); + else if (mp.isToMany()) + this.queryMapToMany(table1, key1, obj1, mp.field, db, queryMap, entityMap); + } + } + + /** + * 查找N对一关系的实体 + * + * @param table1 the table 1 + * @param key1 the key 1 + * @param obj1 the obj 1 + * @param field the field + * @param db the db + * @param queryMap the query map + * @param entityMap the entity map + * @throws IllegalAccessException the illegal access exception + * @throws InstantiationException the instantiation exception + */ + private void queryMapToOne(EntityTable table1, Object key1, Object obj1, + Field field, RdbStore db, HashMap queryMap, + HashMap entityMap) + throws IllegalAccessException, InstantiationException { + EntityTable table2 = TableManager.getTable(field.getType()); + if (this.mTableManager.isSQLMapTableCreated(table1.name, table2.name)) { + SQLStatement relationSql = SQLBuilder.buildQueryRelationSql(table1, table2, key1); + RelationKey relation = new RelationKey(); + Querier.doQuery(db, relationSql, new Querier.CursorParser() { + @Override + public void parseEachCursor(RdbStore db, ResultSet c) throws Exception { + relation.key1 = c.getString(c.getColumnIndexForName(table1.name)); + relation.key2 = c.getString(c.getColumnIndexForName(table2.name)); + this.stopParse(); + } + }); + if (relation.isOK()) { + String key = table2.name + relation.key2; + Object obj2 = entityMap.get(key); + if (obj2 == null) { + SQLStatement entitySql = SQLBuilder.buildQueryMapEntitySql(table2, relation.key2); + obj2 = entitySql.queryOneEntity(db, table2.claxx); + entityMap.put(key, obj2); + } + if (obj2 != null) { + FieldUtil.set(field, obj1, obj2); + this.queryForMappingRecursive(obj2, db, queryMap, entityMap); + } + } + } + } + + /** + * 查找N对关系的实体 + * + * @param table1 the table 1 + * @param key1 the key 1 + * @param obj1 the obj 1 + * @param field the field + * @param db the db + * @param queryMap the query map + * @param entityMap the entity map + * @throws IllegalAccessException the illegal access exception + * @throws InstantiationException the instantiation exception + */ + private void queryMapToMany(EntityTable table1, Object key1, Object obj1, + Field field, RdbStore db, HashMap queryMap, + HashMap entityMap) + throws IllegalAccessException, InstantiationException { + Class class2; + if (Collection.class.isAssignableFrom(field.getType())) class2 = FieldUtil.getGenericType(field); + else if (field.getType().isArray()) class2 = FieldUtil.getComponentType(field); + else + throw new RuntimeException("OneToMany and ManyToMany Relation, " + + "you must use collection or array object"); + EntityTable table2 = TableManager.getTable(class2); + if (this.mTableManager.isSQLMapTableCreated(table1.name, table2.name)) { + SQLStatement relationSql = SQLBuilder.buildQueryRelationSql(table1, table2, key1); + ArrayList key2List = new ArrayList(); + Querier.doQuery(db, relationSql, new Querier.CursorParser() { + @Override + public void parseEachCursor(RdbStore db, ResultSet c) throws Exception { + key2List.add(c.getString(c.getColumnIndexForName(table2.name))); + } + }); + if (!Checker.isEmpty(key2List)) { + ArrayList allList2 = new ArrayList(); + for (int i = key2List.size() - 1; i >= 0; i--) { + Object obj2 = entityMap.get(table2.name + key2List.get(i)); + if (obj2 != null) { + allList2.add(obj2); + key2List.remove(i); + } + } + //final Class class2 = compClass; + int i = 0, start = 0, end; + while (start < key2List.size()) { + int next = ++i * SQLStatement.IN_TOP_LIMIT; + end = Math.min(key2List.size(), next); + List subList = key2List.subList(start, end); + start = next; + + SQLStatement entitySql = QueryBuilder + .create(class2) + .whereIn(table2.key.column, (Object[]) subList.toArray(new String[subList.size()])) + .createStatement(); + + Querier.doQuery(db, entitySql, new Querier.CursorParser() { + @Override + public void parseEachCursor(RdbStore db, ResultSet c) throws Exception { + Object t = ClassUtil.newInstance(class2); + DataUtil.injectDataToObject(c, t, table2); + allList2.add(t); + entityMap.put(table2.name + FieldUtil.get(table2.key.field, t), t); + } + }); + } + if (!Checker.isEmpty(allList2)) { + if (Collection.class.isAssignableFrom(field.getType())) { + Collection coll = (Collection) ClassUtil.newCollectionForField(field); + coll.addAll(allList2); + FieldUtil.set(field, obj1, coll); + } else if (field.getType().isArray()) { + Object[] arrObj = (Object[]) ClassUtil.newArray(class2, allList2.size()); + arrObj = allList2.toArray(arrObj); + FieldUtil.set(field, obj1, arrObj); + } else throw new RuntimeException("OneToMany and ManyToMany Relation, " + + "you must use collection or array object"); + for (Object obj2 : allList2) this.queryForMappingRecursive(obj2, db, queryMap, entityMap); + } + } + } + } + + /** + * 将集合更高效地存储下来 + * + * @param the type parameter + * @param collection any collection + * @return return size of collection if do successfully, -1 or not. + */ + private int saveCollection(Collection collection) { + if (!Checker.isEmpty(collection)) { + RdbStore db = this.mHelper.getRdbStore(); + Integer rowID = Transaction.execute(db, new Worker() { + @Override + public Integer doTransaction(RdbStore db) throws Exception { + //0. 保存第一个实体 + HashMap handleMap = new HashMap(); + Iterator iterator = collection.iterator(); + Object entity = iterator.next(); + SQLStatement stmt = SQLBuilder.buildReplaceSql(entity); + CascadeSQLiteImpl.this.mTableManager.checkOrCreateTable(db, entity); + CascadeSQLiteImpl.this.insertRecursive(stmt, entity, db, handleMap); + + //1.0 保存剩余实体 + while (iterator.hasNext()) { + entity = iterator.next(); + //1.1 绑定对应值 + stmt.bindArgs = SQLBuilder.buildInsertSqlArgsOnly(entity); + //1.2 保存当前实体 + CascadeSQLiteImpl.this.insertRecursive(stmt, entity, db, handleMap); + } + return collection.size(); + } + }); + if (rowID != null) return rowID; + } + return SQLStatement.NONE; + } + + /** + * 将集合更高效地存储下来 + * + * @param the type parameter + * @param collection any collection + * @param conflictAlgorithm when conflict + * @return return size of collection if do successfully, -1 or not. + */ + private int insertCollection(Collection collection, ConflictAlgorithm conflictAlgorithm) { + if (!Checker.isEmpty(collection)) { + RdbStore db = this.mHelper.getRdbStore(); + Integer rowID = Transaction.execute(db, new Worker() { + @Override + public Integer doTransaction(RdbStore db) throws Exception { + //0. 保存第一个实体 + HashMap handleMap = new HashMap(); + Iterator iterator = collection.iterator(); + Object entity = iterator.next(); + SQLStatement stmt = SQLBuilder.buildInsertSql(entity, conflictAlgorithm); + CascadeSQLiteImpl.this.mTableManager.checkOrCreateTable(db, entity); + CascadeSQLiteImpl.this.insertRecursive(stmt, entity, db, handleMap); + + //1.0 保存剩余实体 + while (iterator.hasNext()) { + //1.1 绑定对应值 + entity = iterator.next(); + //1.2 保存当前实体 + stmt.bindArgs = SQLBuilder.buildInsertSqlArgsOnly(entity); + CascadeSQLiteImpl.this.insertRecursive(stmt, entity, db, handleMap); + } + return collection.size(); + } + }); + if (rowID != null) return rowID; + } + return SQLStatement.NONE; + } + + /** + * 将集合更高效地存储下来 + * + * @param the type parameter + * @param collection any collection + * @param cvs the cvs + * @param conflictAlgorithm when conflict + * @return return size of collection if do successfully, -1 or not. + */ + private int updateCollection(Collection collection, ColumnsValue cvs, + ConflictAlgorithm conflictAlgorithm) { + if (!Checker.isEmpty(collection)) { + RdbStore db = this.mHelper.getRdbStore(); + Integer rowID = Transaction.execute(db, new Worker() { + @Override + public Integer doTransaction(RdbStore db) throws Exception { + //0. 保存第一个实体 + HashMap handleMap = new HashMap(); + Iterator iterator = collection.iterator(); + Object entity = iterator.next(); + SQLStatement stmt = SQLBuilder.buildUpdateSql(entity, cvs, conflictAlgorithm); + CascadeSQLiteImpl.this.mTableManager.checkOrCreateTable(db, entity); + CascadeSQLiteImpl.this.updateRecursive(stmt, entity, db, handleMap); + //1.0 保存剩余实体 + while (iterator.hasNext()) { + //1.1 绑定对应值 + entity = iterator.next(); + //1.2 保存当前实体 + stmt.bindArgs = SQLBuilder.buildUpdateSqlArgsOnly(entity, cvs); + CascadeSQLiteImpl.this.updateRecursive(stmt, entity, db, handleMap); + } + return collection.size(); + } + }); + if (rowID != null) return rowID; + } + return SQLStatement.NONE; + } + + /** + * 将集合更高效地删除 + * + * @param the type parameter + * @param collection any collection + * @return return size of collection if do successfully, -1 or not. + */ + private int deleteCollectionIfTableHasCreated(Collection collection) { + if (!Checker.isEmpty(collection)) { + Iterator iterator = collection.iterator(); + Object entity = iterator.next(); + EntityTable table = TableManager.getTable(entity); + if (this.mTableManager.isSQLTableCreated(table.name)) { + RdbStore db = this.mHelper.getRdbStore(); + Integer rowID = Transaction.execute(db, new Worker() { + @Override + public Integer doTransaction(RdbStore db) throws Exception { + //0. 删除第一个实体 + HashMap handleMap = new HashMap(); + SQLStatement stmt = SQLBuilder.buildDeleteSql(entity); + CascadeSQLiteImpl.this.deleteRecursive(stmt, entity, db, handleMap); + + //1.0 删除剩余实体 + while (iterator.hasNext()) { + //1.1 绑定对应值 + Object next = iterator.next(); + //1.2 保存当前实体 + stmt.bindArgs = CascadeSQLiteImpl.getDeleteStatementArgs(next); + CascadeSQLiteImpl.this.deleteRecursive(stmt, next, db, handleMap); + } + return collection.size(); + } + }); + if (rowID != null) return rowID; + } + } + return SQLStatement.NONE; + } + + /** + * 通过递归保存[该对象],以及该对象所有的[关联对象]以及它们的[映射关系] + * + * @param type the type + * @param stmt the stmt + * @param obj1 需要保存的对象 + * @param db 可写数据库对象 + * @param handleMap the handle map + * @return rowID of entity + * @throws Exception the exception + */ + private long handleEntityRecursive(int type, SQLStatement stmt, Object obj1, RdbStore db, + HashMap handleMap) throws Exception { + EntityTable table1 = TableManager.getTable(obj1); + Object key1 = FieldUtil.get(table1.key.field, obj1); + + // 0. 若[当前实体]已存储过,不再操作 + if (handleMap.get(table1.name + key1) != null) return SQLStatement.NONE; + // 1. 存储[当前实体] + long rowID = SQLStatement.NONE; + switch (type) { + case TYPE_INSERT: + rowID = stmt.execInsert(db, obj1); + key1 = FieldUtil.get(table1.key.field, obj1); + break; + case TYPE_UPDATE: + rowID = stmt.execUpdate(db); + break; + case TYPE_DELETE: + rowID = stmt.execDelete(db); + break; + default: + + } + handleMap.put(table1.name + key1, 1); + // 2. 存储[关联实体]以及其[关系映射] + boolean insertNew = type != TYPE_DELETE; + this.handleMapping(key1, obj1, db, insertNew, handleMap); + return rowID; + } + + /** + * 通过递归保更新[该对象],保存该对象所有的[关联对象]以及它们的[映射关系] + * + * @param stmt the stmt + * @param obj1 需要保存的对象 + * @param db 可写数据库对象 + * @param handleMap the handle map + * @return rowID of entity + * @throws Exception the exception + */ + private int updateRecursive(SQLStatement stmt, Object obj1, RdbStore db, + HashMap handleMap) throws Exception { + EntityTable table1 = TableManager.getTable(obj1); + Object key1 = FieldUtil.get(table1.key.field, obj1); + + // 0. 若[当前实体]已存储过,不再操作 + if (handleMap.get(table1.name + key1) != null) return SQLStatement.NONE; + // 1. 更新[当前实体] + int rowID = stmt.execUpdate(db); + key1 = FieldUtil.get(table1.key.field, obj1); + handleMap.put(table1.name + key1, 1); + + // 2. 存储[关联实体]以及其[关系映射] + this.handleMapping(key1, obj1, db, true, handleMap); + return rowID; + } + + /** + * 通过递归删除[该对象],以及该对象所有的[关联对象]以及它们的[映射关系] + * + * @param stmt the stmt + * @param obj1 需要保存的对象 + * @param db 可写数据库对象 + * @param handleMap the handle map + * @return rowID of entity + * @throws Exception the exception + */ + private int deleteRecursive(SQLStatement stmt, Object obj1, RdbStore db, + HashMap handleMap) throws Exception { + EntityTable table1 = TableManager.getTable(obj1); + Object key1 = FieldUtil.get(table1.key.field, obj1); + + // 0. 若[当前实体]已删除过,不再操作 + if (handleMap.get(table1.name + key1) != null) return SQLStatement.NONE; + // 1. 删除[当前实体] + int rowID = stmt.execDelete(db); + handleMap.put(table1.name + key1, 1); + + // 2. 删除[关联实体]以及其[关系映射] + this.handleMapping(key1, obj1, db, false, handleMap); + return rowID; + } + + /** + * 通过递归保存[该对象],以及该对象所有的[关联对象]以及它们的[映射关系] + * + * @param stmt the stmt + * @param obj1 需要保存的对象 + * @param db 可写数据库对象 + * @param handleMap the handle map + * @return rowID of entity + * @throws Exception the exception + */ + private long insertRecursive(SQLStatement stmt, Object obj1, RdbStore db, + HashMap handleMap) throws Exception { + EntityTable table1 = TableManager.getTable(obj1); + Object key1 = FieldUtil.get(table1.key.field, obj1); + + // 0. 若[当前实体]已存储过,不再操作 + if (handleMap.get(table1.name + key1) != null) return SQLStatement.NONE; + // 1. 存储[当前实体] + long rowID = stmt.execInsert(db, obj1); + key1 = FieldUtil.get(table1.key.field, obj1); + handleMap.put(table1.name + key1, 1); + + + // 2. 存储[关联实体]以及其[关系映射] + this.handleMapping(key1, obj1, db, true, handleMap); + return rowID; + } + + /* -------------------------------- 私有方法:处理关系 -------------------------------- */ + + /** + * 通过递归保存[该对象],以及该对象所有的[关联对象]以及它们的[映射关系] + * + * @param obj1 需要保存的对象 + * @param db 可写数据库对象 + * @param handleMap the handle map + * @return rowID of entity + * @throws Exception the exception + */ + private long checkTableAndSaveRecursive(Object obj1, RdbStore db, HashMap handleMap) + throws Exception { + this.mTableManager.checkOrCreateTable(db, obj1); + return this.insertRecursive(SQLBuilder.buildReplaceSql(obj1), obj1, db, handleMap); + } + + /** + * 通过递归删除[该对象],以及该对象所有的[关联对象]以及它们的[映射关系] + * + * @param obj1 需要保存的对象 + * @param db 可写数据库对象 + * @param handleMap the handle map + * @return rowID of entity + * @throws Exception the exception + */ + private int checkTableAndDeleteRecursive(Object obj1, RdbStore db, + HashMap handleMap) + throws Exception { + EntityTable table = TableManager.getTable(obj1); + if (this.mTableManager.isSQLTableCreated(table.name)) + return this.deleteRecursive(SQLBuilder.buildDeleteSql(obj1), obj1, db, handleMap); + return SQLStatement.NONE; + } + + /** + * 处理一个实体中所有的关联实体。 + * + * @param key1 the key 1 + * @param obj1 the obj 1 + * @param db the db + * @param insertNew the insert new + * @param handleMap the handle map + * @throws Exception the exception + */ + private void handleMapping(Object key1, Object obj1, RdbStore db, + boolean insertNew, HashMap handleMap) + throws Exception { + EntityTable table1 = TableManager.getTable(obj1); + // 2. 存储[关联实体]以及其[关系映射] + if (table1.mappingList != null) for (MapProperty map : table1.mappingList) + if (map.isToOne()) { + // handle , relation. + Object obj2 = FieldUtil.get(map.field, obj1); + EntityTable table2 = TableManager.getTable(map.field.getType()); + this.handleMapToOne(table1, table2, key1, obj2, db, insertNew, handleMap); + } else if (map.isToMany()) { + // hanlde , relation. + Object array = FieldUtil.get(map.field, obj1); + if (ClassUtil.isCollection(map.field.getType())) { + EntityTable table2 = TableManager.getTable(FieldUtil.getGenericType(map.field)); + this.handleMapToMany(table1, table2, key1, (Collection) array, db, insertNew, handleMap); + } else if (ClassUtil.isArray(map.field.getType())) { + EntityTable table2 = TableManager.getTable(FieldUtil.getComponentType(map.field)); + Collection coll = null; + // 一定要强转为(Object[]) + if (array != null) coll = Arrays.asList((Object[]) array); + this.handleMapToMany(table1, table2, key1, coll, db, insertNew, handleMap); + } else + throw new RuntimeException("OneToMany and ManyToMany Relation, you must use collection or array object"); + } + } + + /** + * 处理N对1关系的关联实体 + * + * @param table1 the table 1 + * @param table2 the table 2 + * @param key1 the key 1 + * @param obj2 the obj 2 + * @param db the db + * @param insertNew the insert new + * @param handleMap the handle map + * @throws Exception the exception + */ + private void handleMapToOne(EntityTable table1, EntityTable table2, Object key1, Object obj2, + RdbStore db, boolean insertNew, HashMap handleMap) + throws Exception { + // 注意:先递归处理关联对象(如果其主键无值,可以通过先处理赋值) + // 递归存储[关联实体] + // 递归删除[关联实体] + if (obj2 != null) if (insertNew) this.checkTableAndSaveRecursive(obj2, db, handleMap); + else + this.checkTableAndDeleteRecursive(obj2, db, handleMap); + // 现在处理(当前实体)和(关联对象)的[映射关系] + String mapTableName = TableManager.getMapTableName(table1, table2); + + // 删掉旧的[映射关系] + this.mTableManager.checkOrCreateMappingTable(db, mapTableName, table1.name, table2.name); + SQLStatement st = SQLBuilder.buildMappingDeleteSql(mapTableName, key1, table1); + st.execDelete(db); + + // 存储新的[映射关系] + if (insertNew && obj2 != null) { + Object key2 = FieldUtil.get(table2.key.field, obj2); + st = SQLBuilder.buildMappingToOneSql(mapTableName, key1, key2, table1, table2); + if (st != null) st.execInsert(db); + } + } + + /** + * 处理N对N关系的关联实体 + * + * @param table1 the table 1 + * @param table2 the table 2 + * @param key1 the key 1 + * @param coll the coll + * @param db the db + * @param insertNew the insert new + * @param handleMap the handle map + * @throws Exception the exception + */ + private void handleMapToMany(EntityTable table1, EntityTable table2, Object key1, Collection coll, + RdbStore db, boolean insertNew, HashMap handleMap) + throws Exception { + //ArrayList keyList = new ArrayList(); + //StringBuilder sqlForMap = new StringBuilder(); + //boolean isF = true; + //String key1Str = String.valueOf(key1); + //Class class2 = null; + // 遍历每个关联的实体 + // 注意:先递归处理关联对象(如果其主键无值,可以通过先处理赋值) + // 递归存储[关联实体] + // 递归删除[关联实体] + //if (class2 == null) { + // class2 = obj2.getClass(); + //} + // 提前构造[存储新映射关系]的SQL语句和参数 + //if (insertNew) { + // Object key2 = FieldUtil.get(table2.key.field, obj2); + // if (key2 != null) { + // if (isF) { + // sqlForMap.append(SQLBuilder.TWO_HOLDER); + // isF = false; + // } else { + // sqlForMap.append(SQLBuilder.COMMA).append(SQLBuilder.TWO_HOLDER); + // } + // keyList.add(key1Str); + // keyList.add(String.valueOf(key2)); + // } + //} + if (coll != null) for (Object obj2 : coll) + if (obj2 != null) if (insertNew) this.checkTableAndSaveRecursive(obj2, db, handleMap); + else + this.checkTableAndDeleteRecursive(obj2, db, handleMap); + // 现在处理(当前实体)和(关联对象)的[映射关系] + String tableName = TableManager.getMapTableName(table1, table2); + + // 删掉旧的[映射关系] + this.mTableManager.checkOrCreateMappingTable(db, tableName, table1.name, table2.name); + SQLStatement delSql = SQLBuilder.buildMappingDeleteSql(tableName, key1, table1); + delSql.execDelete(db); + + + // 存储新的[映射关系] + if (insertNew && !Checker.isEmpty(coll)) { + ArrayList sqlList = SQLBuilder.buildMappingToManySql(key1, table1, table2, coll); + if (!Checker.isEmpty(sqlList)) for (SQLStatement sql : sqlList) sql.execInsert(db); + } + + // 存储新的[映射关系] + //if (insertNew && !Checker.isEmpty(keyList)) { + // Object[] args = keyList.toArray(new String[keyList.size()]); + // SQLStatement addSql = new SQLStatement(); + // addSql.sql = SQLBuilder.REPLACE + SQLBuilder.INTO + tableName + // + SQLBuilder.PARENTHESES_LEFT + table1.name + SQLBuilder.COMMA + // + table2.name + SQLBuilder.PARENTHESES_RIGHT + SQLBuilder.VALUES + sqlForMap; + // addSql.bindArgs = args; + // addSql.execInsert(db); + //} + } + +} \ No newline at end of file diff --git a/library/src/main/java/com/litesuits/orm/db/impl/SingleSQLiteImpl.java b/library/src/main/java/com/litesuits/orm/db/impl/SingleSQLiteImpl.java new file mode 100644 index 0000000..971e85d --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/impl/SingleSQLiteImpl.java @@ -0,0 +1,524 @@ +package com.litesuits.orm.db.impl; + +import com.litesuits.orm.LiteOrm; +import com.litesuits.orm.db.DataBaseConfig; +import com.litesuits.orm.db.TableManager; +import com.litesuits.orm.db.assit.*; +import com.litesuits.orm.db.model.ColumnsValue; +import com.litesuits.orm.db.model.ConflictAlgorithm; +import com.litesuits.orm.db.model.EntityTable; +import ohos.data.rdb.RdbStore; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * 数据SQLite操作实现 + * 可查阅 SQLite操作指南 + * + * @author mty + * @date 2013 -6-2下午2:32:56 + */ +public final class SingleSQLiteImpl extends LiteOrm { + + /** + * The constant TAG. + */ + public static final String TAG = SingleSQLiteImpl.class.getSimpleName(); + + /** + * Instantiates a new Single sq lite. + * + * @param dataBase the data base + */ + SingleSQLiteImpl(LiteOrm dataBase) { + super(dataBase); + } + + /** + * Instantiates a new Single sq lite. + * + * @param config the config + */ + private SingleSQLiteImpl(DataBaseConfig config) { + super(config); + } + + + /** + * New instance lite orm. + * + * @param config the config + * @return the lite orm + */ + public synchronized static LiteOrm newInstance(DataBaseConfig config) { + return new SingleSQLiteImpl(config); + } + + /** + * Single lite orm. + * + * @return the lite orm + */ + @Override + public LiteOrm single() { + return this; + } + + /** + * Cascade lite orm. + * + * @return the lite orm + */ + @Override + public LiteOrm cascade() { + if (this.otherDatabase == null) this.otherDatabase = new CascadeSQLiteImpl(this); + return this.otherDatabase; + } + + /** + * Save long. + * + * @param entity the entity + * @return the long + */ + @Override + public long save(Object entity) { + //acquireReference(); + try { + RdbStore db = this.mHelper.getRdbStore(); + this.mTableManager.checkOrCreateTable(db, entity); + return SQLBuilder.buildReplaceSql(entity).execInsert(db, entity); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Save int. + * + * @param the type parameter + * @param collection the collection + * @return the int + */ + @Override + public int save(Collection collection) { + //acquireReference(); + try { + if (!Checker.isEmpty(collection)) { + RdbStore db = this.mHelper.getRdbStore(); + Object entity = collection.iterator().next(); + this.mTableManager.checkOrCreateTable(db, entity); + SQLStatement stmt = SQLBuilder.buildReplaceAllSql(entity); + return stmt.execInsertCollection(db, collection); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Insert long. + * + * @param entity the entity + * @return the long + */ + @Override + public long insert(Object entity) { + return this.insert(entity, null); + } + + /** + * Insert long. + * + * @param entity the entity + * @param conflictAlgorithm the conflict algorithm + * @return the long + */ + @Override + public long insert(Object entity, ConflictAlgorithm conflictAlgorithm) { + //acquireReference(); + try { + RdbStore db = this.mHelper.getRdbStore(); + this.mTableManager.checkOrCreateTable(db, entity); + return SQLBuilder.buildInsertSql(entity, conflictAlgorithm).execInsert(db, entity); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Insert int. + * + * @param the type parameter + * @param collection the collection + * @return the int + */ + @Override + public int insert(Collection collection) { + return this.insert(collection, null); + } + + /** + * Insert int. + * + * @param the type parameter + * @param collection the collection + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int insert(Collection collection, ConflictAlgorithm conflictAlgorithm) { + //acquireReference(); + try { + if (!Checker.isEmpty(collection)) { + RdbStore db = this.mHelper.getRdbStore(); + Object entity = collection.iterator().next(); + SQLStatement stmt = SQLBuilder.buildInsertAllSql(entity, conflictAlgorithm); + this.mTableManager.checkOrCreateTable(db, entity); + return stmt.execInsertCollection(db, collection); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Update int. + * + * @param entity the entity + * @return the int + */ + @Override + public int update(Object entity) { + return this.update(entity, null, null); + } + + /** + * Update int. + * + * @param entity the entity + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int update(Object entity, ConflictAlgorithm conflictAlgorithm) { + return this.update(entity, null, conflictAlgorithm); + } + + /** + * Update int. + * + * @param entity the entity + * @param cvs the cvs + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int update(Object entity, ColumnsValue cvs, ConflictAlgorithm conflictAlgorithm) { + //acquireReference(); + try { + RdbStore db = this.mHelper.getRdbStore(); + this.mTableManager.checkOrCreateTable(db, entity); + return SQLBuilder.buildUpdateSql(entity, cvs, conflictAlgorithm).execUpdate(db); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Update int. + * + * @param the type parameter + * @param collection the collection + * @return the int + */ + @Override + public int update(Collection collection) { + return this.update(collection, null, null); + } + + /** + * Update int. + * + * @param the type parameter + * @param collection the collection + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int update(Collection collection, ConflictAlgorithm conflictAlgorithm) { + return this.update(collection, null, conflictAlgorithm); + } + + /** + * Update int. + * + * @param the type parameter + * @param collection the collection + * @param cvs the cvs + * @param conflictAlgorithm the conflict algorithm + * @return the int + */ + @Override + public int update(Collection collection, ColumnsValue cvs, ConflictAlgorithm conflictAlgorithm) { + //acquireReference(); + try { + if (!Checker.isEmpty(collection)) { + RdbStore db = this.mHelper.getRdbStore(); + Object entity = collection.iterator().next(); + this.mTableManager.checkOrCreateTable(db, entity); + SQLStatement stmt = SQLBuilder.buildUpdateAllSql(entity, cvs, conflictAlgorithm); + return stmt.execUpdateCollection(db, collection, cvs); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Delete int. + * + * @param entity the entity + * @return the int + */ + @Override + public int delete(Object entity) { + EntityTable table = TableManager.getTable(entity); + //acquireReference(); + if (this.mTableManager.isSQLTableCreated(table.name)) try { + RdbStore db = this.mHelper.getRdbStore(); + return SQLBuilder.buildDeleteSql(entity).execDelete(db); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Delete int. + * + * @param the type parameter + * @param claxx the claxx + * @return the int + */ + @Override + public int delete(Class claxx) { + return this.deleteAll(claxx); + } + + /** + * Delete int. + * + * @param the type parameter + * @param collection the collection + * @return the int + */ + @Override + public int delete(Collection collection) { + //acquireReference(); + try { + if (!Checker.isEmpty(collection)) { + EntityTable table = TableManager.getTable(collection.iterator().next()); + if (this.mTableManager.isSQLTableCreated(table.name)) { + int rows; + RdbStore db = this.mHelper.getRdbStore(); + db.beginTransaction(); + try { + rows = CollSpliter.split(collection, SQLStatement.IN_TOP_LIMIT, new CollSpliter.Spliter() { + @Override + public int oneSplit(ArrayList list) throws Exception { + return SQLBuilder.buildDeleteSql(list).execDeleteCollection(db, list); + } + }); + db.markAsCommit();//.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + return rows; + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Delete int. + * + * @param the type parameter + * @param claxx the claxx + * @param where the where + * @return the int + */ + @Override + @Deprecated + public int delete(Class claxx, WhereBuilder where) { + return this.delete(where); + } + + /** + * Delete int. + * + * @param where the where + * @return the int + */ + @Override + public int delete(WhereBuilder where) { + EntityTable table = TableManager.getTable(where.getTableClass(), false); + //acquireReference(); + if (this.mTableManager.isSQLTableCreated(table.name)) try { + RdbStore db = this.mHelper.getRdbStore(); + return where.createStatementDelete().execDelete(db); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Delete all int. + * + * @param the type parameter + * @param claxx the claxx + * @return the int + */ + @Override + public int deleteAll(Class claxx) { + EntityTable table = TableManager.getTable(claxx, false); + //acquireReference(); + if (this.mTableManager.isSQLTableCreated(table.name)) try { + RdbStore db = this.mHelper.getRdbStore(); + SQLStatement stmt = SQLBuilder.buildDeleteAllSql(claxx); + return stmt.execDelete(db); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * 删除从[start,end]的数据 + * + * @param the type parameter + * @param claxx the claxx + * @param start the start + * @param end the end + * @param orderAscColumn the order asc column + * @return the int + */ + @Override + public int delete(Class claxx, long start, long end, String orderAscColumn) { + EntityTable table = TableManager.getTable(claxx, false); + //acquireReference(); + if (this.mTableManager.isSQLTableCreated(table.name)) try { + if (start < 0 || end < start) throw new RuntimeException("start must >=0 and smaller than end"); + if (start != 0) start -= 1; + end = end == Integer.MAX_VALUE ? -1 : end - start; + SQLStatement stmt = SQLBuilder.buildDeleteSql(claxx, start, end, orderAscColumn); + RdbStore db = this.mHelper.getRdbStore(); + return stmt.execDelete(db); + } catch (Exception e) { + e.printStackTrace(); + } finally { + //releaseReference(); + } + return SQLStatement.NONE; + } + + /** + * Query array list. + * + * @param the type parameter + * @param claxx the claxx + * @return the array list + */ + @Override + public ArrayList query(Class claxx) { + return this.query(new QueryBuilder(claxx)); + } + + /** + * Query array list. + * + * @param the type parameter + * @param qb the qb + * @return the array list + */ + @Override + public ArrayList query(QueryBuilder qb) { + EntityTable table = TableManager.getTable(qb.getQueryClass(), false); + //acquireReference(); + if (this.mTableManager.isSQLTableCreated(table.name)) try { + return qb.createStatement().query(this.mHelper.getRdbStore(), qb.getQueryClass()); + } finally { + //releaseReference(); + } + else return new ArrayList(); + } + + /** + * Query by id t. + * + * @param the type parameter + * @param id the id + * @param claxx the claxx + * @return the t + */ + @Override + public T queryById(long id, Class claxx) { + return this.queryById(String.valueOf(id), claxx); + } + + /** + * Query by id t. + * + * @param the type parameter + * @param id the id + * @param claxx the claxx + * @return the t + */ + @Override + public T queryById(String id, Class claxx) { + EntityTable table = TableManager.getTable(claxx, false); + //acquireReference(); + if (this.mTableManager.isSQLTableCreated(table.name)) try { + SQLStatement stmt = new QueryBuilder(claxx) + .where(table.key.column + "=?", id) + .createStatement(); + ArrayList list = stmt.query(this.mHelper.getRdbStore(), claxx); + if (!Checker.isEmpty(list)) return list.get(0); + } finally { + //releaseReference(); + } + return null; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/model/ColumnsValue.java b/library/src/main/java/com/litesuits/orm/db/model/ColumnsValue.java new file mode 100644 index 0000000..61191d8 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/model/ColumnsValue.java @@ -0,0 +1,104 @@ +package com.litesuits.orm.db.model; + +import com.litesuits.orm.db.assit.Checker; + +import java.util.HashMap; +import java.util.Map; + +/** + * help to build custom column value + * {@link #columns}不能为NULL,你的SQL语句仅仅对在这个数组里面的列起作用。比如update,只更新这里面的列。 + * 列名column为map的key,key对应的value是强制赋给这个列对应的值. + * 如果列column对应的value不为null,那么将会使用这里面的值优先写入数据库. + * 如果列column对应的value为null,那么将会把实体该字段最新的值写入数据库. + * + * @author MaTianyu 2014-8-7 + */ +public class ColumnsValue { + + /** + * your sql only affect column in this {@link #columns}. + */ + public String[] columns; + + /** + * can be null, if not this will mapping with {@link #columns} 1 by 1. + * if not null, your columns well aways set value in {@link #values}. + */ +//private Object[] values; + + private Map map = new HashMap(); + + /** + * Instantiates a new Columns value. + * + * @param map the map + */ + public ColumnsValue(Map map) { + if (!Checker.isEmpty(map)) { + this.columns = new String[map.size()]; + //values = new Object[map.size()]; + int i = 0; + for (Map.Entry entry : map.entrySet()) { + this.columns[i] = entry.getKey(); + //values[i] = entry.getValue(); + i++; + } + this.map = map; + } + } + + /** + * Instantiates a new Columns value. + * + * @param columns the columns + */ + public ColumnsValue(String[] columns) { + this.columns = columns; + for (String key : columns) this.map.put(key, null); + } + + /** + * Instantiates a new Columns value. + * + * @param columns the columns + * @param values the values + */ + public ColumnsValue(String[] columns, Object[] values) { + this.columns = columns; + //this.values = values; + if (values != null) { + if (columns.length != values.length) + throw new IllegalArgumentException("length of columns and values must be the same"); + int i = 0; + for (String key : columns) this.map.put(key, values[i++]); + } else for (String key : columns) this.map.put(key, null); + } + + /** + * Check columns boolean. + * + * @return the boolean + */ + public boolean checkColumns() { + if (this.columns == null) throw new IllegalArgumentException("columns must not be null"); + //else if (values != null && columns.length != values.length) { + // throw new IllegalArgumentException("length of columns and values must be the same"); + //} + return true; + } + + /** + * value 存在,强制更新使用value里面的值, + * value 不存在,更新entity最新值。 + * + * @param key the key + * @return the value + */ +//public boolean hasValues() { + // return values != null; + //} + public Object getValue(String key) { + return this.map.get(key); + } +} diff --git a/library/src/main/java/com/litesuits/orm/db/model/ConflictAlgorithm.java b/library/src/main/java/com/litesuits/orm/db/model/ConflictAlgorithm.java new file mode 100644 index 0000000..5b45ca1 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/model/ConflictAlgorithm.java @@ -0,0 +1,84 @@ +package com.litesuits.orm.db.model; + +/** + * The enum Conflict algorithm. + * + * @date 2014 -08-07 + */ +public enum ConflictAlgorithm { + /** + * The algorithm specified in the OR clause of an INSERT or UPDATE overrides + * any algorithm specified in a CREATE TABLE. If no algorithm is specified + * anywhere, the ABORT algorithm is used. + */ + None(" "), + /** + * When an applicable constraint violation occurs, the ROLLBACK resolution + * algorithm aborts the current SQL statement with an SQLITE_CONSTRAINT + * error and rolls back the current transaction. If no transaction is active + * (other than the implied transaction that is created on every command) + * then the ROLLBACK resolution algorithm works the same as the ABORT algorithm. + */ + Rollback(" OR ROLLBACK "), + /** + * When an applicable constraint violation occurs, the ABORT resolution algorithm + * aborts the current SQL statement with an SQLITE_CONSTRAINT error and backs + * out any changes made by the current SQL statement; but changes caused by + * prior SQL statements within the same transaction are preserved and the + * transaction remains active. This is the default behavior and the behavior + * specified by the SQL standard. + */ + Abort(" OR ABORT "), + /** + * When an applicable constraint violation occurs, the FAIL resolution algorithm + * aborts the current SQL statement with an SQLITE_CONSTRAINT error. But the FAIL + * resolution does not back out prior changes of the SQL statement that failed nor + * does it end the transaction. For example, if an UPDATE statement encountered a + * constraint violation on the 100th row that it attempts to update, then the first + * 99 row changes are preserved but changes to rows 100 and beyond never occur. + */ + Fail(" OR FAIL "), + /** + * When an applicable constraint violation occurs, the IGNORE resolution algorithm + * skips the one row that contains the constraint violation and continues + * processing subsequent rows of the SQL statement as if nothing went wrong. Other + * rows before and after the row that contained the constraint violation are + * inserted or updated normally. No error is returned when the IGNORE conflict + * resolution algorithm is used. + */ + Ignore(" OR IGNORE "), + /** + * When a UNIQUE constraint violation occurs, the REPLACE algorithm deletes + * pre-existing rows that are causing the constraint violation prior to inserting + * or updating the current row and the command continues executing normally. If a + * NOT NULL constraint violation occurs, the REPLACE conflict resolution replaces + * the NULL value with the default value for that column, or if the column has no + * default value, then the ABORT algorithm is used. If a CHECK constraint violation + * occurs, the REPLACE conflict resolution algorithm always works like ABORT. + */ + Replace(" OR REPLACE "); + + /** + * The Algorithm. + */ + private final String algorithm; + + /** + * Instantiates a new Conflict algorithm. + * + * @param algorithm the algorithm + */ + ConflictAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + /** + * Gets algorithm. + * + * @return the algorithm + */ + public String getAlgorithm() { + return this.algorithm; + } +} + diff --git a/library/src/main/java/com/litesuits/orm/db/model/EntityTable.java b/library/src/main/java/com/litesuits/orm/db/model/EntityTable.java new file mode 100644 index 0000000..e1c4f90 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/model/EntityTable.java @@ -0,0 +1,77 @@ +package com.litesuits.orm.db.model; + +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.LinkedHashMap; + +/** + * 实体的表结构 + * + * @author mty + * @date 2013 -6-9上午1:10:48 + */ +public class EntityTable implements Serializable { + /** + * The constant serialVersionUID. + */ + private static final long serialVersionUID = 421721084878061123L; + /** + * 实体对应类 + */ + public Class claxx; + /** + * 实体对应表名 + */ + public String name; + /** + * 主键 + */ + public Primarykey key; + /** + * 属性列表 + */ + public LinkedHashMap pmap; + /** + * N对N 关系映射表 + */ + public ArrayList mappingList; + + /** + * 是否已对该表进行检查 + * + * @param pro the pro + */ +//public boolean isChecked = false; + public void addMapping(MapProperty pro) { + if (this.mappingList == null) this.mappingList = new ArrayList(); + this.mappingList.add(pro); + } + + /** + * Gets annotation. + * + * @param annoClass the anno class + * @return the annotation + */ + public Annotation getAnnotation(Class annoClass) { + if (this.claxx != null) return this.claxx.getAnnotation(annoClass); + return null; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "EntityTable{" + + "claxx=" + this.claxx + + ", name='" + this.name + '\'' + + ", key=" + this.key + + ", pmap=" + this.pmap + + ", mappingList=" + this.mappingList + + '}'; + } +} diff --git a/library/src/main/java/com/litesuits/orm/db/model/MapInfo.java b/library/src/main/java/com/litesuits/orm/db/model/MapInfo.java new file mode 100644 index 0000000..e7e4654 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/model/MapInfo.java @@ -0,0 +1,116 @@ +package com.litesuits.orm.db.model; + +import com.litesuits.orm.db.assit.Checker; +import com.litesuits.orm.db.assit.SQLStatement; + +import java.util.ArrayList; + +/** + * 映射表类 + * + * @author MaTianyu 2014-3-8上午3:20:20 + */ +public class MapInfo { + + /** + * The Table list. + */ + public ArrayList tableList; + /** + * The Map new relation sql. + */ + public ArrayList mapNewRelationSQL; + /** + * The Del old relation sql. + */ + public ArrayList delOldRelationSQL; + + /** + * Add table boolean. + * + * @param table the table + * @return the boolean + */ + public boolean addTable(MapTable table) { + if (table.name == null) return false; + if (this.tableList == null) this.tableList = new ArrayList(); + //for (MapTable mt : tableList) { + // if (mt.name.equals(table.name)) return false; + //} + return this.tableList.add(table); + } + + /** + * Add new relation sql boolean. + * + * @param st the st + * @return the boolean + */ + public boolean addNewRelationSQL(SQLStatement st) { + if (this.mapNewRelationSQL == null) this.mapNewRelationSQL = new ArrayList(); + return this.mapNewRelationSQL.add(st); + } + + /** + * Add new relation sql boolean. + * + * @param list the list + * @return the boolean + */ + public boolean addNewRelationSQL(ArrayList list) { + if (this.mapNewRelationSQL == null) this.mapNewRelationSQL = new ArrayList(); + return this.mapNewRelationSQL.addAll(list); + } + + /** + * Add del old relation sql boolean. + * + * @param st the st + * @return the boolean + */ + public boolean addDelOldRelationSQL(SQLStatement st) { + if (this.delOldRelationSQL == null) this.delOldRelationSQL = new ArrayList(); + return this.delOldRelationSQL.add(st); + } + + /** + * Is empty boolean. + * + * @return the boolean + */ + public boolean isEmpty() { + return Checker.isEmpty(this.tableList) + || Checker.isEmpty(this.mapNewRelationSQL) && Checker.isEmpty(this.delOldRelationSQL); + } + + /** + * The type Map table. + */ + public static class MapTable { + /** + * The Name. + */ + public String name; + /** + * The Column 1. + */ + public String column1; + /** + * The Column 2. + */ + public String column2; + + /** + * Instantiates a new Map table. + * + * @param name the name + * @param col1 the col 1 + * @param col2 the col 2 + */ + public MapTable(String name, String col1, String col2) { + this.name = name; + this.column1 = col1; + this.column2 = col2; + } + } +} \ No newline at end of file diff --git a/library/src/main/java/com/litesuits/orm/db/model/MapProperty.java b/library/src/main/java/com/litesuits/orm/db/model/MapProperty.java new file mode 100644 index 0000000..f6d9121 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/model/MapProperty.java @@ -0,0 +1,66 @@ +package com.litesuits.orm.db.model; + +import com.litesuits.orm.db.enums.Relation; + +import java.lang.reflect.Field; + +/** + * 映射关系 + * + * @author MaTianyu 2014-3-7下午11:16:19 + */ +public class MapProperty extends Property { + /** + * The constant PRIMARYKEY. + */ + public static final String PRIMARYKEY = " PRIMARY KEY "; + /** + * The constant serialVersionUID. + */ + private static final long serialVersionUID = 1641409866866426637L; + /** + * The Relation. + */ + private final Relation relation; + + /** + * Instantiates a new Map property. + * + * @param p the p + * @param relation the relation + */ + public MapProperty(Property p, Relation relation) { + this(p.column, p.field, relation); + } + + /** + * Instantiates a new Map property. + * + * @param column the column + * @param field the field + * @param relation the relation + */ + private MapProperty(String column, Field field, Relation relation) { + super(column, field); + this.relation = relation; + } + + /** + * Is to many boolean. + * + * @return the boolean + */ + public boolean isToMany() { + return this.relation == Relation.ManyToMany || this.relation == Relation.OneToMany; + } + + /** + * Is to one boolean. + * + * @return the boolean + */ + public boolean isToOne() { + return this.relation == Relation.ManyToOne || this.relation == Relation.OneToOne; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/model/Primarykey.java b/library/src/main/java/com/litesuits/orm/db/model/Primarykey.java new file mode 100644 index 0000000..af0d9fb --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/model/Primarykey.java @@ -0,0 +1,65 @@ +package com.litesuits.orm.db.model; + + +import com.litesuits.orm.db.enums.AssignType; + +import java.lang.reflect.Field; + +/** + * 主键 + * + * @author mty + * @date 2013 -6-9上午1:09:33 + */ +public class Primarykey extends Property { + /** + * The constant serialVersionUID. + */ + private static final long serialVersionUID = 2304252505493855513L; + + /** + * The Assign. + */ + public AssignType assign; + + /** + * Instantiates a new Primarykey. + * + * @param p the p + * @param assign the assign + */ + public Primarykey(Property p, AssignType assign) { + this(p.column, p.field, p.classType, assign); + } + + /** + * Instantiates a new Primarykey. + * + * @param column the column + * @param field the field + * @param classType the class type + * @param assign the assign + */ + public Primarykey(String column, Field field, int classType, AssignType assign) { + super(column, field, classType); + this.assign = assign; + } + + /** + * Is assigned by system boolean. + * + * @return the boolean + */ + public boolean isAssignedBySystem() { + return this.assign == AssignType.AUTO_INCREMENT; + } + + /** + * Is assigned by myself boolean. + * + * @return the boolean + */ + public boolean isAssignedByMyself() { + return this.assign == AssignType.BY_MYSELF; + } +} diff --git a/library/src/main/java/com/litesuits/orm/db/model/Property.java b/library/src/main/java/com/litesuits/orm/db/model/Property.java new file mode 100644 index 0000000..171765c --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/model/Property.java @@ -0,0 +1,105 @@ +package com.litesuits.orm.db.model; + +import com.litesuits.orm.db.utils.DataUtil; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Field; + +/** + * 属性 + * + * @author mty + * @date 2013 -6-9上午1:09:17 + */ +public class Property implements Serializable { + + /** + * The constant serialVersionUID. + */ + private static final long serialVersionUID = 1542861322620643038L; + /** + * The Column. + */ + public String column; + /** + * The Field. + */ + public Field field; + /** + * The Class type. + */ + public int classType = DataUtil.CLASS_TYPE_NONE; + + //public Property() { + //} + + /** + * Instantiates a new Property. + * + * @param column the column + * @param field the field + */ + public Property(String column, Field field) { + this.column = column; + this.field = field; + if (this.classType <= 0) this.classType = DataUtil.getFieldClassType(field); + } + + /** + * Instantiates a new Property. + * + * @param column the column + * @param field the field + * @param classType the class type + */ + Property(String column, Field field, int classType) { + this.column = column; + this.field = field; + if (classType <= 0) this.classType = DataUtil.getFieldClassType(field); + this.classType = classType; + } + + /** + * Write object. + * + * @param out the out + * @throws IOException the io exception + */ + private void writeObject(ObjectOutputStream out) throws IOException { + out.writeObject(this.column); + out.writeObject(this.field); + out.writeInt(this.classType); + } + + /** + * Read object. + * + * @param ins the ins + * @throws IOException the io exception + * @throws ClassNotFoundException the class not found exception + */ + private void readObject(ObjectInputStream ins) throws IOException, ClassNotFoundException { + this.column = (String) ins.readObject(); + this.field = (Field) ins.readObject(); + this.classType = ins.readInt(); + } + + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "Property{" + + "column='" + this.column + '\'' + + ", field=" + this.field + + ", classType=" + this.classType + + '}'; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/model/RelationKey.java b/library/src/main/java/com/litesuits/orm/db/model/RelationKey.java new file mode 100644 index 0000000..64032ea --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/model/RelationKey.java @@ -0,0 +1,28 @@ +package com.litesuits.orm.db.model; + +/** + * The type Relation key. + * + * @author MaTianyu + * @date 14 -7-24 + */ +public class RelationKey { + /** + * The Key 1. + */ + public String key1; + /** + * The Key 2. + */ + public String key2; + + /** + * Is ok boolean. + * + * @return the boolean + */ + public boolean isOK() { + return this.key1 != null && this.key2 != null; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/model/SQLiteColumn.java b/library/src/main/java/com/litesuits/orm/db/model/SQLiteColumn.java new file mode 100644 index 0000000..05a6bdc --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/model/SQLiteColumn.java @@ -0,0 +1,61 @@ +package com.litesuits.orm.db.model; + +import com.litesuits.orm.db.annotation.Column; + +import java.io.Serializable; + + +/** + * 列结构 + * + * @author mty + * @date 2013 -6-7上午1:17:49 + */ +public class SQLiteColumn implements Serializable { + /** + * The constant serialVersionUID. + */ + private static final long serialVersionUID = 8822000632819424751L; + /** + * The Name. + */ + @Column("name") + public String name; + /** + * The Type. + */ + @Column("type") + public String type; + /** + * The Cid. + */ + @Column("cid") + private long cid; + /** + * The Notnull. + */ + @Column("notnull") + private short notnull; + /** + * The Dflt value. + */ + @Column("dflt_value") + private String dflt_value; + /** + * The Pk. + */ + @Column("pk") + private short pk; + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "Column [cid=" + this.cid + ", name=" + this.name + ", type=" + this.type + ", notnull=" + this.notnull + ", dflt_value=" + + this.dflt_value + ", pk=" + this.pk + "]"; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/model/SQLiteTable.java b/library/src/main/java/com/litesuits/orm/db/model/SQLiteTable.java new file mode 100644 index 0000000..d36abe7 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/model/SQLiteTable.java @@ -0,0 +1,86 @@ +package com.litesuits.orm.db.model; + +import com.litesuits.orm.db.annotation.Column; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * 表结构,SQLite中的每一张表都有这样的属性。 + * CREATE TABLE sqlite_master ( + *  type TEXT, + *  name TEXT, + *  tbl_name TEXT, + *  rootpage INTEGER, + *  sql TEXT + * ); + * + * @author mty + * @date 2013 -6-2下午11:17:40 + */ +public class SQLiteTable implements Serializable { + /** + * The constant serialVersionUID. + */ + private static final long serialVersionUID = 6706520684759700566L; + + /** + * The Type. + */ + @Column("type") + public String type; + + /** + * The Name. + */ + @Column("name") + public String name; + /** + * The Sql. + */ + @Column("sql") + public String sql = "CREATE TABLE sqlite_master (" + + "  type TEXT," + + "  name TEXT," + + "  tbl_name TEXT," + + "  rootpage INTEGER," + + "  sql TEXT" + + " );"; + /** + * The Is table checked. + */ + public boolean isTableChecked; + /** + * The Columns. + */ + public HashMap columns; + /** + * The Tbl name. + */ + @Column("tbl_name") + private String tbl_name; + /** + * The Rootpage. + */ + @Column("rootpage") + private long rootpage; + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "SQLiteTable{" + + "type='" + this.type + '\'' + + ", name='" + this.name + '\'' + + ", tbl_name='" + this.tbl_name + '\'' + + ", rootpage=" + this.rootpage + + ", sql='" + this.sql + '\'' + + ", isTableChecked=" + this.isTableChecked + + ", columns=" + this.columns + + '}'; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/utils/ClassUtil.java b/library/src/main/java/com/litesuits/orm/db/utils/ClassUtil.java new file mode 100644 index 0000000..24333d6 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/utils/ClassUtil.java @@ -0,0 +1,133 @@ +package com.litesuits.orm.db.utils; + +import com.litesuits.orm.db.annotation.MapCollection; + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.Collection; +import java.util.Date; + +/** + * 类工具 + * + * @author mty + * @date 2013 -6-10下午8:00:46 + */ +public class ClassUtil { + + /** + * 判断类是否是基础数据类型 + * 目前支持11种 + * 在{@link DataUtil#injectDataToObject} 中注入也有体现 + * + * @param clazz the clazz + * @return the boolean + */ + static boolean isBaseDataType(Class clazz) { + return clazz.isPrimitive() || clazz.equals(String.class) || clazz.equals(Boolean.class) + || clazz.equals(Integer.class) || clazz.equals(Long.class) || clazz.equals(Float.class) + || clazz.equals(Double.class) || clazz.equals(Byte.class) || clazz.equals(Character.class) + || clazz.equals(Short.class) || clazz.equals(Date.class) || clazz.equals(byte[].class) + || clazz.equals(Byte[].class); + } + + /** + * 根据类获取对象:不再必须一个无参构造 + * + * @param the type parameter + * @param claxx the claxx + * @return the t + * @throws IllegalAccessException the illegal access exception + * @throws InvocationTargetException the invocation target exception + * @throws InstantiationException the instantiation exception + */ + public static T newInstance(Class claxx) + throws IllegalAccessException, InvocationTargetException, InstantiationException { + Constructor[] cons = claxx.getDeclaredConstructors(); + for (Constructor c : cons) { + Class[] cls = c.getParameterTypes(); + if (cls.length == 0) { + c.setAccessible(true); + return (T) c.newInstance(); + } else { + Object[] objs = new Object[cls.length]; + for (int i = 0; i < cls.length; i++) objs[i] = getDefaultPrimiticeValue(cls[i]); + c.setAccessible(true); + return (T) c.newInstance(objs); + } + } + return null; + } + + /** + * New collection object. + * + * @param claxx the claxx + * @return the object + * @throws IllegalAccessException the illegal access exception + * @throws InstantiationException the instantiation exception + */ + public static Object newCollection(Class claxx) throws IllegalAccessException, InstantiationException { + return claxx.newInstance(); + } + + /** + * New collection for field object. + * + * @param field the field + * @return the object + * @throws IllegalAccessException the illegal access exception + * @throws InstantiationException the instantiation exception + */ + public static Object newCollectionForField(Field field) throws IllegalAccessException, InstantiationException { + MapCollection coll = field.getAnnotation(MapCollection.class); + if (coll == null) return field.getType().newInstance(); + else return coll.value().newInstance(); + } + + /** + * New array object. + * + * @param claxx the claxx + * @param size the size + * @return the object + */ + public static Object newArray(Class claxx, int size) { + return Array.newInstance(claxx, size); + } + + + /** + * Gets default primitice value. + * + * @param clazz the clazz + * @return the default primitice value + */ + private static Object getDefaultPrimiticeValue(Class clazz) { + if (clazz.isPrimitive()) return clazz == boolean.class ? false : 0; + return null; + } + + /** + * Is collection boolean. + * + * @param claxx the claxx + * @return the boolean + */ + public static boolean isCollection(Class claxx) { + return Collection.class.isAssignableFrom(claxx); + } + + /** + * Is array boolean. + * + * @param claxx the claxx + * @return the boolean + */ + public static boolean isArray(Class claxx) { + return claxx.isArray(); + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/utils/DataUtil.java b/library/src/main/java/com/litesuits/orm/db/utils/DataUtil.java new file mode 100644 index 0000000..84b7483 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/utils/DataUtil.java @@ -0,0 +1,395 @@ +package com.litesuits.orm.db.utils; + +import com.litesuits.orm.db.assit.Checker; +import com.litesuits.orm.db.model.EntityTable; +import com.litesuits.orm.db.model.Property; +import com.litesuits.orm.log.OrmLog; +import ohos.data.resultset.ResultSet; + +import java.io.*; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.List; + +/** + * SQLite支持的数据类型 + * 类型描述摘自sqlite官网 http://sqlite.org/datatype3.html + * + * @author mty + * @date 2013 -6-10下午5:28:10 + */ +public class DataUtil implements Serializable { + /** + * NULL. The value is a NULL value. + */ + public static final String NULL = " NULL "; + /** + * INTEGER. The value is a signed integer, stored in 1, 2, 3, 4, 6, or 8 + * bytes depending on the magnitude of the value. + */ + public static final String INTEGER = " INTEGER "; + /** + * TEXT. The value is a text string, stored using the database encoding + * (UTF-8, UTF-16BE or UTF-16LE). + */ + public static final String TEXT = " TEXT "; + /** + * The constant CLASS_TYPE_NONE. + */ + public static final int CLASS_TYPE_NONE = 0; + /** + * The constant TAG. + */ + private static final String TAG = DataUtil.class.getSimpleName(); + /** + * REAL. The value is a floating point value, stored as an 8-byte IEEE + * floating point number. + */ + private static final String REAL = " REAL "; + /** + * BLOB. The value is a blob of data, stored exactly as it was input. + */ + private static final String BLOB = " BLOB "; + /** + * Value returned by {@link #getType(Object)} if the specified column is null + */ + private static final int FIELD_TYPE_NULL = 0; + /** + * Value returned by {@link #getType(Object)} if the specified column type is + * integer or long + */ + private static final int FIELD_TYPE_LONG = 1; + /** + * Value returned by {@link #getType(Object)} if the specified column type is + * float or double + */ + private static final int FIELD_TYPE_REAL = 2; + /** + * Value returned by {@link #getType(Object)} if the specified column type is + * string + */ + private static final int FIELD_TYPE_STRING = 3; + /** + * Value returned by {@link #getType(Object)} if the specified column type is + * blob + */ + private static final int FIELD_TYPE_BLOB = 4; + /** + * Value returned by {@link #getType(Object)} if the specified column type is + * date + */ + private static final int FIELD_TYPE_DATE = 5; + /** + * Value returned by {@link #getType(Object)} if the specified column type is + * serializable + */ + private static final int FIELD_TYPE_SERIALIZABLE = 6; + /** + * The constant CLASS_TYPE_STRING. + */ + private static final int CLASS_TYPE_STRING = 1; + /** + * The constant CLASS_TYPE_BOOLEAN. + */ + private static final int CLASS_TYPE_BOOLEAN = 2; + /** + * The constant CLASS_TYPE_DOUBLE. + */ + private static final int CLASS_TYPE_DOUBLE = 3; + /** + * The constant CLASS_TYPE_FLOAT. + */ + private static final int CLASS_TYPE_FLOAT = 4; + /** + * The constant CLASS_TYPE_LONG. + */ + private static final int CLASS_TYPE_LONG = 5; + /** + * The constant CLASS_TYPE_INT. + */ + private static final int CLASS_TYPE_INT = 6; + /** + * The constant CLASS_TYPE_SHORT. + */ + private static final int CLASS_TYPE_SHORT = 7; + /** + * The constant CLASS_TYPE_BYTE. + */ + private static final int CLASS_TYPE_BYTE = 8; + /** + * The constant CLASS_TYPE_BYTE_ARRAY. + */ + private static final int CLASS_TYPE_BYTE_ARRAY = 9; + /** + * The constant CLASS_TYPE_CHAR. + */ + private static final int CLASS_TYPE_CHAR = 10; + /** + * The constant CLASS_TYPE_DATE. + */ + private static final int CLASS_TYPE_DATE = 11; + /** + * The constant CLASS_TYPE_SERIALIZABLE. + */ + private static final int CLASS_TYPE_SERIALIZABLE = 12; + /** + * The constant CLASS_TYPE_UNKNOWN. + */ + private static final int CLASS_TYPE_UNKNOWN = 13; + /** + * The constant serialVersionUID. + */ + private static final long serialVersionUID = 6668874253056236676L; + + /** + * Returns data type of the given object. + *

+ * Returned column types are + *

    + *
  • {@link #FIELD_TYPE_NULL}
  • + *
  • {@link #FIELD_TYPE_LONG}
  • + *
  • {@link #FIELD_TYPE_REAL}
  • + *
  • {@link #FIELD_TYPE_STRING}
  • + *
  • {@link #FIELD_TYPE_BLOB}
  • + *
  • {@link #FIELD_TYPE_DATE}
  • + *
  • {@link #FIELD_TYPE_SERIALIZABLE}
  • + *
+ *

+ * + * @param obj the obj + * @return the type + */ + public static int getType(Object obj) { + if (obj == null) return FIELD_TYPE_NULL; + else if (obj instanceof CharSequence || obj instanceof Boolean || obj instanceof Character) + return FIELD_TYPE_STRING; + else if (obj instanceof Float || obj instanceof Double) return FIELD_TYPE_REAL; + else if (obj instanceof Number) return FIELD_TYPE_LONG; + else if (obj instanceof Date) return FIELD_TYPE_DATE; + else if (obj instanceof byte[]) return FIELD_TYPE_BLOB; + else if (obj instanceof Serializable) return FIELD_TYPE_SERIALIZABLE; + else return FIELD_TYPE_NULL; + } + + /** + * Gets sql data type. + * + * @param classType the class type + * @return the sql data type + */ + public static String getSQLDataType(int classType) { + switch (classType) { + case CLASS_TYPE_STRING: + case CLASS_TYPE_BOOLEAN: + case CLASS_TYPE_CHAR: + return TEXT; + case CLASS_TYPE_DOUBLE: + case CLASS_TYPE_FLOAT: + return REAL; + case CLASS_TYPE_LONG: + case CLASS_TYPE_INT: + case CLASS_TYPE_SHORT: + case CLASS_TYPE_BYTE: + case CLASS_TYPE_DATE: + return INTEGER; + case CLASS_TYPE_BYTE_ARRAY: + case CLASS_TYPE_SERIALIZABLE: + default: + return BLOB; + } + } + + /** + * 将Cursor的数据注入模型 + * 支持11种基本类型,见{@link ClassUtil#isBaseDataType(Class)} ()} + * 同时支持序列化对象 + * + * @param c 数据库Cursor + * @param entity 实体对象 + * @param table the table + * @throws Exception the exception + */ + public static void injectDataToObject(ResultSet c, Object entity, EntityTable table) throws Exception { + Field f; + Property p; + for (int i = 0, size = c.getColumnCount(); i < size; i++) { + //long start = System.nanoTime(); + + String col = c.getColumnNameForIndex(i); + p = null; + if (!Checker.isEmpty(table.pmap)) p = table.pmap.get(col); + if (p == null && table.key != null && col.equals(table.key.column)) p = table.key; + if (p == null) { + if (OrmLog.isPrint) OrmLog.w(TAG, "数据库字段[" + col + "]已在实体中被移除"); + continue; + } + f = p.field; + f.setAccessible(true); + //Log.i(TAG, "parse pre after " + ((System.nanoTime() - start) / 1000)); + //start = System.nanoTime(); + switch (p.classType) { + case CLASS_TYPE_STRING: +// Log.println("injectDataToObject index:%s ColumnCount:%s RowCount:%s",i,c.getColumnCount(),c.getRowCount()); + f.set(entity, c.getString(i)); + break; + case CLASS_TYPE_BOOLEAN: + f.set(entity, Boolean.parseBoolean(c.getString(i))); + break; + case CLASS_TYPE_LONG: + f.set(entity, c.getLong(i)); + break; + case CLASS_TYPE_INT: + f.set(entity, c.getInt(i)); + break; + case CLASS_TYPE_DOUBLE: + f.set(entity, c.getDouble(i)); + break; + case CLASS_TYPE_FLOAT: + f.set(entity, c.getFloat(i)); + break; + case CLASS_TYPE_SHORT: + f.set(entity, c.getShort(i)); + break; + case CLASS_TYPE_BYTE: + if (c.getString(i) != null) f.set(entity, Byte.parseByte(c.getString(i))); + break; + case CLASS_TYPE_BYTE_ARRAY: + f.set(entity, c.getBlob(i)); + break; + case CLASS_TYPE_CHAR: + String value = c.getString(i); + if (!Checker.isEmpty(value)) f.set(entity, value.charAt(0)); + break; + case CLASS_TYPE_DATE: + Long time = c.getLong(i); + if (time != null) f.set(entity, new Date(time)); + break; + case CLASS_TYPE_SERIALIZABLE: + byte[] bytes = c.getBlob(i); + //序列化的对象 + if (bytes != null) f.set(entity, byteToObject(bytes)); + break; + default: + break; + } + //Log.i(TAG, "parse set after " + ((System.nanoTime() - start) / 1000)); + } + } + + /** + * Gets field class type. + * + * @param f the f + * @return the field class type + */ + public static int getFieldClassType(Field f) { + Class type = f.getType(); + if (CharSequence.class.isAssignableFrom(type)) return CLASS_TYPE_STRING; + else if (boolean.class.isAssignableFrom(type) || Boolean.class.isAssignableFrom(type)) + return CLASS_TYPE_BOOLEAN; + else if (double.class.isAssignableFrom(type) || Double.class.isAssignableFrom(type)) return CLASS_TYPE_DOUBLE; + else if (float.class.isAssignableFrom(type) || Float.class.isAssignableFrom(type)) return CLASS_TYPE_FLOAT; + else if (long.class.isAssignableFrom(type) || Long.class.isAssignableFrom(type)) return CLASS_TYPE_LONG; + else if (int.class.isAssignableFrom(type) || Integer.class.isAssignableFrom(type)) return CLASS_TYPE_INT; + else if (short.class.isAssignableFrom(type) || Short.class.isAssignableFrom(type)) return CLASS_TYPE_SHORT; + else if (byte.class.isAssignableFrom(type) || Byte.class.isAssignableFrom(type)) return CLASS_TYPE_BYTE; + else if (byte[].class.isAssignableFrom(type) || Byte[].class.isAssignableFrom(type)) + return CLASS_TYPE_BYTE_ARRAY; + else if (char.class.isAssignableFrom(type) || Character.class.isAssignableFrom(type)) return CLASS_TYPE_CHAR; + else if (Date.class.isAssignableFrom(type)) return CLASS_TYPE_DATE; + else if (Serializable.class.isAssignableFrom(type)) return CLASS_TYPE_SERIALIZABLE; + return CLASS_TYPE_UNKNOWN; + } + + /** + * byte[] 转为 对象 + * + * @param bytes the bytes + * @return the object + * @throws Exception the exception + */ + private static Object byteToObject(byte[] bytes) throws Exception { + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) { + return ois.readObject(); + } + } + + /** + * 对象 转为 byte[] + * + * @param obj the obj + * @return the byte [ ] + * @throws IOException the io exception + */ + public static byte[] objectToByte(Object obj) throws IOException { + ObjectOutputStream oos = null; + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + oos = new ObjectOutputStream(bos); + oos.writeObject(obj); + return bos.toByteArray(); + } finally { + if (oos != null) oos.close(); + } + } + + + /** + * Array to list list. + * + * @param array the array + * @return the list + */ + public static List arrayToList(Object[] array) { + return Arrays.asList(array); + } + + /** + * Array to list object [ ]. + * + * @param coll the coll + * @return the object [ ] + */ + public static Object[] arrayToList(Collection coll) { + return coll.toArray(); + } + + /** + * Concat t [ ]. + * + * @param the type parameter + * @param first the first + * @param second the second + * @return the t [ ] + */ +// @TargetApi(Build.VERSION_CODES.GINGERBREAD) + public static T[] concat(T[] first, T[] second) { + T[] result = Arrays.copyOf(first, first.length + second.length); + System.arraycopy(second, 0, result, first.length, second.length); + return result; + } + + /** + * Concat all t [ ]. + * + * @param the type parameter + * @param first the first + * @param rest the rest + * @return the t [ ] + */ +// @TargetApi(Build.VERSION_CODES.GINGERBREAD) + public static T[] concatAll(T[] first, T[]... rest) { + int totalLength = first.length; + for (T[] array : rest) totalLength += array.length; + T[] result = Arrays.copyOf(first, totalLength); + int offset = first.length; + for (T[] array : rest) { + System.arraycopy(array, 0, result, offset, array.length); + offset += array.length; + } + return result; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/db/utils/FieldUtil.java b/library/src/main/java/com/litesuits/orm/db/utils/FieldUtil.java new file mode 100644 index 0000000..b9d753f --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/db/utils/FieldUtil.java @@ -0,0 +1,227 @@ +package com.litesuits.orm.db.utils; + +import com.litesuits.orm.db.annotation.Ignore; +import com.litesuits.orm.db.model.Primarykey; + +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.LinkedList; +import java.util.List; + +/** + * 域工具 + * + * @author mty + * @date 2013 -6-10下午6:36:29 + */ +public class FieldUtil { + + /** + * 判断域是否被忽略 + * + * @param f the f + * @return the boolean + */ + private static boolean isIgnored(Field f) { + return f.getAnnotation(Ignore.class) != null; + } + + /** + * 检测非法:static final 或者 加了{@link Ignore} 注解 + * + * @param f the f + * @return the boolean + */ + public static boolean isInvalid(Field f) { + return (Modifier.isStatic(f.getModifiers()) && Modifier.isFinal(f.getModifiers())) + || isIgnored(f) || f.isSynthetic(); + } + + /** + * Is long boolean. + * + * @param field the field + * @return the boolean + */ + public static boolean isLong(Field field) { + return field.getType() == long.class || field.getType() == Long.class; + } + + /** + * Is integer boolean. + * + * @param field the field + * @return the boolean + */ + public static boolean isInteger(Field field) { + return field.getType() == int.class || field.getType() != Integer.class; + } + + /** + * 判断是否序列化 + * + * @param f the f + * @return the boolean + */ + public static boolean isSerializable(Field f) { + Class[] cls = f.getType().getInterfaces(); + for (Class c : cls) if (Serializable.class == c) return true; + return false; + } + + /** + * 设置域的值 + * + * @param f the f + * @param obj the obj + * @param value the value + * @throws IllegalArgumentException the illegal argument exception + * @throws IllegalAccessException the illegal access exception + */ + public static void set(Field f, Object obj, Object value) throws IllegalArgumentException, IllegalAccessException { + f.setAccessible(true); + f.set(obj, value); + } + + /** + * 获取域的值 + * + * @param f the f + * @param obj the obj + * @return the object + * @throws IllegalArgumentException the illegal argument exception + * @throws IllegalAccessException the illegal access exception + */ + public static Object get(Field f, Object obj) throws IllegalArgumentException, IllegalAccessException { + f.setAccessible(true); + return f.get(obj); + } + + /** + * 获取域的泛型类型,如果不带泛型返回null + * + * @param f the f + * @return the generic type + */ + public static Class getGenericType(Field f) { + Type type = f.getGenericType(); + if (type instanceof ParameterizedType) { + type = ((ParameterizedType) type).getActualTypeArguments()[0]; + if (type instanceof Class) return (Class) type; + } else if (type instanceof Class) return (Class) type; + return null; + } + + /** + * 获取数组的类型 + * + * @param f the f + * @return the component type + */ + public static Class getComponentType(Field f) { + return f.getType().getComponentType(); + } + + + /** + * Gets assigned key object. + * + * @param key the key + * @param entity the entity + * @return the assigned key object + * @throws IllegalArgumentException the illegal argument exception + * @throws IllegalAccessException the illegal access exception + */ + public static Object getAssignedKeyObject(Primarykey key, Object entity) throws IllegalArgumentException, + IllegalAccessException { + Object obj = get(key.field, entity); + if (key.isAssignedByMyself() + || (key.isAssignedBySystem() && obj != null && ((Number) obj).longValue() > 0)) return obj; + return null; + } + + /** + * Sets key value ifneed. + * + * @param entity the entity + * @param key the key + * @param keyObj the key obj + * @param rowID the row id + * @return the key value ifneed + * @throws IllegalArgumentException the illegal argument exception + * @throws IllegalAccessException the illegal access exception + */ + public static boolean setKeyValueIfneed(Object entity, Primarykey key, Object keyObj, long rowID) + throws IllegalArgumentException, IllegalAccessException { + if (key != null && key.isAssignedBySystem() + && (keyObj == null || ((Number) keyObj).longValue() < 1)) { + FieldUtil.setNumber(entity, key.field, rowID); + return true; + } + return false; + } + + /** + * Gets all declared fields. + * + * @param claxx the claxx + * @return the all declared fields + */ + public static List getAllDeclaredFields(Class claxx) { + // find all field. + LinkedList fieldList = new LinkedList(); + while (claxx != null && claxx != Object.class) { + Field[] fs = claxx.getDeclaredFields(); + for (int i = 0; i < fs.length; i++) { + Field f = fs[i]; + if (!isInvalid(f)) fieldList.addLast(f); + } + claxx = claxx.getSuperclass(); + } + return fieldList; + } + + /** + * Sets number. + * + * @param o the o + * @param field the field + * @param n the n + * @throws IllegalAccessException the illegal access exception + */ + private static void setNumber(Object o, Field field, long n) throws IllegalAccessException { + field.setAccessible(true); + Class claxx = field.getType(); + if (claxx == long.class) field.setLong(o, n); + else if (claxx == int.class) field.setInt(o, (int) n); + else if (claxx == short.class) field.setShort(o, (short) n); + else if (claxx == byte.class) field.setByte(o, (byte) n); + else if (claxx == Long.class) field.set(o, new Long(n)); + else if (claxx == Integer.class) field.set(o, new Integer((int) n)); + else if (claxx == Short.class) field.set(o, new Short((short) n)); + else if (claxx == Byte.class) field.set(o, new Byte((byte) n)); + else + throw new RuntimeException("field is not a number class"); + } + + /** + * Is number boolean. + * + * @param claxx the claxx + * @return the boolean + */ + public static boolean isNumber(Class claxx) { + return claxx == long.class + || claxx == Long.class + || claxx == int.class + || claxx == Integer.class + || claxx == short.class + || claxx == Short.class + || claxx == byte.class + || claxx == Byte.class; + } + +} diff --git a/library/src/main/java/com/litesuits/orm/kvdb/DataCache.java b/library/src/main/java/com/litesuits/orm/kvdb/DataCache.java new file mode 100644 index 0000000..f7b0885 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/kvdb/DataCache.java @@ -0,0 +1,48 @@ +package com.litesuits.orm.kvdb; + +import java.util.List; + +/** + * 数据操作定义 + * + * @param the type parameter + * @param the type parameter + * @author mty + * @date 2013 -6-2上午2:37:56 + */ +public interface DataCache { + + /** + * Save object. + * + * @param key the key + * @param data the data + * @return the object + */ + Object save(K key, V data); + + /** + * Delete object. + * + * @param key the key + * @return the object + */ + Object delete(K key); + + /** + * Update object. + * + * @param key the key + * @param data the data + * @return the object + */ + Object update(K key, V data); + + /** + * Query list. + * + * @param arg the arg + * @return the list + */ + List query(String arg); +} diff --git a/library/src/main/java/com/litesuits/orm/kvdb/FileDataCahe.java b/library/src/main/java/com/litesuits/orm/kvdb/FileDataCahe.java new file mode 100644 index 0000000..a7cd07b --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/kvdb/FileDataCahe.java @@ -0,0 +1,8 @@ +package com.litesuits.orm.kvdb; + +/** + * The interface File data cahe. + */ +public interface FileDataCahe { + +} diff --git a/library/src/main/java/com/litesuits/orm/log/Log.java b/library/src/main/java/com/litesuits/orm/log/Log.java new file mode 100644 index 0000000..db43f71 --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/log/Log.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2021 Huawei Device Co., Ltd. + */ + +package com.litesuits.orm.log; + +import ohos.hiviewdfx.HiLog; +import ohos.hiviewdfx.HiLogLabel; + +/** + * The type Log. + */ +public class Log { + /** + * The constant MY_TAG. + */ + private static final String MY_TAG = "TZXCL_MY_TAG_" + Log.class.getPackage().getName(); + /** + * The constant LABEL. + */ + private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00234, MY_TAG); + + /** + * E int. + * + * @param tag the tag + * @param log the log + * @param e the e + * @return the int + */ + public static int e(String tag, String log, Throwable e) { + return HiLog.error(LABEL, "Tag:%{public}s - Log:%{public}s - StackTrace:%{public}s", tag, log, HiLog.getStackTrace(e)); + } + + /** + * E int. + * + * @param tag the tag + * @param e the e + * @return the int + */ + public static int e(String tag, Throwable e) { + return HiLog.error(LABEL, "Tag:%{public}s - StackTrace:%{public}s", tag, HiLog.getStackTrace(e)); + } + + /** + * E int. + * + * @param tag the tag + * @param log the log + * @return the int + */ + public static int e(String tag, String log) { + return HiLog.error(LABEL, "Tag:%{public}s - Log:%{public}s", tag, log); + } + + /** + * W int. + * + * @param tag the tag + * @param e the e + * @return the int + */ + public static int w(String tag, Throwable e) { + return HiLog.warn(LABEL, "Tag:%{public}s - StackTrace:%{public}s", tag, HiLog.getStackTrace(e)); + } + + /** + * W int. + * + * @param tag the tag + * @param msg the msg + * @param e the e + * @return the int + */ + static int w(String tag, String msg, Throwable e) { + return HiLog.warn(LABEL, "Tag:%{public}s - %{public}s - StackTrace:%{public}s", tag, msg, HiLog.getStackTrace(e)); + } + + /** + * W int. + * + * @param tag the tag + * @param log the log + * @return the int + */ + public static int w(String tag, String log) { + return HiLog.warn(LABEL, "Tag:%{public}s - Log:%{public}s", tag, log); + } + + /** + * D int. + * + * @param tag the tag + * @param log the log + * @return the int + */ + public static int d(String tag, String log) { + return HiLog.debug(LABEL, "Tag:%{public}s - Log:%{public}s", tag, log); + } + + /** + * D int. + * + * @param tag the tag + * @param log the log + * @param e the e + * @return the int + */ + public static int d(String tag, String log, Throwable e) { + return HiLog.debug(LABEL, "Tag:%{public}s - Log:%{public}s - StackTrace:%{public}s", tag, log, HiLog.getStackTrace(e)); + } + + /** + * int. + * + * @param tag the tag + * @param log the log + * @return the int + */ + public static int i(String tag, String log) { + return HiLog.info(LABEL, "Tag:%{public}s - Log:%{public}s", tag, log); + } + + /** + * int. + * + * @param tag the tag + * @param log the log + * @param e the e + * @return the int + */ + public static int i(String tag, String log, Throwable e) { + return HiLog.info(LABEL, "Tag:%{public}s - Log:%{public}s - StackTrace:%{public}s", tag, log, HiLog.getStackTrace(e)); + } + + /** + * Println. + * + * @param tag the tag + * @param log the log + */ + public static void println(String tag, String log) { + String str; + if (tag.contains("%s")) str = String.format(tag, log); + else str = String.format("Tag:%s - Log:%s", tag, log); + debug(str); + } + + /** + * Println. + * + * @param string the string + * @param args the args + */ + public static void println(String string, Object... args) { + String str = String.format(string, args); + debug(str); + } + + /** + * Debug. + * + * @param log the log + */ + private static void debug(String log) { + System.out.println(MY_TAG + "---" + log); +// XLog.warn(LABEL, log); + } + +} diff --git a/library/src/main/java/com/litesuits/orm/log/OrmLog.java b/library/src/main/java/com/litesuits/orm/log/OrmLog.java new file mode 100644 index 0000000..2e7637f --- /dev/null +++ b/library/src/main/java/com/litesuits/orm/log/OrmLog.java @@ -0,0 +1,285 @@ +package com.litesuits.orm.log; + +/** + * the logger + * + * @author MaTianyu 2014-1-1下午4:05:39 + */ +public final class OrmLog { + + /** + * The constant isPrint. + */ + public static boolean isPrint; + /** + * The constant defaultTag. + */ + private static String defaultTag = "OrmLog"; + + /** + * Instantiates a new Orm log. + */ + private OrmLog() { + } + + /** + * Sets tag. + * + * @param tag the tag + */ + public static void setTag(String tag) { + OrmLog.defaultTag = tag; + } + + /** + * int. + * + * @param o the o + * @return the int + */ + public static int i(Object o) { + return isPrint && o != null ? Log.i(defaultTag, o.toString()) : -1; + } + + /** + * int. + * + * @param m the m + * @return the int + */ + public static int i(String m) { + return isPrint && m != null ? Log.i(defaultTag, m) : -1; + } + + /*********************** Log @param tag the tag + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int v(String tag, String msg) { + return isPrint && msg != null ? Log.i(tag, msg) : -1; + } + + /** + * D int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int d(String tag, String msg) { + return isPrint && msg != null ? Log.d(tag, msg) : -1; + } + + /** + * int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int i(String tag, String msg) { + return isPrint && msg != null ? Log.i(tag, msg) : -1; + } + + /** + * W int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int w(String tag, String msg) { + return isPrint && msg != null ? Log.w(tag, msg) : -1; + } + + /** + * E int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int e(String tag, String msg) { + return isPrint && msg != null ? Log.e(tag, msg) : -1; + } + + /*********************** Log with object list @param tag the tag + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int v(String tag, Object... msg) { + return isPrint ? Log.i(tag, getLogMessage(msg)) : -1; + } + + /** + * D int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int d(String tag, Object... msg) { + return isPrint ? Log.d(tag, getLogMessage(msg)) : -1; + } + + /** + * int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int i(String tag, Object... msg) { + return isPrint ? Log.i(tag, getLogMessage(msg)) : -1; + } + + /** + * W int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int w(String tag, Object... msg) { + return isPrint ? Log.w(tag, getLogMessage(msg)) : -1; + } + + /** + * E int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int e(String tag, Object... msg) { + return isPrint ? Log.e(tag, getLogMessage(msg)) : -1; + } + + /** + * Gets log message. + * + * @param msg the msg + * @return the log message + */ + private static String getLogMessage(Object... msg) { + if (msg != null && msg.length > 0) { + StringBuilder sb = new StringBuilder(); + for (Object s : msg) if (s != null) sb.append(s); + return sb.toString(); + } + return ""; + } + + /*********************** Log with Throwable @param tag the tag + * @param tag the tag + * @param msg the msg + * @param tr the tr + * @return the int + */ + public static int v(String tag, String msg, Throwable tr) { + return isPrint && msg != null ? Log.i(tag, msg, tr) : -1; + } + + /** + * D int. + * + * @param tag the tag + * @param msg the msg + * @param tr the tr + * @return the int + */ + public static int d(String tag, String msg, Throwable tr) { + return isPrint && msg != null ? Log.d(tag, msg, tr) : -1; + } + + /** + * int. + * + * @param tag the tag + * @param msg the msg + * @param tr the tr + * @return the int + */ + public static int i(String tag, String msg, Throwable tr) { + return isPrint && msg != null ? Log.i(tag, msg, tr) : -1; + } + + /** + * W int. + * + * @param tag the tag + * @param msg the msg + * @param tr the tr + * @return the int + */ + public static int w(String tag, String msg, Throwable tr) { + return isPrint && msg != null ? Log.w(tag, msg, tr) : -1; + } + + /** + * E int. + * + * @param tag the tag + * @param msg the msg + * @param tr the tr + * @return the int + */ + public static int e(String tag, String msg, Throwable tr) { + return isPrint && msg != null ? Log.e(tag, msg, tr) : -1; + } + + /*********************** TAG use Object Tag @param tag the tag + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int v(Object tag, String msg) { + return isPrint ? Log.i(tag.getClass().getSimpleName(), msg) : -1; + } + + /** + * D int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int d(Object tag, String msg) { + return isPrint ? Log.d(tag.getClass().getSimpleName(), msg) : -1; + } + + /** + * int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int i(Object tag, String msg) { + return isPrint ? Log.i(tag.getClass().getSimpleName(), msg) : -1; + } + + /** + * W int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int w(Object tag, String msg) { + return isPrint ? Log.w(tag.getClass().getSimpleName(), msg) : -1; + } + + /** + * E int. + * + * @param tag the tag + * @param msg the msg + * @return the int + */ + public static int e(Object tag, String msg) { + return isPrint ? Log.e(tag.getClass().getSimpleName(), msg) : -1; + } +} diff --git a/library/src/main/resources/base/element/resources.json b/library/src/main/resources/base/element/resources.json new file mode 100644 index 0000000..f740532 --- /dev/null +++ b/library/src/main/resources/base/element/resources.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "田梓萱", + "value": "用于简单的数据库链接" + } + ] +} \ No newline at end of file diff --git a/library/src/test/java/com/litesuits/library/ExampleTest.java b/library/src/test/java/com/litesuits/library/ExampleTest.java new file mode 100644 index 0000000..6426bd5 --- /dev/null +++ b/library/src/test/java/com/litesuits/library/ExampleTest.java @@ -0,0 +1,15 @@ +package com.litesuits.library; + +import org.junit.Test; + +/** + * The type Example test. + */ +public class ExampleTest { + /** + * On start. + */ + @Test + public void onStart() { + } +}