Repository: greenrobot/greenDAO
Branch: master
Commit: 0bbb338e17c4
Files: 305
Total size: 1.1 MB
Directory structure:
gitextract_u02juyft/
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── DaoCore/
│ ├── .gitignore
│ ├── LICENSE
│ ├── NOTICE
│ ├── build.gradle
│ ├── libs/
│ │ └── sqlcipher.jar
│ └── src/
│ └── main/
│ └── java/
│ └── org/
│ └── greenrobot/
│ └── greendao/
│ ├── AbstractDao.java
│ ├── AbstractDaoMaster.java
│ ├── AbstractDaoSession.java
│ ├── DaoException.java
│ ├── DaoLog.java
│ ├── DbUtils.java
│ ├── InternalQueryDaoAccess.java
│ ├── InternalUnitTestDaoAccess.java
│ ├── Property.java
│ ├── async/
│ │ ├── AsyncDaoException.java
│ │ ├── AsyncOperation.java
│ │ ├── AsyncOperationExecutor.java
│ │ ├── AsyncOperationListener.java
│ │ └── AsyncSession.java
│ ├── database/
│ │ ├── Database.java
│ │ ├── DatabaseOpenHelper.java
│ │ ├── DatabaseStatement.java
│ │ ├── EncryptedDatabase.java
│ │ ├── EncryptedDatabaseStatement.java
│ │ ├── SqlCipherEncryptedHelper.java
│ │ ├── StandardDatabase.java
│ │ └── StandardDatabaseStatement.java
│ ├── identityscope/
│ │ ├── IdentityScope.java
│ │ ├── IdentityScopeLong.java
│ │ ├── IdentityScopeObject.java
│ │ └── IdentityScopeType.java
│ ├── internal/
│ │ ├── DaoConfig.java
│ │ ├── FastCursor.java
│ │ ├── LongHashMap.java
│ │ ├── SqlUtils.java
│ │ └── TableStatements.java
│ ├── query/
│ │ ├── AbstractQuery.java
│ │ ├── AbstractQueryData.java
│ │ ├── AbstractQueryWithLimit.java
│ │ ├── CloseableListIterator.java
│ │ ├── CountQuery.java
│ │ ├── CursorQuery.java
│ │ ├── DeleteQuery.java
│ │ ├── Join.java
│ │ ├── LazyList.java
│ │ ├── Query.java
│ │ ├── QueryBuilder.java
│ │ ├── WhereCollector.java
│ │ └── WhereCondition.java
│ ├── rx/
│ │ ├── RxBase.java
│ │ ├── RxDao.java
│ │ ├── RxQuery.java
│ │ ├── RxTransaction.java
│ │ └── RxUtils.java
│ └── test/
│ ├── AbstractDaoSessionTest.java
│ ├── AbstractDaoTest.java
│ ├── AbstractDaoTestLongPk.java
│ ├── AbstractDaoTestSinglePk.java
│ ├── AbstractDaoTestStringPk.java
│ └── DbTest.java
├── DaoGenerator/
│ ├── .freemarker-ide.xml
│ ├── .gitignore
│ ├── build.gradle
│ ├── performance/
│ │ ├── galaxy-nexus.xlsx
│ │ └── performance-data.xlsx
│ ├── src/
│ │ └── org/
│ │ └── greenrobot/
│ │ └── greendao/
│ │ └── generator/
│ │ ├── ContentProvider.java
│ │ ├── DaoGenerator.java
│ │ ├── DaoUtil.java
│ │ ├── Entity.java
│ │ ├── Index.java
│ │ ├── Property.java
│ │ ├── PropertyOrderList.java
│ │ ├── PropertyType.java
│ │ ├── Query.java
│ │ ├── QueryParam.java
│ │ ├── Schema.java
│ │ ├── ToMany.java
│ │ ├── ToManyBase.java
│ │ ├── ToManyWithJoinEntity.java
│ │ └── ToOne.java
│ ├── src-template/
│ │ ├── content-provider.ftl
│ │ ├── dao-deep.ftl
│ │ ├── dao-master.ftl
│ │ ├── dao-session.ftl
│ │ ├── dao-unit-test.ftl
│ │ ├── dao.ftl
│ │ └── entity.ftl
│ └── src-test/
│ └── org/
│ └── greenrobot/
│ └── greendao/
│ └── generator/
│ └── SimpleDaoGeneratorTest.java
├── README.md
├── build.gradle
├── examples/
│ ├── DaoExample/
│ │ ├── build.gradle
│ │ └── src/
│ │ ├── androidTest/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── greenrobot/
│ │ │ └── greendao/
│ │ │ └── example/
│ │ │ └── NoteTest.java
│ │ └── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── org/
│ │ │ └── greenrobot/
│ │ │ └── greendao/
│ │ │ └── example/
│ │ │ ├── App.java
│ │ │ ├── Note.java
│ │ │ ├── NoteActivity.java
│ │ │ ├── NoteType.java
│ │ │ ├── NoteTypeConverter.java
│ │ │ └── NotesAdapter.java
│ │ └── res/
│ │ ├── layout/
│ │ │ ├── item_note.xml
│ │ │ └── main.xml
│ │ └── values/
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── RxDaoExample/
│ ├── build.gradle
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── org/
│ │ └── greenrobot/
│ │ └── greendao/
│ │ └── rxexample/
│ │ ├── App.java
│ │ ├── MainActivity.java
│ │ ├── Note.java
│ │ ├── NoteType.java
│ │ ├── NoteTypeConverter.java
│ │ └── NotesAdapter.java
│ └── res/
│ ├── layout/
│ │ ├── activity_main.xml
│ │ └── item_note.xml
│ └── values/
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── gradle/
│ ├── publish.gradle
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── greendao-api/
│ ├── LICENSE
│ ├── NOTICE
│ ├── build.gradle
│ └── src/
│ └── main/
│ └── java/
│ └── org/
│ └── greenrobot/
│ └── greendao/
│ ├── annotation/
│ │ ├── Convert.java
│ │ ├── Entity.java
│ │ ├── Generated.java
│ │ ├── Id.java
│ │ ├── Index.java
│ │ ├── JoinEntity.java
│ │ ├── JoinProperty.java
│ │ ├── Keep.java
│ │ ├── NotNull.java
│ │ ├── OrderBy.java
│ │ ├── Property.java
│ │ ├── ToMany.java
│ │ ├── ToOne.java
│ │ ├── Transient.java
│ │ ├── Unique.java
│ │ └── apihint/
│ │ ├── Beta.java
│ │ ├── Experimental.java
│ │ └── Internal.java
│ └── converter/
│ └── PropertyConverter.java
├── javadoc-style/
│ └── stylesheet.css
├── settings.gradle
└── tests/
├── DaoTest/
│ ├── build.gradle
│ ├── proguard.cfg
│ ├── project.properties
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── org/
│ │ └── greenrobot/
│ │ └── greendao/
│ │ ├── daotest/
│ │ │ ├── DaoSessionConcurrentTest.java
│ │ │ ├── DaoSessionConcurrentWALTest.java
│ │ │ ├── DaoSessionTest.java
│ │ │ ├── DbTestTest.java
│ │ │ ├── DbUtilsTest.java
│ │ │ ├── DeadlockPreventionTest.java
│ │ │ ├── IndexTest.java
│ │ │ ├── LongHashMapTest.java
│ │ │ ├── async/
│ │ │ │ ├── AbstractAsyncTest.java
│ │ │ │ ├── BasicAsyncTest.java
│ │ │ │ └── MergeTxAsyncTest.java
│ │ │ ├── contentprovider/
│ │ │ │ └── SimpleEntityContentProviderTest.java
│ │ │ ├── encrypted/
│ │ │ │ ├── EncryptedDataFileTest.java
│ │ │ │ ├── EncryptedDatabaseOpenHelperTest.java
│ │ │ │ ├── EncryptedDbUtils.java
│ │ │ │ └── EncryptionSimpleEntityTest.java
│ │ │ ├── entity/
│ │ │ │ ├── AbcdefEntityTest.java
│ │ │ │ ├── AnActiveEntityMultithreadingTest.java
│ │ │ │ ├── AnActiveEntityTest.java
│ │ │ │ ├── AutoincrementEntityTest.java
│ │ │ │ ├── CustomTypeEntityTest.java
│ │ │ │ ├── DateEntityTest.java
│ │ │ │ ├── ExtendsImplementsEntityTest.java
│ │ │ │ ├── IndexedStringEntityTest.java
│ │ │ │ ├── JoinManyToDateEntityTest.java
│ │ │ │ ├── RelationEntityTest.java
│ │ │ │ ├── RelationEntityTestIdentityScope.java
│ │ │ │ ├── SimpleEntityNotNullTest.java
│ │ │ │ ├── SimpleEntityTest.java
│ │ │ │ ├── SpecialNamesEntityTest.java
│ │ │ │ ├── SqliteMasterTest.java
│ │ │ │ ├── StringKeyValueEntityIdentityScopeTest.java
│ │ │ │ ├── StringKeyValueEntityTest.java
│ │ │ │ ├── TestEntityIdentityScopeTest.java
│ │ │ │ ├── TestEntityTest.java
│ │ │ │ ├── TestEntityTestBase.java
│ │ │ │ ├── ToManyEntityTest.java
│ │ │ │ ├── ToManyTargetEntityTest.java
│ │ │ │ ├── TransactionTest.java
│ │ │ │ └── TreeEntityTest.java
│ │ │ ├── query/
│ │ │ │ ├── CountQueryTest.java
│ │ │ │ ├── CountQueryThreadLocalTest.java
│ │ │ │ ├── CursorQueryTest.java
│ │ │ │ ├── DeleteQueryTest.java
│ │ │ │ ├── DeleteQueryThreadLocalTest.java
│ │ │ │ ├── JoinTest.java
│ │ │ │ ├── LazyListTest.java
│ │ │ │ ├── QueryBuilderAndOrTest.java
│ │ │ │ ├── QueryBuilderOrderTest.java
│ │ │ │ ├── QueryBuilderSimpleTest.java
│ │ │ │ ├── QueryForThreadTest.java
│ │ │ │ ├── QueryLimitOffsetTest.java
│ │ │ │ ├── QuerySpecialNamesTest.java
│ │ │ │ └── RawQueryTest.java
│ │ │ └── rx/
│ │ │ ├── RxDaoTest.java
│ │ │ ├── RxQueryTest.java
│ │ │ ├── RxTestHelper.java
│ │ │ └── RxTransactionTest.java
│ │ └── daotest2/
│ │ └── entity/
│ │ └── KeepEntityTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ └── assets/
│ │ └── minimal-entity.sql
│ └── test/
│ └── java/
│ └── org/
│ └── greenrobot/
│ └── greendao/
│ └── unittest/
│ ├── DaoMaster.java
│ ├── DaoSession.java
│ ├── MinimalEntity.java
│ ├── MinimalEntityDao.java
│ ├── MinimalEntityTest.java
│ └── OptionalDepedenciesTest.java
├── DaoTestBase/
│ ├── build.gradle
│ └── src/
│ └── main/
│ └── java/
│ └── org/
│ └── greenrobot/
│ └── greendao/
│ ├── daotest/
│ │ ├── AbcdefEntity.java
│ │ ├── AbcdefEntityDao.java
│ │ ├── AnActiveEntity.java
│ │ ├── AnActiveEntityDao.java
│ │ ├── AutoincrementEntity.java
│ │ ├── AutoincrementEntityDao.java
│ │ ├── CustomTypeEntity.java
│ │ ├── CustomTypeEntityDao.java
│ │ ├── DaoMaster.java
│ │ ├── DaoSession.java
│ │ ├── DateEntity.java
│ │ ├── DateEntityDao.java
│ │ ├── ExtendsImplementsEntity.java
│ │ ├── ExtendsImplementsEntityDao.java
│ │ ├── IndexedStringEntity.java
│ │ ├── IndexedStringEntityDao.java
│ │ ├── JoinManyToDateEntity.java
│ │ ├── JoinManyToDateEntityDao.java
│ │ ├── RelationEntity.java
│ │ ├── RelationEntityDao.java
│ │ ├── SimpleEntity.java
│ │ ├── SimpleEntityContentProvider.java
│ │ ├── SimpleEntityDao.java
│ │ ├── SimpleEntityNotNull.java
│ │ ├── SimpleEntityNotNullDao.java
│ │ ├── SpecialNamesEntity.java
│ │ ├── SpecialNamesEntityDao.java
│ │ ├── SqliteMaster.java
│ │ ├── SqliteMasterDao.java
│ │ ├── StringKeyValueEntity.java
│ │ ├── StringKeyValueEntityDao.java
│ │ ├── TestEntity.java
│ │ ├── TestEntityDao.java
│ │ ├── TestInterface.java
│ │ ├── TestSuperclass.java
│ │ ├── ToManyEntity.java
│ │ ├── ToManyEntityDao.java
│ │ ├── ToManyTargetEntity.java
│ │ ├── ToManyTargetEntityDao.java
│ │ ├── TreeEntity.java
│ │ ├── TreeEntityDao.java
│ │ ├── customtype/
│ │ │ ├── IntegerListConverter.java
│ │ │ ├── MyTimestamp.java
│ │ │ └── MyTimestampConverter.java
│ │ └── entity/
│ │ └── SimpleEntityNotNullHelper.java
│ └── daotest2/
│ ├── KeepEntity.java
│ ├── ToManyTarget2.java
│ ├── dao/
│ │ ├── DaoMaster.java
│ │ ├── DaoSession.java
│ │ ├── KeepEntityDao.java
│ │ └── ToManyTarget2Dao.java
│ ├── specialdao/
│ │ └── RelationSource2Dao.java
│ ├── specialentity/
│ │ └── RelationSource2.java
│ ├── to1_specialdao/
│ │ └── ToOneTarget2Dao.java
│ └── to1_specialentity/
│ └── ToOneTarget2.java
├── DaoTestEntityAnnotation/
│ ├── build.gradle
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── org/
│ │ └── greenrobot/
│ │ └── greendao/
│ │ └── test/
│ │ └── entityannotation/
│ │ ├── CustomerOrderTest.java
│ │ ├── CustomerTest.java
│ │ ├── NotNullThingTest.java
│ │ ├── OrderTest.java
│ │ └── TypesInInnerClassTest.java
│ └── main/
│ ├── AndroidManifest.xml
│ └── java/
│ └── org/
│ └── greenrobot/
│ └── greendao/
│ └── test/
│ └── entityannotation/
│ ├── Customer.java
│ ├── NotNullThing.java
│ ├── Order.java
│ └── TypesInInnerClass.java
├── DaoTestGenerator/
│ ├── build.gradle
│ └── src/
│ └── org/
│ └── greenrobot/
│ └── greendao/
│ └── generator/
│ └── gentest/
│ └── TestDaoGenerator.java
└── DaoTestPerformance/
├── build.gradle
└── src/
├── androidTest/
│ └── java/
│ └── org/
│ └── greenrobot/
│ └── greendao/
│ └── performance/
│ ├── Benchmark.java
│ ├── IndexedStringPerformanceTest.java
│ ├── LoockupPerformanceTest.java
│ ├── PerformanceTest.java
│ ├── PerformanceTestNotNull.java
│ ├── PerformanceTestNotNullIdentityScope.java
│ ├── ReflectionPerformanceTest.java
│ ├── StringGenerator.java
│ └── target/
│ ├── ArrayUtils.java
│ ├── LongHashMapAmarena2DZechner.java
│ ├── LongHashMapJDBM.java
│ └── LongSparseArray.java
└── main/
└── AndroidManifest.xml
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.gradle
*.iml
.idea/
out/
build/
local.properties
================================================
FILE: .travis.yml
================================================
# Use the Travis Container-Based Infrastructure
sudo: false
language: android
jdk:
- oraclejdk8
before_install:
# Install the rest of tools (e.g., avdmanager)
- yes | sdkmanager tools
# Install the system image
- yes | sdkmanager "system-images;android-18;default;armeabi-v7a"
# Create and start emulator for the script. Meant to race the install task.
- echo no | avdmanager create avd --force -n test -k "system-images;android-18;default;armeabi-v7a"
- $ANDROID_HOME/emulator/emulator -avd test -no-audio -no-window &
install: ./gradlew clean assemble assembleAndroidTest --stacktrace
before_script:
- android-wait-for-emulator
- adb shell input keyevent 82
script: ./gradlew check connectedCheck -x :tests:DaoTestPerformance:connectedCheck --stacktrace
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- $HOME/.android/build-cache
================================================
FILE: CONTRIBUTING.md
================================================
Before you create an Issue...
=============================
There are better Places for Support
-----------------------------------
We want your question to be answered, so it is important that you ask at the right place. Be aware that an issue tracker is not the best place to ask for support. An issue tracker is used to track issues (bugs or feature requests).
Instead, please use [stackoverflow.com](https://stackoverflow.com/questions/tagged/greendao?sort=frequent) and use the tag [greendao](https://stackoverflow.com/tags/greendao/info) for your question.
Examples for support questions that are more likely to be answered on StackOverflow:
* Asking how something works
* Asking how to use greenDAO in a specific scenario
* Your app crashes/misbehaves and you are not sure why
The perfect Issue Report
------------------------
A couple of simple steps can save time for everyone.
Check before reporting:
* It's not a support inquiry
* You have read the docs
* You searched the web and stackoverflow
* You searched existing issues to avoid duplicates
Reporting bugs:
* Please investigate if is the bug is really caused by the library. Isolate the issue: what's the minimal code to reproduce the bug?
* Bonus steps to gain extra karma points: once you isolated and identified the issue, you can prepare an push request. Submit an unit test causing the bug, and ideally a fix for the bug.
Requesting features:
* Ask yourself: is the feature useful for a majority users? One of our major goals is to keep the API simple and concise. We do not want to cover all possible use cases, but those that make 80% of users happy.
Thanks for reading!
===================
It's your feedback that makes maintaining this library fun.
================================================
FILE: DaoCore/.gitignore
================================================
/gradle.properties
================================================
FILE: DaoCore/LICENSE
================================================
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.
================================================
FILE: DaoCore/NOTICE
================================================
greenrobot greenDAO (c) Copyright 2011-2016 by Markus Junginger / greenrobot.org
All rights reserved
This product includes software developed at greenrobot.org
================================================
FILE: DaoCore/build.gradle
================================================
apply plugin: 'java'
group = 'org.greenrobot'
archivesBaseName = 'greendao'
version = rootProject.version
sourceCompatibility = 1.7
targetCompatibility = 1.7
repositories {
mavenCentral()
}
dependencies {
compile project(':greendao-api')
compileOnly 'com.google.android:android:4.1.1.4'
compileOnly 'com.google.android:android-test:4.1.1.4'
compileOnly 'com.google.android:annotations:4.1.1.4'
compileOnly 'com.google.android:support-v4:r7'
compileOnly 'io.reactivex:rxjava:1.1.8'
compileOnly files('libs/sqlcipher.jar')
}
apply from: rootProject.file("gradle/publish.gradle")
javadoc {
failOnError = false
title = " greenDAO ${version} API"
options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2011-2020 greenrobot.org . All Rights Reserved. '
excludes = ['org/greenrobot/dao/internal', 'org/greenrobot/dao/Internal*']
def srcApi = project(':greendao-api').file('src/main/java/')
if (!srcApi.directory) throw new GradleScriptException("Not a directory: ${srcApi}", null)
source += srcApi
doLast {
copy {
from '../javadoc-style'
into "build/docs/javadoc/"
}
}
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from 'build/docs/javadoc'
}
task sourcesJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
}
artifacts {
// jar added by Java plugin.
archives javadocJar
archives sourcesJar
}
uploadArchives {
repositories {
mavenDeployer {
// Basic definitions are defined in root project
pom.project {
name 'greenDAO'
description 'greenDAO is a light and fast ORM for Android'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}
}
}
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/AbstractDao.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao;
import android.database.CrossProcessCursor;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
import org.greenrobot.greendao.annotation.apihint.Experimental;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.database.DatabaseStatement;
import org.greenrobot.greendao.identityscope.IdentityScope;
import org.greenrobot.greendao.identityscope.IdentityScopeLong;
import org.greenrobot.greendao.internal.DaoConfig;
import org.greenrobot.greendao.internal.FastCursor;
import org.greenrobot.greendao.internal.TableStatements;
import org.greenrobot.greendao.query.Query;
import org.greenrobot.greendao.query.QueryBuilder;
import org.greenrobot.greendao.rx.RxDao;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import rx.schedulers.Schedulers;
/**
* Base class for all DAOs: Implements entity operations like insert, load, delete, and query.
*
* This class is thread-safe.
*
* @param Entity type
* @param Primary key (PK) type; use Void if entity does not have exactly one PK
* @author Markus
*/
/*
* When operating on TX, statements, or identity scope the following locking order must be met to avoid deadlocks:
*
* 1.) If not inside a TX already, begin a TX to acquire a DB connection (connection is to be handled like a lock)
*
* 2.) The DatabaseStatement
*
* 3.) identityScope
*/
public abstract class AbstractDao {
protected final DaoConfig config;
protected final Database db;
protected final boolean isStandardSQLite;
protected final IdentityScope identityScope;
protected final IdentityScopeLong identityScopeLong;
protected final TableStatements statements;
protected final AbstractDaoSession session;
protected final int pkOrdinal;
private volatile RxDao rxDao;
private volatile RxDao rxDaoPlain;
public AbstractDao(DaoConfig config) {
this(config, null);
}
@SuppressWarnings("unchecked")
public AbstractDao(DaoConfig config, AbstractDaoSession daoSession) {
this.config = config;
this.session = daoSession;
db = config.db;
isStandardSQLite = db.getRawDatabase() instanceof SQLiteDatabase;
identityScope = (IdentityScope) config.getIdentityScope();
if (identityScope instanceof IdentityScopeLong) {
identityScopeLong = (IdentityScopeLong) identityScope;
} else {
identityScopeLong = null;
}
statements = config.statements;
pkOrdinal = config.pkProperty != null ? config.pkProperty.ordinal : -1;
}
public AbstractDaoSession getSession() {
return session;
}
TableStatements getStatements() {
return config.statements;
}
public String getTablename() {
return config.tablename;
}
public Property[] getProperties() {
return config.properties;
}
public Property getPkProperty() {
return config.pkProperty;
}
public String[] getAllColumns() {
return config.allColumns;
}
public String[] getPkColumns() {
return config.pkColumns;
}
public String[] getNonPkColumns() {
return config.nonPkColumns;
}
/**
* Loads the entity for the given PK.
*
* @param key a PK value or null
* @return The entity or null, if no entity matched the PK value
*/
public T load(K key) {
assertSinglePk();
if (key == null) {
return null;
}
if (identityScope != null) {
T entity = identityScope.get(key);
if (entity != null) {
return entity;
}
}
String sql = statements.getSelectByKey();
String[] keyArray = new String[]{key.toString()};
Cursor cursor = db.rawQuery(sql, keyArray);
return loadUniqueAndCloseCursor(cursor);
}
public T loadByRowId(long rowId) {
String[] idArray = new String[]{Long.toString(rowId)};
Cursor cursor = db.rawQuery(statements.getSelectByRowId(), idArray);
return loadUniqueAndCloseCursor(cursor);
}
protected T loadUniqueAndCloseCursor(Cursor cursor) {
try {
return loadUnique(cursor);
} finally {
cursor.close();
}
}
protected T loadUnique(Cursor cursor) {
boolean available = cursor.moveToFirst();
if (!available) {
return null;
} else if (!cursor.isLast()) {
throw new DaoException("Expected unique result, but count was " + cursor.getCount());
}
return loadCurrent(cursor, 0, true);
}
/** Loads all available entities from the database. */
public List loadAll() {
Cursor cursor = db.rawQuery(statements.getSelectAll(), null);
return loadAllAndCloseCursor(cursor);
}
/** Detaches an entity from the identity scope (session). Subsequent query results won't return this object. */
public boolean detach(T entity) {
if (identityScope != null) {
K key = getKeyVerified(entity);
return identityScope.detach(key, entity);
} else {
return false;
}
}
/**
* Detaches all entities (of type T) from the identity scope (session). Subsequent query results won't return any
* previously loaded objects.
*/
public void detachAll() {
if (identityScope != null) {
identityScope.clear();
}
}
protected List loadAllAndCloseCursor(Cursor cursor) {
try {
return loadAllFromCursor(cursor);
} finally {
cursor.close();
}
}
/**
* Inserts the given entities in the database using a transaction.
*
* @param entities The entities to insert.
*/
public void insertInTx(Iterable entities) {
insertInTx(entities, isEntityUpdateable());
}
/**
* Inserts the given entities in the database using a transaction.
*
* @param entities The entities to insert.
*/
public void insertInTx(T... entities) {
insertInTx(Arrays.asList(entities), isEntityUpdateable());
}
/**
* Inserts the given entities in the database using a transaction. The given entities will become tracked if the PK
* is set.
*
* @param entities The entities to insert.
* @param setPrimaryKey if true, the PKs of the given will be set after the insert; pass false to improve
* performance.
*/
public void insertInTx(Iterable entities, boolean setPrimaryKey) {
DatabaseStatement stmt = statements.getInsertStatement();
executeInsertInTx(stmt, entities, setPrimaryKey);
}
/**
* Inserts or replaces the given entities in the database using a transaction. The given entities will become
* tracked if the PK is set.
*
* @param entities The entities to insert.
* @param setPrimaryKey if true, the PKs of the given will be set after the insert; pass false to improve
* performance.
*/
public void insertOrReplaceInTx(Iterable entities, boolean setPrimaryKey) {
DatabaseStatement stmt = statements.getInsertOrReplaceStatement();
executeInsertInTx(stmt, entities, setPrimaryKey);
}
/**
* Inserts or replaces the given entities in the database using a transaction.
*
* @param entities The entities to insert.
*/
public void insertOrReplaceInTx(Iterable entities) {
insertOrReplaceInTx(entities, isEntityUpdateable());
}
/**
* Inserts or replaces the given entities in the database using a transaction.
*
* @param entities The entities to insert.
*/
public void insertOrReplaceInTx(T... entities) {
insertOrReplaceInTx(Arrays.asList(entities), isEntityUpdateable());
}
private void executeInsertInTx(DatabaseStatement stmt, Iterable entities, boolean setPrimaryKey) {
db.beginTransaction();
try {
synchronized (stmt) {
if (identityScope != null) {
identityScope.lock();
}
try {
if (isStandardSQLite) {
SQLiteStatement rawStmt = (SQLiteStatement) stmt.getRawStatement();
for (T entity : entities) {
bindValues(rawStmt, entity);
if (setPrimaryKey) {
long rowId = rawStmt.executeInsert();
updateKeyAfterInsertAndAttach(entity, rowId, false);
} else {
rawStmt.execute();
}
}
} else {
for (T entity : entities) {
bindValues(stmt, entity);
if (setPrimaryKey) {
long rowId = stmt.executeInsert();
updateKeyAfterInsertAndAttach(entity, rowId, false);
} else {
stmt.execute();
}
}
}
} finally {
if (identityScope != null) {
identityScope.unlock();
}
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
/**
* Insert an entity into the table associated with a concrete DAO.
*
* @return row ID of newly inserted entity
*/
public long insert(T entity) {
return executeInsert(entity, statements.getInsertStatement(), true);
}
/**
* Insert an entity into the table associated with a concrete DAO without setting key property.
*
* Warning: This may be faster, but the entity should not be used anymore. The entity also won't be attached to
* identity scope.
*
* @return row ID of newly inserted entity
*/
public long insertWithoutSettingPk(T entity) {
return executeInsert(entity, statements.getInsertOrReplaceStatement(), false);
}
/**
* Insert an entity into the table associated with a concrete DAO.
*
* @return row ID of newly inserted entity
*/
public long insertOrReplace(T entity) {
return executeInsert(entity, statements.getInsertOrReplaceStatement(), true);
}
private long executeInsert(T entity, DatabaseStatement stmt, boolean setKeyAndAttach) {
long rowId;
if (db.isDbLockedByCurrentThread()) {
rowId = insertInsideTx(entity, stmt);
} else {
// Do TX to acquire a connection before locking the stmt to avoid deadlocks
db.beginTransaction();
try {
rowId = insertInsideTx(entity, stmt);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
if (setKeyAndAttach) {
updateKeyAfterInsertAndAttach(entity, rowId, true);
}
return rowId;
}
private long insertInsideTx(T entity, DatabaseStatement stmt) {
synchronized (stmt) {
if (isStandardSQLite) {
SQLiteStatement rawStmt = (SQLiteStatement) stmt.getRawStatement();
bindValues(rawStmt, entity);
return rawStmt.executeInsert();
} else {
bindValues(stmt, entity);
return stmt.executeInsert();
}
}
}
protected void updateKeyAfterInsertAndAttach(T entity, long rowId, boolean lock) {
if (rowId != -1) {
K key = updateKeyAfterInsert(entity, rowId);
attachEntity(key, entity, lock);
} else {
// TODO When does this actually happen? Should we throw instead?
DaoLog.w("Could not insert row (executeInsert returned -1)");
}
}
/**
* "Saves" an entity to the database: depending on the existence of the key property, it will be inserted
* (key is null) or updated (key is not null).
*
* This is similar to {@link #insertOrReplace(Object)}, but may be more efficient, because if a key is present,
* it does not have to query if that key already exists.
*/
public void save(T entity) {
if (hasKey(entity)) {
update(entity);
} else {
insert(entity);
}
}
/**
* Saves (see {@link #save(Object)}) the given entities in the database using a transaction.
*
* @param entities The entities to save.
*/
public void saveInTx(T... entities) {
saveInTx(Arrays.asList(entities));
}
/**
* Saves (see {@link #save(Object)}) the given entities in the database using a transaction.
*
* @param entities The entities to save.
*/
public void saveInTx(Iterable entities) {
int updateCount = 0;
int insertCount = 0;
for (T entity : entities) {
if (hasKey(entity)) {
updateCount++;
} else {
insertCount++;
}
}
if (updateCount > 0 && insertCount > 0) {
List toUpdate = new ArrayList<>(updateCount);
List toInsert = new ArrayList<>(insertCount);
for (T entity : entities) {
if (hasKey(entity)) {
toUpdate.add(entity);
} else {
toInsert.add(entity);
}
}
db.beginTransaction();
try {
updateInTx(toUpdate);
insertInTx(toInsert);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
} else if (insertCount > 0) {
insertInTx(entities);
} else if (updateCount > 0) {
updateInTx(entities);
}
}
/** Reads all available rows from the given cursor and returns a list of entities. */
protected List loadAllFromCursor(Cursor cursor) {
int count = cursor.getCount();
if (count == 0) {
return new ArrayList();
}
List list = new ArrayList(count);
CursorWindow window = null;
boolean useFastCursor = false;
if (cursor instanceof CrossProcessCursor) {
window = ((CrossProcessCursor) cursor).getWindow();
if (window != null) { // E.g. Robolectric has no Window at this point
if (window.getNumRows() == count) {
cursor = new FastCursor(window);
useFastCursor = true;
} else {
DaoLog.d("Window vs. result size: " + window.getNumRows() + "/" + count);
}
}
}
if (cursor.moveToFirst()) {
if (identityScope != null) {
identityScope.lock();
identityScope.reserveRoom(count);
}
try {
if (!useFastCursor && window != null && identityScope != null) {
loadAllUnlockOnWindowBounds(cursor, window, list);
} else {
do {
list.add(loadCurrent(cursor, 0, false));
} while (cursor.moveToNext());
}
} finally {
if (identityScope != null) {
identityScope.unlock();
}
}
}
return list;
}
private void loadAllUnlockOnWindowBounds(Cursor cursor, CursorWindow window, List list) {
int windowEnd = window.getStartPosition() + window.getNumRows();
for (int row = 0; ; row++) {
list.add(loadCurrent(cursor, 0, false));
row++;
if (row >= windowEnd) {
window = moveToNextUnlocked(cursor);
if (window == null) {
break;
}
windowEnd = window.getStartPosition() + window.getNumRows();
} else {
if (!cursor.moveToNext()) {
break;
}
}
}
}
/**
* Unlock identityScope during cursor.moveToNext() when it is about to fill the window (needs a db connection):
* We should not hold the lock while trying to acquire a db connection to avoid deadlocks.
*/
private CursorWindow moveToNextUnlocked(Cursor cursor) {
identityScope.unlock();
try {
if (cursor.moveToNext()) {
return ((CrossProcessCursor) cursor).getWindow();
} else {
return null;
}
} finally {
identityScope.lock();
}
}
/** Internal use only. Considers identity scope. */
final protected T loadCurrent(Cursor cursor, int offset, boolean lock) {
if (identityScopeLong != null) {
if (offset != 0) {
// Occurs with deep loads (left outer joins)
if (cursor.isNull(pkOrdinal + offset)) {
return null;
}
}
long key = cursor.getLong(pkOrdinal + offset);
T entity = lock ? identityScopeLong.get2(key) : identityScopeLong.get2NoLock(key);
if (entity != null) {
return entity;
} else {
entity = readEntity(cursor, offset);
attachEntity(entity);
if (lock) {
identityScopeLong.put2(key, entity);
} else {
identityScopeLong.put2NoLock(key, entity);
}
return entity;
}
} else if (identityScope != null) {
K key = readKey(cursor, offset);
if (offset != 0 && key == null) {
// Occurs with deep loads (left outer joins)
return null;
}
T entity = lock ? identityScope.get(key) : identityScope.getNoLock(key);
if (entity != null) {
return entity;
} else {
entity = readEntity(cursor, offset);
attachEntity(key, entity, lock);
return entity;
}
} else {
// Check offset, assume a value !=0 indicating a potential outer join, so check PK
if (offset != 0) {
K key = readKey(cursor, offset);
if (key == null) {
// Occurs with deep loads (left outer joins)
return null;
}
}
T entity = readEntity(cursor, offset);
attachEntity(entity);
return entity;
}
}
/** Internal use only. Considers identity scope. */
final protected O loadCurrentOther(AbstractDao dao, Cursor cursor, int offset) {
return dao.loadCurrent(cursor, offset, /* TODO check this */true);
}
/** A raw-style query where you can pass any WHERE clause and arguments. */
public List queryRaw(String where, String... selectionArg) {
Cursor cursor = db.rawQuery(statements.getSelectAll() + where, selectionArg);
return loadAllAndCloseCursor(cursor);
}
/**
* Creates a repeatable {@link Query} object based on the given raw SQL where you can pass any WHERE clause and
* arguments.
*/
public Query queryRawCreate(String where, Object... selectionArg) {
List argList = Arrays.asList(selectionArg);
return queryRawCreateListArgs(where, argList);
}
/**
* Creates a repeatable {@link Query} object based on the given raw SQL where you can pass any WHERE clause and
* arguments.
*/
public Query queryRawCreateListArgs(String where, Collection selectionArg) {
return Query.internalCreate(this, statements.getSelectAll() + where, selectionArg.toArray());
}
public void deleteAll() {
// String sql = SqlUtils.createSqlDelete(config.tablename, null);
// db.execSQL(sql);
db.execSQL("DELETE FROM '" + config.tablename + "'");
if (identityScope != null) {
identityScope.clear();
}
}
/** Deletes the given entity from the database. Currently, only single value PK entities are supported. */
public void delete(T entity) {
assertSinglePk();
K key = getKeyVerified(entity);
deleteByKey(key);
}
/** Deletes an entity with the given PK from the database. Currently, only single value PK entities are supported. */
public void deleteByKey(K key) {
assertSinglePk();
DatabaseStatement stmt = statements.getDeleteStatement();
if (db.isDbLockedByCurrentThread()) {
synchronized (stmt) {
deleteByKeyInsideSynchronized(key, stmt);
}
} else {
// Do TX to acquire a connection before locking the stmt to avoid deadlocks
db.beginTransaction();
try {
synchronized (stmt) {
deleteByKeyInsideSynchronized(key, stmt);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
if (identityScope != null) {
identityScope.remove(key);
}
}
private void deleteByKeyInsideSynchronized(K key, DatabaseStatement stmt) {
if (key instanceof Long) {
stmt.bindLong(1, (Long) key);
} else if (key == null) {
throw new DaoException("Cannot delete entity, key is null");
} else {
stmt.bindString(1, key.toString());
}
stmt.execute();
}
private void deleteInTxInternal(Iterable entities, Iterable keys) {
assertSinglePk();
DatabaseStatement stmt = statements.getDeleteStatement();
List keysToRemoveFromIdentityScope = null;
db.beginTransaction();
try {
synchronized (stmt) {
if (identityScope != null) {
identityScope.lock();
keysToRemoveFromIdentityScope = new ArrayList();
}
try {
if (entities != null) {
for (T entity : entities) {
K key = getKeyVerified(entity);
deleteByKeyInsideSynchronized(key, stmt);
if (keysToRemoveFromIdentityScope != null) {
keysToRemoveFromIdentityScope.add(key);
}
}
}
if (keys != null) {
for (K key : keys) {
deleteByKeyInsideSynchronized(key, stmt);
if (keysToRemoveFromIdentityScope != null) {
keysToRemoveFromIdentityScope.add(key);
}
}
}
} finally {
if (identityScope != null) {
identityScope.unlock();
}
}
}
db.setTransactionSuccessful();
if (keysToRemoveFromIdentityScope != null && identityScope != null) {
identityScope.remove(keysToRemoveFromIdentityScope);
}
} finally {
db.endTransaction();
}
}
/**
* Deletes the given entities in the database using a transaction.
*
* @param entities The entities to delete.
*/
public void deleteInTx(Iterable entities) {
deleteInTxInternal(entities, null);
}
/**
* Deletes the given entities in the database using a transaction.
*
* @param entities The entities to delete.
*/
public void deleteInTx(T... entities) {
deleteInTxInternal(Arrays.asList(entities), null);
}
/**
* Deletes all entities with the given keys in the database using a transaction.
*
* @param keys Keys of the entities to delete.
*/
public void deleteByKeyInTx(Iterable keys) {
deleteInTxInternal(null, keys);
}
/**
* Deletes all entities with the given keys in the database using a transaction.
*
* @param keys Keys of the entities to delete.
*/
public void deleteByKeyInTx(K... keys) {
deleteInTxInternal(null, Arrays.asList(keys));
}
/** Resets all locally changed properties of the entity by reloading the values from the database. */
public void refresh(T entity) {
assertSinglePk();
K key = getKeyVerified(entity);
String sql = statements.getSelectByKey();
String[] keyArray = new String[]{key.toString()};
Cursor cursor = db.rawQuery(sql, keyArray);
try {
boolean available = cursor.moveToFirst();
if (!available) {
throw new DaoException("Entity does not exist in the database anymore: " + entity.getClass()
+ " with key " + key);
} else if (!cursor.isLast()) {
throw new DaoException("Expected unique result, but count was " + cursor.getCount());
}
readEntity(cursor, entity, 0);
attachEntity(key, entity, true);
} finally {
cursor.close();
}
}
public void update(T entity) {
assertSinglePk();
DatabaseStatement stmt = statements.getUpdateStatement();
if (db.isDbLockedByCurrentThread()) {
synchronized (stmt) {
if (isStandardSQLite) {
updateInsideSynchronized(entity, (SQLiteStatement) stmt.getRawStatement(), true);
} else {
updateInsideSynchronized(entity, stmt, true);
}
}
} else {
// Do TX to acquire a connection before locking the stmt to avoid deadlocks
db.beginTransaction();
try {
synchronized (stmt) {
updateInsideSynchronized(entity, stmt, true);
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
}
public QueryBuilder queryBuilder() {
return QueryBuilder.internalCreate(this);
}
protected void updateInsideSynchronized(T entity, DatabaseStatement stmt, boolean lock) {
// To do? Check if it's worth not to bind PKs here (performance).
bindValues(stmt, entity);
int index = config.allColumns.length + 1;
K key = getKey(entity);
if (key instanceof Long) {
stmt.bindLong(index, (Long) key);
} else if (key == null) {
throw new DaoException("Cannot update entity without key - was it inserted before?");
} else {
stmt.bindString(index, key.toString());
}
stmt.execute();
attachEntity(key, entity, lock);
}
protected void updateInsideSynchronized(T entity, SQLiteStatement stmt, boolean lock) {
// To do? Check if it's worth not to bind PKs here (performance).
bindValues(stmt, entity);
int index = config.allColumns.length + 1;
K key = getKey(entity);
if (key instanceof Long) {
stmt.bindLong(index, (Long) key);
} else if (key == null) {
throw new DaoException("Cannot update entity without key - was it inserted before?");
} else {
stmt.bindString(index, key.toString());
}
stmt.execute();
attachEntity(key, entity, lock);
}
/**
* Attaches the entity to the identity scope. Calls attachEntity(T entity).
*
* @param key Needed only for identity scope, pass null if there's none.
* @param entity The entitiy to attach
*/
protected final void attachEntity(K key, T entity, boolean lock) {
attachEntity(entity);
if (identityScope != null && key != null) {
if (lock) {
identityScope.put(key, entity);
} else {
identityScope.putNoLock(key, entity);
}
}
}
/**
* Sub classes with relations additionally set the DaoMaster here. Must be called before the entity is attached to
* the identity scope.
*
* @param entity The entitiy to attach
*/
protected void attachEntity(T entity) {
}
/**
* Updates the given entities in the database using a transaction.
*
* @param entities The entities to insert.
*/
public void updateInTx(Iterable entities) {
DatabaseStatement stmt = statements.getUpdateStatement();
db.beginTransaction();
// txEx: just to preserve original exception in case another exceptions is thrown in endTransaction()
RuntimeException txEx = null;
try {
synchronized (stmt) {
if (identityScope != null) {
identityScope.lock();
}
try {
if (isStandardSQLite) {
SQLiteStatement rawStmt = (SQLiteStatement) stmt.getRawStatement();
for (T entity : entities) {
updateInsideSynchronized(entity, rawStmt, false);
}
} else {
for (T entity : entities) {
updateInsideSynchronized(entity, stmt, false);
}
}
} finally {
if (identityScope != null) {
identityScope.unlock();
}
}
}
db.setTransactionSuccessful();
} catch (RuntimeException e) {
txEx = e;
} finally {
try {
db.endTransaction();
} catch (RuntimeException e) {
if (txEx != null) {
DaoLog.w("Could not end transaction (rethrowing initial exception)", e);
throw txEx;
} else {
throw e;
}
}
}
if (txEx != null) {
throw txEx;
}
}
/**
* Updates the given entities in the database using a transaction.
*
* @param entities The entities to update.
*/
public void updateInTx(T... entities) {
updateInTx(Arrays.asList(entities));
}
protected void assertSinglePk() {
if (config.pkColumns.length != 1) {
throw new DaoException(this + " (" + config.tablename + ") does not have a single-column primary key");
}
}
public long count() {
return statements.getCountStatement().simpleQueryForLong();
}
/** See {@link #getKey(Object)}, but guarantees that the returned key is never null (throws if null). */
protected K getKeyVerified(T entity) {
K key = getKey(entity);
if (key == null) {
if (entity == null) {
throw new NullPointerException("Entity may not be null");
} else {
throw new DaoException("Entity has no key");
}
} else {
return key;
}
}
/**
* The returned RxDao is a special DAO that let's you interact with Rx Observables without any Scheduler set
* for subscribeOn.
*
* @see #rx()
*/
@Experimental
public RxDao rxPlain() {
if (rxDaoPlain == null) {
rxDaoPlain = new RxDao<>(this);
}
return rxDaoPlain;
}
/**
* The returned RxDao is a special DAO that let's you interact with Rx Observables using RX's IO scheduler for
* subscribeOn.
*
* @see #rxPlain()
*/
@Experimental
public RxDao rx() {
if (rxDao == null) {
rxDao = new RxDao<>(this, Schedulers.io());
}
return rxDao;
}
/** Gets the SQLiteDatabase for custom database access. Not needed for greenDAO entities. */
public Database getDatabase() {
return db;
}
/** Reads the values from the current position of the given cursor and returns a new entity. */
abstract protected T readEntity(Cursor cursor, int offset);
/** Reads the key from the current position of the given cursor, or returns null if there's no single-value key. */
abstract protected K readKey(Cursor cursor, int offset);
/** Reads the values from the current position of the given cursor into an existing entity. */
abstract protected void readEntity(Cursor cursor, T entity, int offset);
/** Binds the entity's values to the statement. Make sure to synchronize the statement outside of the method. */
abstract protected void bindValues(DatabaseStatement stmt, T entity);
/**
* Binds the entity's values to the statement. Make sure to synchronize the enclosing DatabaseStatement outside
* of the method.
*/
protected abstract void bindValues(SQLiteStatement stmt, T entity);
/**
* Updates the entity's key if possible (only for Long PKs currently). This method must always return the entity's
* key regardless of whether the key existed before or not.
*/
abstract protected K updateKeyAfterInsert(T entity, long rowId);
/**
* Returns the value of the primary key, if the entity has a single primary key, or, if not, null. Returns null if
* entity is null.
*/
abstract protected K getKey(T entity);
/**
* Returns true if the entity is not null, and has a non-null key, which is also != 0.
* entity is null.
*/
abstract protected boolean hasKey(T entity);
/** Returns true if the Entity class can be updated, e.g. for setting the PK after insert. */
abstract protected boolean isEntityUpdateable();
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/AbstractDaoMaster.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao;
import java.util.HashMap;
import java.util.Map;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.identityscope.IdentityScopeType;
import org.greenrobot.greendao.internal.DaoConfig;
/**
* The master of dao will guide you: start dao sessions with the master.
*
* @author Markus
*/
public abstract class AbstractDaoMaster {
protected final Database db;
protected final int schemaVersion;
protected final Map>, DaoConfig> daoConfigMap;
public AbstractDaoMaster(Database db, int schemaVersion) {
this.db = db;
this.schemaVersion = schemaVersion;
daoConfigMap = new HashMap>, DaoConfig>();
}
protected void registerDaoClass(Class extends AbstractDao, ?>> daoClass) {
DaoConfig daoConfig = new DaoConfig(db, daoClass);
daoConfigMap.put(daoClass, daoConfig);
}
public int getSchemaVersion() {
return schemaVersion;
}
/** Gets the SQLiteDatabase for custom database access. Not needed for greenDAO entities. */
public Database getDatabase() {
return db;
}
public abstract AbstractDaoSession newSession();
public abstract AbstractDaoSession newSession(IdentityScopeType type);
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/AbstractDaoSession.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import org.greenrobot.greendao.annotation.apihint.Experimental;
import org.greenrobot.greendao.async.AsyncSession;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.query.QueryBuilder;
import org.greenrobot.greendao.rx.RxTransaction;
import rx.schedulers.Schedulers;
/**
* DaoSession gives you access to your DAOs, offers convenient persistence methods, and also serves as a session cache.
*
* To access the DAOs, call the get{entity}Dao methods by the generated DaoSession sub class.
*
* DaoSession offers many of the available persistence operations on entities as a convenience. Consider using DAOs
* directly to access all available operations, especially if you call a lot of operations on a single entity type to
* avoid the overhead imposed by DaoSession (the overhead is small, but it may add up).
*
* By default, the DaoSession has a session cache (IdentityScopeType.Session). The session cache is not just a plain
* data cache to improve performance, but also manages object identities. For example, if you load the same entity twice
* in a query, you will get a single Java object instead of two when using a session cache. This is particular useful
* for relations pointing to a common set of entities.
*
* This class is thread-safe.
*
* @author Markus
*
*/
public class AbstractDaoSession {
private final Database db;
private final Map, AbstractDao, ?>> entityToDao;
private volatile RxTransaction rxTxPlain;
private volatile RxTransaction rxTxIo;
public AbstractDaoSession(Database db) {
this.db = db;
this.entityToDao = new HashMap, AbstractDao, ?>>();
}
protected void registerDao(Class entityClass, AbstractDao dao) {
entityToDao.put(entityClass, dao);
}
/** Convenient call for {@link AbstractDao#insert(Object)}. */
public long insert(T entity) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entity.getClass());
return dao.insert(entity);
}
/** Convenient call for {@link AbstractDao#insertOrReplace(Object)}. */
public long insertOrReplace(T entity) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entity.getClass());
return dao.insertOrReplace(entity);
}
/** Convenient call for {@link AbstractDao#refresh(Object)}. */
public void refresh(T entity) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entity.getClass());
dao.refresh(entity);
}
/** Convenient call for {@link AbstractDao#update(Object)}. */
public void update(T entity) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entity.getClass());
dao.update(entity);
}
/** Convenient call for {@link AbstractDao#delete(Object)}. */
public void delete(T entity) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entity.getClass());
dao.delete(entity);
}
/** Convenient call for {@link AbstractDao#deleteAll()}. */
public void deleteAll(Class entityClass) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entityClass);
dao.deleteAll();
}
/** Convenient call for {@link AbstractDao#load(Object)}. */
public T load(Class entityClass, K key) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entityClass);
return dao.load(key);
}
/** Convenient call for {@link AbstractDao#loadAll()}. */
public List loadAll(Class entityClass) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entityClass);
return dao.loadAll();
}
/** Convenient call for {@link AbstractDao#queryRaw(String, String...)}. */
public List queryRaw(Class entityClass, String where, String... selectionArgs) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entityClass);
return dao.queryRaw(where, selectionArgs);
}
/** Convenient call for {@link AbstractDao#queryBuilder()}. */
public QueryBuilder queryBuilder(Class entityClass) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entityClass);
return dao.queryBuilder();
}
public AbstractDao, ?> getDao(Class extends Object> entityClass) {
AbstractDao, ?> dao = entityToDao.get(entityClass);
if (dao == null) {
throw new DaoException("No DAO registered for " + entityClass);
}
return dao;
}
/**
* Run the given Runnable inside a database transaction. If you except a result, consider callInTx.
*/
public void runInTx(Runnable runnable) {
db.beginTransaction();
try {
runnable.run();
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
/**
* Calls the given Callable inside a database transaction and returns the result of the Callable. If you don't
* except a result, consider runInTx.
*/
public V callInTx(Callable callable) throws Exception {
db.beginTransaction();
try {
V result = callable.call();
db.setTransactionSuccessful();
return result;
} finally {
db.endTransaction();
}
}
/**
* Like {@link #callInTx(Callable)} but does not require Exception handling (rethrows an Exception as a runtime
* DaoException).
*/
public V callInTxNoException(Callable callable) {
db.beginTransaction();
try {
V result;
try {
result = callable.call();
} catch (Exception e) {
throw new DaoException("Callable failed", e);
}
db.setTransactionSuccessful();
return result;
} finally {
db.endTransaction();
}
}
/** Gets the Database for custom database access. Not needed for greenDAO entities. */
public Database getDatabase() {
return db;
}
/** Allows to inspect the meta model using DAOs (e.g. querying table names or properties). */
public Collection> getAllDaos() {
return Collections.unmodifiableCollection(entityToDao.values());
}
/**
* Creates a new {@link AsyncSession} to issue asynchronous entity operations. See {@link AsyncSession} for details.
*/
public AsyncSession startAsyncSession() {
return new AsyncSession(this);
}
/**
* The returned {@link RxTransaction} allows DB transactions using Rx Observables without any Scheduler set for
* subscribeOn.
*
* @see #rxTx()
*/
@Experimental
public RxTransaction rxTxPlain() {
if (rxTxPlain == null) {
rxTxPlain = new RxTransaction(this);
}
return rxTxPlain;
}
/**
* The returned {@link RxTransaction} allows DB transactions using Rx Observables using RX's IO scheduler for
* subscribeOn.
*
* @see #rxTxPlain()
*/
@Experimental
public RxTransaction rxTx() {
if (rxTxIo == null) {
rxTxIo = new RxTransaction(this, Schedulers.io());
}
return rxTxIo;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/DaoException.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao;
import android.database.SQLException;
/**
* Exception thrown when something goes wrong in the DAO/ORM layer.
*
* @author Markus
*
*/
public class DaoException extends SQLException {
private static final long serialVersionUID = -5877937327907457779L;
public DaoException() {
}
public DaoException(String error) {
super(error);
}
public DaoException(String error, Throwable cause) {
super(error);
safeInitCause(cause);
}
public DaoException(Throwable th) {
safeInitCause(th);
}
protected void safeInitCause(Throwable cause) {
try {
initCause(cause);
} catch (Throwable e) {
DaoLog.e("Could not set initial cause", e);
DaoLog.e( "Initial cause is:", cause);
}
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/DaoLog.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao;
import android.util.Log;
/**
* Internal greenDAO logger class. A wrapper around the Android Log class providing a static Log Tag.
*
* @author markus
*
*/
public class DaoLog {
private final static String TAG = "greenDAO";
public static final int VERBOSE = 2;
public static final int DEBUG = 3;
public static final int INFO = 4;
public static final int WARN = 5;
public static final int ERROR = 6;
public static final int ASSERT = 7;
public static boolean isLoggable(int level) {
return Log.isLoggable(TAG, level);
}
public static String getStackTraceString(Throwable th) {
return Log.getStackTraceString(th);
}
public static int println(int level, String msg) {
return Log.println(level, TAG, msg);
}
public static int v(String msg) {
return Log.v(TAG, msg);
}
public static int v(String msg, Throwable th) {
return Log.v(TAG, msg, th);
}
public static int d(String msg) {
return Log.d(TAG, msg);
}
public static int d(String msg, Throwable th) {
return Log.d(TAG, msg, th);
}
public static int i(String msg) {
return Log.i(TAG, msg);
}
public static int i(String msg, Throwable th) {
return Log.i(TAG, msg, th);
}
public static int w(String msg) {
return Log.w(TAG, msg);
}
public static int w(String msg, Throwable th) {
return Log.w(TAG, msg, th);
}
public static int w(Throwable th) {
return Log.w(TAG, th);
}
public static int e(String msg) {
return Log.w(TAG, msg);
}
public static int e(String msg, Throwable th) {
return Log.e(TAG, msg, th);
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/DbUtils.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import org.greenrobot.greendao.database.Database;
/** Database utils, for example to execute SQL scripts */
// TODO add unit tests
public class DbUtils {
public static void vacuum(Database db) {
db.execSQL("VACUUM");
}
/**
* Calls {@link #executeSqlScript(Context, Database, String, boolean)} with transactional set to true.
*
* @return number of statements executed.
*/
public static int executeSqlScript(Context context, Database db, String assetFilename) throws IOException {
return executeSqlScript(context, db, assetFilename, true);
}
/**
* Executes the given SQL asset in the given database (SQL file should be UTF-8). The database file may contain
* multiple SQL statements. Statements are split using a simple regular expression (something like
* "semicolon before a line break"), not by analyzing the SQL syntax. This will work for many SQL files, but check
* yours.
*
* @return number of statements executed.
*/
public static int executeSqlScript(Context context, Database db, String assetFilename, boolean transactional)
throws IOException {
byte[] bytes = readAsset(context, assetFilename);
String sql = new String(bytes, "UTF-8");
String[] lines = sql.split(";(\\s)*[\n\r]");
int count;
if (transactional) {
count = executeSqlStatementsInTx(db, lines);
} else {
count = executeSqlStatements(db, lines);
}
DaoLog.i("Executed " + count + " statements from SQL script '" + assetFilename + "'");
return count;
}
public static int executeSqlStatementsInTx(Database db, String[] statements) {
db.beginTransaction();
try {
int count = executeSqlStatements(db, statements);
db.setTransactionSuccessful();
return count;
} finally {
db.endTransaction();
}
}
public static int executeSqlStatements(Database db, String[] statements) {
int count = 0;
for (String line : statements) {
line = line.trim();
if (line.length() > 0) {
db.execSQL(line);
count++;
}
}
return count;
}
/**
* Copies all available data from in to out without closing any stream.
*
* @return number of bytes copied
*/
public static int copyAllBytes(InputStream in, OutputStream out) throws IOException {
int byteCount = 0;
byte[] buffer = new byte[4096];
while (true) {
int read = in.read(buffer);
if (read == -1) {
break;
}
out.write(buffer, 0, read);
byteCount += read;
}
return byteCount;
}
public static byte[] readAllBytes(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
copyAllBytes(in, out);
return out.toByteArray();
}
public static byte[] readAsset(Context context, String filename) throws IOException {
InputStream in = context.getResources().getAssets().open(filename);
try {
return readAllBytes(in);
} finally {
in.close();
}
}
public static void logTableDump(SQLiteDatabase db, String tablename) {
Cursor cursor = db.query(tablename, null, null, null, null, null, null);
try {
String dump = DatabaseUtils.dumpCursorToString(cursor);
DaoLog.d(dump);
} finally {
cursor.close();
}
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/InternalQueryDaoAccess.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao;
import java.util.List;
import android.database.Cursor;
import org.greenrobot.greendao.internal.TableStatements;
/** For internal use by greenDAO only. */
public final class InternalQueryDaoAccess {
private final AbstractDao dao;
public InternalQueryDaoAccess(AbstractDao abstractDao) {
dao = abstractDao;
}
public T loadCurrent(Cursor cursor, int offset, boolean lock) {
return dao.loadCurrent(cursor, offset, lock);
}
public List loadAllAndCloseCursor(Cursor cursor) {
return dao.loadAllAndCloseCursor(cursor);
}
public T loadUniqueAndCloseCursor(Cursor cursor) {
return dao.loadUniqueAndCloseCursor(cursor);
}
public TableStatements getStatements() {
return dao.getStatements();
}
public static TableStatements getStatements(AbstractDao dao) {
return dao.getStatements();
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/InternalUnitTestDaoAccess.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao;
import android.database.Cursor;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.identityscope.IdentityScope;
import org.greenrobot.greendao.internal.DaoConfig;
import java.lang.reflect.Constructor;
/** Reserved for internal unit tests that want to access some non-public methods. Don't use for anything else. */
public class InternalUnitTestDaoAccess {
private final AbstractDao dao;
public InternalUnitTestDaoAccess(Database db, Class> daoClass, IdentityScope, ?> identityScope)
throws Exception {
DaoConfig daoConfig = new DaoConfig(db, daoClass);
daoConfig.setIdentityScope(identityScope);
Constructor> constructor = daoClass.getConstructor(DaoConfig.class);
dao = constructor.newInstance(daoConfig);
}
public K getKey(T entity) {
return dao.getKey(entity);
}
public Property[] getProperties() {
return dao.getProperties();
}
public boolean isEntityUpdateable() {
return dao.isEntityUpdateable();
}
public T readEntity(Cursor cursor, int offset) {
return dao.readEntity(cursor, offset);
}
public K readKey(Cursor cursor, int offset) {
return dao.readKey(cursor, offset);
}
public AbstractDao getDao() {
return dao;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/Property.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao;
import java.util.Collection;
import org.greenrobot.greendao.internal.SqlUtils;
import org.greenrobot.greendao.query.WhereCondition;
import org.greenrobot.greendao.query.WhereCondition.PropertyCondition;
/**
* Meta data describing a property mapped to a database column; used to create WhereCondition object used by the query builder.
*
* @author Markus
*/
public class Property {
public final int ordinal;
public final Class> type;
public final String name;
public final boolean primaryKey;
public final String columnName;
public Property(int ordinal, Class> type, String name, boolean primaryKey, String columnName) {
this.ordinal = ordinal;
this.type = type;
this.name = name;
this.primaryKey = primaryKey;
this.columnName = columnName;
}
/** Creates an "equal ('=')" condition for this property. */
public WhereCondition eq(Object value) {
return new PropertyCondition(this, "=?", value);
}
/** Creates an "not equal ('<>')" condition for this property. */
public WhereCondition notEq(Object value) {
return new PropertyCondition(this, "<>?", value);
}
/** Creates an "LIKE" condition for this property. */
public WhereCondition like(String value) {
return new PropertyCondition(this, " LIKE ?", value);
}
/** Creates an "BETWEEN ... AND ..." condition for this property. */
public WhereCondition between(Object value1, Object value2) {
Object[] values = { value1, value2 };
return new PropertyCondition(this, " BETWEEN ? AND ?", values);
}
/** Creates an "IN (..., ..., ...)" condition for this property. */
public WhereCondition in(Object... inValues) {
StringBuilder condition = new StringBuilder(" IN (");
SqlUtils.appendPlaceholders(condition, inValues.length).append(')');
return new PropertyCondition(this, condition.toString(), inValues);
}
/** Creates an "IN (..., ..., ...)" condition for this property. */
public WhereCondition in(Collection> inValues) {
return in(inValues.toArray());
}
/** Creates an "NOT IN (..., ..., ...)" condition for this property. */
public WhereCondition notIn(Object... notInValues) {
StringBuilder condition = new StringBuilder(" NOT IN (");
SqlUtils.appendPlaceholders(condition, notInValues.length).append(')');
return new PropertyCondition(this, condition.toString(), notInValues);
}
/** Creates an "NOT IN (..., ..., ...)" condition for this property. */
public WhereCondition notIn(Collection> notInValues) {
return notIn(notInValues.toArray());
}
/** Creates an "greater than ('>')" condition for this property. */
public WhereCondition gt(Object value) {
return new PropertyCondition(this, ">?", value);
}
/** Creates an "less than ('<')" condition for this property. */
public WhereCondition lt(Object value) {
return new PropertyCondition(this, "", value);
}
/** Creates an "greater or equal ('>=')" condition for this property. */
public WhereCondition ge(Object value) {
return new PropertyCondition(this, ">=?", value);
}
/** Creates an "less or equal ('<=')" condition for this property. */
public WhereCondition le(Object value) {
return new PropertyCondition(this, "<=?", value);
}
/** Creates an "IS NULL" condition for this property. */
public WhereCondition isNull() {
return new PropertyCondition(this, " IS NULL");
}
/** Creates an "IS NOT NULL" condition for this property. */
public WhereCondition isNotNull() {
return new PropertyCondition(this, " IS NOT NULL");
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/async/AsyncDaoException.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.async;
import org.greenrobot.greendao.DaoException;
/**
* Used here: {@link AsyncOperation#getResult()}.
*
* @author Markus
*/
public class AsyncDaoException extends DaoException {
private static final long serialVersionUID = 5872157552005102382L;
private final AsyncOperation failedOperation;
public AsyncDaoException(AsyncOperation failedOperation, Throwable cause) {
super(cause);
this.failedOperation = failedOperation;
}
public AsyncOperation getFailedOperation() {
return failedOperation;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/async/AsyncOperation.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.async;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.DaoException;
import org.greenrobot.greendao.database.Database;
/**
* An operation that will be enqueued for asynchronous execution.
*
* @author Markus
* @see AsyncSession
*/
// TODO Implement Future
public class AsyncOperation {
public enum OperationType {
Insert, InsertInTxIterable, InsertInTxArray, //
InsertOrReplace, InsertOrReplaceInTxIterable, InsertOrReplaceInTxArray, //
Update, UpdateInTxIterable, UpdateInTxArray, //
Delete, DeleteInTxIterable, DeleteInTxArray, //
DeleteByKey, DeleteAll, //
TransactionRunnable, TransactionCallable, //
QueryList, QueryUnique, //
Load, LoadAll, //
Count, Refresh
}
public static final int FLAG_MERGE_TX = 1;
/** TODO unused, just an idea */
public static final int FLAG_STOP_QUEUE_ON_EXCEPTION = 1 << 1;
public static final int FLAG_TRACK_CREATOR_STACKTRACE = 1 << 2;
final OperationType type;
final AbstractDao dao;
private final Database database;
/** Entity, Iterable, Entity[], or Runnable. */
final Object parameter;
final int flags;
volatile long timeStarted;
volatile long timeCompleted;
private volatile boolean completed;
volatile Throwable throwable;
final Exception creatorStacktrace;
volatile Object result;
volatile int mergedOperationsCount;
int sequenceNumber;
@SuppressWarnings("unchecked")
/** Either supply dao or database (set other to null). */
AsyncOperation(OperationType type, AbstractDao, ?> dao, Database database, Object parameter, int flags) {
this.type = type;
this.flags = flags;
this.dao = (AbstractDao) dao;
this.database = database;
this.parameter = parameter;
creatorStacktrace = (flags & FLAG_TRACK_CREATOR_STACKTRACE) != 0 ? new Exception("AsyncOperation was created here") : null;
}
public Throwable getThrowable() {
return throwable;
}
public void setThrowable(Throwable throwable) {
this.throwable = throwable;
}
public OperationType getType() {
return type;
}
public Object getParameter() {
return parameter;
}
/**
* The operation's result after it has completed. Waits until a result is available.
*
* @return The operation's result or null if the operation type does not produce any result.
* @throws {@link AsyncDaoException} if the operation produced an exception
* @see #waitForCompletion()
*/
public synchronized Object getResult() {
if (!completed) {
waitForCompletion();
}
if (throwable != null) {
throw new AsyncDaoException(this, throwable);
}
return result;
}
/** @return true if this operation may be merged with others into a single database transaction. */
public boolean isMergeTx() {
return (flags & FLAG_MERGE_TX) != 0;
}
Database getDatabase() {
return database != null ? database : dao.getDatabase();
}
/**
* @return true if this operation is mergeable with the given operation. Checks for null, {@link #FLAG_MERGE_TX},
* and if the database instances match.
*/
boolean isMergeableWith(AsyncOperation other) {
return other != null && isMergeTx() && other.isMergeTx() && getDatabase() == other.getDatabase();
}
public long getTimeStarted() {
return timeStarted;
}
public long getTimeCompleted() {
return timeCompleted;
}
public long getDuration() {
if (timeCompleted == 0) {
throw new DaoException("This operation did not yet complete");
} else {
return timeCompleted - timeStarted;
}
}
public boolean isFailed() {
return throwable != null;
}
public boolean isCompleted() {
return completed;
}
/**
* Waits until the operation is complete. If the thread gets interrupted, any {@link InterruptedException} will be
* rethrown as a {@link DaoException}.
*
* @return Result if any, see {@link #getResult()}
*/
public synchronized Object waitForCompletion() {
while (!completed) {
try {
wait();
} catch (InterruptedException e) {
throw new DaoException("Interrupted while waiting for operation to complete", e);
}
}
return result;
}
/**
* Waits until the operation is complete, but at most the given amount of milliseconds.If the thread gets
* interrupted, any {@link InterruptedException} will be rethrown as a {@link DaoException}.
*
* @return true if the operation completed in the given time frame.
*/
public synchronized boolean waitForCompletion(int maxMillis) {
if (!completed) {
try {
wait(maxMillis);
} catch (InterruptedException e) {
throw new DaoException("Interrupted while waiting for operation to complete", e);
}
}
return completed;
}
/** Called when the operation is done. Notifies any threads waiting for this operation's completion. */
synchronized void setCompleted() {
completed = true;
notifyAll();
}
public boolean isCompletedSucessfully() {
return completed && throwable == null;
}
/**
* If this operation was successfully merged with other operation into a single TX, this will give the count of
* merged operations. If the operation was not merged, it will be 0.
*/
public int getMergedOperationsCount() {
return mergedOperationsCount;
}
/**
* Each operation get a unique sequence number when the operation is enqueued. Can be used for efficiently
* identifying/mapping operations.
*/
public int getSequenceNumber() {
return sequenceNumber;
}
/** Reset to prepare another execution run. */
void reset() {
timeStarted = 0;
timeCompleted = 0;
completed = false;
throwable = null;
result = null;
mergedOperationsCount = 0;
}
/**
* The stacktrace is captured using an exception if {@link #FLAG_TRACK_CREATOR_STACKTRACE} was used (null
* otherwise).
*/
public Exception getCreatorStacktrace() {
return creatorStacktrace;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/async/AsyncOperationExecutor.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.async;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import org.greenrobot.greendao.DaoException;
import org.greenrobot.greendao.DaoLog;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.query.Query;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
class AsyncOperationExecutor implements Runnable, Handler.Callback {
private static ExecutorService executorService = Executors.newCachedThreadPool();
private final BlockingQueue queue;
private volatile boolean executorRunning;
private volatile int maxOperationCountToMerge;
private volatile AsyncOperationListener listener;
private volatile AsyncOperationListener listenerMainThread;
private volatile int waitForMergeMillis;
private int countOperationsEnqueued;
private int countOperationsCompleted;
private Handler handlerMainThread;
private int lastSequenceNumber;
AsyncOperationExecutor() {
queue = new LinkedBlockingQueue();
maxOperationCountToMerge = 50;
waitForMergeMillis = 50;
}
public void enqueue(AsyncOperation operation) {
synchronized (this) {
operation.sequenceNumber = ++lastSequenceNumber;
queue.add(operation);
countOperationsEnqueued++;
if (!executorRunning) {
executorRunning = true;
executorService.execute(this);
}
}
}
public int getMaxOperationCountToMerge() {
return maxOperationCountToMerge;
}
public void setMaxOperationCountToMerge(int maxOperationCountToMerge) {
this.maxOperationCountToMerge = maxOperationCountToMerge;
}
public int getWaitForMergeMillis() {
return waitForMergeMillis;
}
public void setWaitForMergeMillis(int waitForMergeMillis) {
this.waitForMergeMillis = waitForMergeMillis;
}
public AsyncOperationListener getListener() {
return listener;
}
public void setListener(AsyncOperationListener listener) {
this.listener = listener;
}
public AsyncOperationListener getListenerMainThread() {
return listenerMainThread;
}
public void setListenerMainThread(AsyncOperationListener listenerMainThread) {
this.listenerMainThread = listenerMainThread;
}
public synchronized boolean isCompleted() {
return countOperationsEnqueued == countOperationsCompleted;
}
/**
* Waits until all enqueued operations are complete. If the thread gets interrupted, any
* {@link InterruptedException} will be rethrown as a {@link DaoException}.
*/
public synchronized void waitForCompletion() {
while (!isCompleted()) {
try {
wait();
} catch (InterruptedException e) {
throw new DaoException("Interrupted while waiting for all operations to complete", e);
}
}
}
/**
* Waits until all enqueued operations are complete, but at most the given amount of milliseconds. If the thread
* gets interrupted, any {@link InterruptedException} will be rethrown as a {@link DaoException}.
*
* @return true if operations completed in the given time frame.
*/
public synchronized boolean waitForCompletion(int maxMillis) {
if (!isCompleted()) {
try {
wait(maxMillis);
} catch (InterruptedException e) {
throw new DaoException("Interrupted while waiting for all operations to complete", e);
}
}
return isCompleted();
}
@Override
public void run() {
try {
try {
while (true) {
AsyncOperation operation = queue.poll(1, TimeUnit.SECONDS);
if (operation == null) {
synchronized (this) {
// Check again, this time in synchronized to be in sync with enqueue(AsyncOperation)
operation = queue.poll();
if (operation == null) {
// set flag while still inside synchronized
executorRunning = false;
return;
}
}
}
if (operation.isMergeTx()) {
// Wait some ms for another operation to merge because a TX is expensive
AsyncOperation operation2 = queue.poll(waitForMergeMillis, TimeUnit.MILLISECONDS);
if (operation2 != null) {
if (operation.isMergeableWith(operation2)) {
mergeTxAndExecute(operation, operation2);
} else {
// Cannot merge, execute both
executeOperationAndPostCompleted(operation);
executeOperationAndPostCompleted(operation2);
}
continue;
}
}
executeOperationAndPostCompleted(operation);
}
} catch (InterruptedException e) {
DaoLog.w(Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
/** Also checks for other operations in the queue that can be merged into the transaction. */
private void mergeTxAndExecute(AsyncOperation operation1, AsyncOperation operation2) {
ArrayList mergedOps = new ArrayList();
mergedOps.add(operation1);
mergedOps.add(operation2);
Database db = operation1.getDatabase();
db.beginTransaction();
boolean success = false;
try {
for (int i = 0; i < mergedOps.size(); i++) {
AsyncOperation operation = mergedOps.get(i);
executeOperation(operation);
if (operation.isFailed()) {
// Operation may still have changed the DB, roll back everything
break;
}
if (i == mergedOps.size() - 1) {
AsyncOperation peekedOp = queue.peek();
if (i < maxOperationCountToMerge && operation.isMergeableWith(peekedOp)) {
AsyncOperation removedOp = queue.remove();
if (removedOp != peekedOp) {
// Paranoia check, should not occur unless threading is broken
throw new DaoException("Internal error: peeked op did not match removed op");
}
mergedOps.add(removedOp);
} else {
// No more ops in the queue to merge, finish it
db.setTransactionSuccessful();
success = true;
break;
}
}
}
} finally {
try {
db.endTransaction();
} catch (RuntimeException e) {
DaoLog.i("Async transaction could not be ended, success so far was: " + success, e);
success = false;
}
}
if (success) {
int mergedCount = mergedOps.size();
for (AsyncOperation asyncOperation : mergedOps) {
asyncOperation.mergedOperationsCount = mergedCount;
handleOperationCompleted(asyncOperation);
}
} else {
DaoLog.i("Reverted merged transaction because one of the operations failed. Executing operations one by " +
"one instead...");
for (AsyncOperation asyncOperation : mergedOps) {
asyncOperation.reset();
executeOperationAndPostCompleted(asyncOperation);
}
}
}
private void handleOperationCompleted(AsyncOperation operation) {
operation.setCompleted();
AsyncOperationListener listenerToCall = listener;
if (listenerToCall != null) {
listenerToCall.onAsyncOperationCompleted(operation);
}
if (listenerMainThread != null) {
if (handlerMainThread == null) {
handlerMainThread = new Handler(Looper.getMainLooper(), this);
}
Message msg = handlerMainThread.obtainMessage(1, operation);
handlerMainThread.sendMessage(msg);
}
synchronized (this) {
countOperationsCompleted++;
if (countOperationsCompleted == countOperationsEnqueued) {
notifyAll();
}
}
}
private void executeOperationAndPostCompleted(AsyncOperation operation) {
executeOperation(operation);
handleOperationCompleted(operation);
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void executeOperation(AsyncOperation operation) {
operation.timeStarted = System.currentTimeMillis();
try {
switch (operation.type) {
case Delete:
operation.dao.delete(operation.parameter);
break;
case DeleteInTxIterable:
operation.dao.deleteInTx((Iterable) operation.parameter);
break;
case DeleteInTxArray:
operation.dao.deleteInTx((Object[]) operation.parameter);
break;
case Insert:
operation.dao.insert(operation.parameter);
break;
case InsertInTxIterable:
operation.dao.insertInTx((Iterable) operation.parameter);
break;
case InsertInTxArray:
operation.dao.insertInTx((Object[]) operation.parameter);
break;
case InsertOrReplace:
operation.dao.insertOrReplace(operation.parameter);
break;
case InsertOrReplaceInTxIterable:
operation.dao.insertOrReplaceInTx((Iterable) operation.parameter);
break;
case InsertOrReplaceInTxArray:
operation.dao.insertOrReplaceInTx((Object[]) operation.parameter);
break;
case Update:
operation.dao.update(operation.parameter);
break;
case UpdateInTxIterable:
operation.dao.updateInTx((Iterable) operation.parameter);
break;
case UpdateInTxArray:
operation.dao.updateInTx((Object[]) operation.parameter);
break;
case TransactionRunnable:
executeTransactionRunnable(operation);
break;
case TransactionCallable:
executeTransactionCallable(operation);
break;
case QueryList:
operation.result = ((Query) operation.parameter).forCurrentThread().list();
break;
case QueryUnique:
operation.result = ((Query) operation.parameter).forCurrentThread().unique();
break;
case DeleteByKey:
operation.dao.deleteByKey(operation.parameter);
break;
case DeleteAll:
operation.dao.deleteAll();
break;
case Load:
operation.result = operation.dao.load(operation.parameter);
break;
case LoadAll:
operation.result = operation.dao.loadAll();
break;
case Count:
operation.result = operation.dao.count();
break;
case Refresh:
operation.dao.refresh(operation.parameter);
break;
default:
throw new DaoException("Unsupported operation: " + operation.type);
}
} catch (Throwable th) {
operation.throwable = th;
}
operation.timeCompleted = System.currentTimeMillis();
// Do not set it to completed here because it might be a merged TX
}
private void executeTransactionRunnable(AsyncOperation operation) {
Database db = operation.getDatabase();
db.beginTransaction();
try {
((Runnable) operation.parameter).run();
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
@SuppressWarnings("unchecked")
private void executeTransactionCallable(AsyncOperation operation) throws Exception {
Database db = operation.getDatabase();
db.beginTransaction();
try {
operation.result = ((Callable) operation.parameter).call();
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
@Override
public boolean handleMessage(Message msg) {
AsyncOperationListener listenerToCall = listenerMainThread;
if (listenerToCall != null) {
listenerToCall.onAsyncOperationCompleted((AsyncOperation) msg.obj);
}
return false;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/async/AsyncOperationListener.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.async;
/** Listener being called after completion of {@link org.greenrobot.greendao.async.AsyncOperation}. */
public interface AsyncOperationListener {
/**
* Note, that the operation may not have been successful, check
* {@link AsyncOperation#isFailed()} and/or {@link AsyncOperation#getThrowable()} for error situations.
*/
void onAsyncOperationCompleted(AsyncOperation operation);
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/async/AsyncSession.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.async;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.AbstractDaoSession;
import org.greenrobot.greendao.DaoException;
import org.greenrobot.greendao.async.AsyncOperation.OperationType;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.query.Query;
import java.util.concurrent.Callable;
/**
* Asynchronous interface to entity operations. All operations will enqueued a @link {@link AsyncOperation} and return
* immediately (fine to call on the UI/main thread). The queue will be processed in a (single) background thread. The
* processing order is the call order of the operations. It's possible to start multiple AsyncSessions that will
* execute
* concurrently.
*
* @author Markus
* @see AbstractDaoSession#startAsyncSession()
*/
// Facade to AsyncOperationExecutor: prepares operations and delegates work to AsyncOperationExecutor.
public class AsyncSession {
private final AbstractDaoSession daoSession;
private final AsyncOperationExecutor executor;
private int sessionFlags;
public AsyncSession(AbstractDaoSession daoSession) {
this.daoSession = daoSession;
this.executor = new AsyncOperationExecutor();
}
public int getMaxOperationCountToMerge() {
return executor.getMaxOperationCountToMerge();
}
public void setMaxOperationCountToMerge(int maxOperationCountToMerge) {
executor.setMaxOperationCountToMerge(maxOperationCountToMerge);
}
public int getWaitForMergeMillis() {
return executor.getWaitForMergeMillis();
}
public void setWaitForMergeMillis(int waitForMergeMillis) {
executor.setWaitForMergeMillis(waitForMergeMillis);
}
public AsyncOperationListener getListener() {
return executor.getListener();
}
public void setListener(AsyncOperationListener listener) {
executor.setListener(listener);
}
public AsyncOperationListener getListenerMainThread() {
return executor.getListenerMainThread();
}
public void setListenerMainThread(AsyncOperationListener listenerMainThread) {
executor.setListenerMainThread(listenerMainThread);
}
public boolean isCompleted() {
return executor.isCompleted();
}
/**
* Waits until all enqueued operations are complete. If the thread gets interrupted, any
* {@link InterruptedException} will be rethrown as a {@link DaoException}.
*/
public void waitForCompletion() {
executor.waitForCompletion();
}
/**
* Waits until all enqueued operations are complete, but at most the given amount of milliseconds. If the thread
* gets interrupted, any {@link InterruptedException} will be rethrown as a {@link DaoException}.
*
* @return true if operations completed in the given time frame.
*/
public boolean waitForCompletion(int maxMillis) {
return executor.waitForCompletion(maxMillis);
}
/** Asynchronous version of {@link AbstractDao#insert(Object)}. */
public AsyncOperation insert(Object entity) {
return insert(entity, 0);
}
/** Asynchronous version of {@link AbstractDao#insert(Object)}. */
public AsyncOperation insert(Object entity, int flags) {
return enqueueEntityOperation(OperationType.Insert, entity, flags);
}
/** Asynchronous version of {@link AbstractDao#insertInTx(Object...)}. */
public AsyncOperation insertInTx(Class entityClass, E... entities) {
return insertInTx(entityClass, 0, entities);
}
/** Asynchronous version of {@link AbstractDao#insertInTx(Object...)}. */
public AsyncOperation insertInTx(Class entityClass, int flags, E... entities) {
return enqueEntityOperation(OperationType.InsertInTxArray, entityClass, entities, flags);
}
/** Asynchronous version of {@link AbstractDao#insertInTx(Iterable)}. */
public AsyncOperation insertInTx(Class entityClass, Iterable entities) {
return insertInTx(entityClass, entities, 0);
}
/** Asynchronous version of {@link AbstractDao#insertInTx(Iterable)}. */
public AsyncOperation insertInTx(Class entityClass, Iterable entities, int flags) {
return enqueEntityOperation(OperationType.InsertInTxIterable, entityClass, entities, flags);
}
/** Asynchronous version of {@link AbstractDao#insertOrReplace(Object)}. */
public AsyncOperation insertOrReplace(Object entity) {
return insertOrReplace(entity, 0);
}
/** Asynchronous version of {@link AbstractDao#insertOrReplace(Object)}. */
public AsyncOperation insertOrReplace(Object entity, int flags) {
return enqueueEntityOperation(OperationType.InsertOrReplace, entity, flags);
}
/** Asynchronous version of {@link AbstractDao#insertOrReplaceInTx(Object...)}. */
public AsyncOperation insertOrReplaceInTx(Class entityClass, E... entities) {
return insertOrReplaceInTx(entityClass, 0, entities);
}
/** Asynchronous version of {@link AbstractDao#insertOrReplaceInTx(Object...)}. */
public AsyncOperation insertOrReplaceInTx(Class entityClass, int flags, E... entities) {
return enqueEntityOperation(OperationType.InsertOrReplaceInTxArray, entityClass, entities, flags);
}
/** Asynchronous version of {@link AbstractDao#insertOrReplaceInTx(Iterable)}. */
public AsyncOperation insertOrReplaceInTx(Class entityClass, Iterable entities) {
return insertOrReplaceInTx(entityClass, entities, 0);
}
/** Asynchronous version of {@link AbstractDao#insertOrReplaceInTx(Iterable)}. */
public AsyncOperation insertOrReplaceInTx(Class entityClass, Iterable entities, int flags) {
return enqueEntityOperation(OperationType.InsertOrReplaceInTxIterable, entityClass, entities, flags);
}
/** Asynchronous version of {@link AbstractDao#update(Object)}. */
public AsyncOperation update(Object entity) {
return update(entity, 0);
}
/** Asynchronous version of {@link AbstractDao#update(Object)}. */
public AsyncOperation update(Object entity, int flags) {
return enqueueEntityOperation(OperationType.Update, entity, flags);
}
/** Asynchronous version of {@link AbstractDao#updateInTx(Object...)}. */
public AsyncOperation updateInTx(Class entityClass, E... entities) {
return updateInTx(entityClass, 0, entities);
}
/** Asynchronous version of {@link AbstractDao#updateInTx(Object...)}. */
public AsyncOperation updateInTx(Class entityClass, int flags, E... entities) {
return enqueEntityOperation(OperationType.UpdateInTxArray, entityClass, entities, flags);
}
/** Asynchronous version of {@link AbstractDao#updateInTx(Iterable)}. */
public AsyncOperation updateInTx(Class entityClass, Iterable entities) {
return updateInTx(entityClass, entities, 0);
}
/** Asynchronous version of {@link AbstractDao#updateInTx(Iterable)}. */
public AsyncOperation updateInTx(Class entityClass, Iterable entities, int flags) {
return enqueEntityOperation(OperationType.UpdateInTxIterable, entityClass, entities, flags);
}
/** Asynchronous version of {@link AbstractDao#delete(Object)}. */
public AsyncOperation delete(Object entity) {
return delete(entity, 0);
}
/** Asynchronous version of {@link AbstractDao#delete(Object)}. */
public AsyncOperation delete(Object entity, int flags) {
return enqueueEntityOperation(OperationType.Delete, entity, flags);
}
/** Asynchronous version of {@link AbstractDao#deleteByKey(Object)}. */
public AsyncOperation deleteByKey(Object key) {
return deleteByKey(key, 0);
}
/** Asynchronous version of {@link AbstractDao#deleteByKey(Object)}. */
public AsyncOperation deleteByKey(Object key, int flags) {
return enqueueEntityOperation(OperationType.DeleteByKey, key, flags);
}
/** Asynchronous version of {@link AbstractDao#deleteInTx(Object...)}. */
public AsyncOperation deleteInTx(Class entityClass, E... entities) {
return deleteInTx(entityClass, 0, entities);
}
/** Asynchronous version of {@link AbstractDao#deleteInTx(Object...)}. */
public AsyncOperation deleteInTx(Class entityClass, int flags, E... entities) {
return enqueEntityOperation(OperationType.DeleteInTxArray, entityClass, entities, flags);
}
/** Asynchronous version of {@link AbstractDao#deleteInTx(Iterable)}. */
public AsyncOperation deleteInTx(Class entityClass, Iterable entities) {
return deleteInTx(entityClass, entities, 0);
}
/** Asynchronous version of {@link AbstractDao#deleteInTx(Iterable)}. */
public AsyncOperation deleteInTx(Class entityClass, Iterable entities, int flags) {
return enqueEntityOperation(OperationType.DeleteInTxIterable, entityClass, entities, flags);
}
/** Asynchronous version of {@link AbstractDao#deleteAll()}. */
public AsyncOperation deleteAll(Class entityClass) {
return deleteAll(entityClass, 0);
}
/** Asynchronous version of {@link AbstractDao#deleteAll()}. */
public AsyncOperation deleteAll(Class entityClass, int flags) {
return enqueEntityOperation(OperationType.DeleteAll, entityClass, null, flags);
}
/** Asynchronous version of {@link AbstractDaoSession#runInTx(Runnable)}. */
public AsyncOperation runInTx(Runnable runnable) {
return runInTx(runnable, 0);
}
/** Asynchronous version of {@link AbstractDaoSession#runInTx(Runnable)}. */
public AsyncOperation runInTx(Runnable runnable, int flags) {
return enqueueDatabaseOperation(OperationType.TransactionRunnable, runnable, flags);
}
/** Asynchronous version of {@link AbstractDaoSession#callInTx(Callable)}. */
public AsyncOperation callInTx(Callable> callable) {
return callInTx(callable, 0);
}
/** Asynchronous version of {@link AbstractDaoSession#callInTx(Callable)}. */
public AsyncOperation callInTx(Callable> callable, int flags) {
return enqueueDatabaseOperation(OperationType.TransactionCallable, callable, flags);
}
/** Asynchronous version of {@link Query#list()}. */
public AsyncOperation queryList(Query> query) {
return queryList(query, 0);
}
/** Asynchronous version of {@link Query#list()}. */
public AsyncOperation queryList(Query> query, int flags) {
return enqueueDatabaseOperation(OperationType.QueryList, query, flags);
}
/** Asynchronous version of {@link Query#unique()}. */
public AsyncOperation queryUnique(Query> query) {
return queryUnique(query, 0);
}
/** Asynchronous version of {@link Query#unique()}. */
public AsyncOperation queryUnique(Query> query, int flags) {
return enqueueDatabaseOperation(OperationType.QueryUnique, query, flags);
}
/** Asynchronous version of {@link AbstractDao#load(Object)}. */
public AsyncOperation load(Class> entityClass, Object key) {
return load(entityClass, key, 0);
}
/** Asynchronous version of {@link AbstractDao#load(Object)}. */
public AsyncOperation load(Class> entityClass, Object key, int flags) {
return enqueEntityOperation(OperationType.Load, entityClass, key, flags);
}
/** Asynchronous version of {@link AbstractDao#loadAll()}. */
public AsyncOperation loadAll(Class> entityClass) {
return loadAll(entityClass, 0);
}
/** Asynchronous version of {@link AbstractDao#loadAll()}. */
public AsyncOperation loadAll(Class> entityClass, int flags) {
return enqueEntityOperation(OperationType.LoadAll, entityClass, null, flags);
}
/** Asynchronous version of {@link AbstractDao#count()}. */
public AsyncOperation count(Class> entityClass) {
return count(entityClass, 0);
}
/** Asynchronous version of {@link AbstractDao#count()}. */
public AsyncOperation count(Class> entityClass, int flags) {
return enqueEntityOperation(OperationType.Count, entityClass, null, flags);
}
/** Asynchronous version of {@link AbstractDao#refresh(Object)}. */
public AsyncOperation refresh(Object entity) {
return refresh(entity, 0);
}
/** Asynchronous version of {@link AbstractDao#refresh(Object)}. */
public AsyncOperation refresh(Object entity, int flags) {
return enqueueEntityOperation(OperationType.Refresh, entity, flags);
}
private AsyncOperation enqueueDatabaseOperation(OperationType type, Object param, int flags) {
Database database = daoSession.getDatabase();
AsyncOperation operation = new AsyncOperation(type, null, database, param, flags | sessionFlags);
executor.enqueue(operation);
return operation;
}
private AsyncOperation enqueueEntityOperation(OperationType type, Object entity, int flags) {
return enqueEntityOperation(type, entity.getClass(), entity, flags);
}
private AsyncOperation enqueEntityOperation(OperationType type, Class entityClass, Object param, int flags) {
AbstractDao, ?> dao = daoSession.getDao(entityClass);
AsyncOperation operation = new AsyncOperation(type, dao, null, param, flags | sessionFlags);
executor.enqueue(operation);
return operation;
}
/** {@link org.greenrobot.greendao.async.AsyncOperation} flags set for all operations (will be ORed with call flags). */
public int getSessionFlags() {
return sessionFlags;
}
/** {@link org.greenrobot.greendao.async.AsyncOperation} flags set for all operations (will be ORed with call flags). */
public void setSessionFlags(int sessionFlags) {
this.sessionFlags = sessionFlags;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/database/Database.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.database;
import android.database.Cursor;
import android.database.SQLException;
/**
* Database abstraction used internally by greenDAO.
*/
public interface Database {
Cursor rawQuery(String sql, String[] selectionArgs);
void execSQL(String sql) throws SQLException;
void beginTransaction();
void endTransaction();
boolean inTransaction();
void setTransactionSuccessful();
void execSQL(String sql, Object[] bindArgs) throws SQLException;
DatabaseStatement compileStatement(String sql);
boolean isDbLockedByCurrentThread();
boolean isOpen();
void close();
Object getRawDatabase();
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/database/DatabaseOpenHelper.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.database;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import org.greenrobot.greendao.DaoException;
import java.lang.reflect.Constructor;
/**
* SQLiteOpenHelper to allow working with greenDAO's {@link Database} abstraction to create and update database schemas.
*/
public abstract class DatabaseOpenHelper extends SQLiteOpenHelper {
private final Context context;
private final String name;
private final int version;
private EncryptedHelper encryptedHelper;
private boolean loadSQLCipherNativeLibs = true;
public DatabaseOpenHelper(Context context, String name, int version) {
this(context, name, null, version);
}
public DatabaseOpenHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
this.context = context;
this.name = name;
this.version = version;
}
@SuppressLint("NewApi")
public DatabaseOpenHelper(Context context, String name, CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {
super(context, name, factory, version, errorHandler);
this.context = context;
this.name = name;
this.version = version;
}
/**
* Flag to load SQLCipher native libs (default: true).
*/
public void setLoadSQLCipherNativeLibs(boolean loadSQLCipherNativeLibs) {
this.loadSQLCipherNativeLibs = loadSQLCipherNativeLibs;
}
/**
* Like {@link #getWritableDatabase()}, but returns a greenDAO abstraction of the database.
* The backing DB is an standard {@link SQLiteDatabase}.
*/
public Database getWritableDb() {
return wrap(getWritableDatabase());
}
/**
* Like {@link #getReadableDatabase()}, but returns a greenDAO abstraction of the database.
* The backing DB is an standard {@link SQLiteDatabase}.
*/
public Database getReadableDb() {
return wrap(getReadableDatabase());
}
protected Database wrap(SQLiteDatabase sqLiteDatabase) {
return new StandardDatabase(sqLiteDatabase);
}
/**
* Delegates to {@link #onCreate(Database)}, which uses greenDAO's database abstraction.
*/
@Override
public void onCreate(SQLiteDatabase db) {
onCreate(wrap(db));
}
/**
* Override this if you do not want to depend on {@link SQLiteDatabase}.
*/
public void onCreate(Database db) {
// Do nothing by default
}
/**
* Delegates to {@link #onUpgrade(Database, int, int)}, which uses greenDAO's database abstraction.
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(wrap(db), oldVersion, newVersion);
}
/**
* Override this if you do not want to depend on {@link SQLiteDatabase}.
*/
public void onUpgrade(Database db, int oldVersion, int newVersion) {
// Do nothing by default
}
/**
* Delegates to {@link #onOpen(Database)}, which uses greenDAO's database abstraction.
*/
@Override
public void onOpen(SQLiteDatabase db) {
onOpen(wrap(db));
}
/**
* Override this if you do not want to depend on {@link SQLiteDatabase}.
*/
public void onOpen(Database db) {
// Do nothing by default
}
interface EncryptedHelper {
Database getEncryptedReadableDb(String password);
Database getEncryptedReadableDb(char[] password);
Database getEncryptedWritableDb(String password);
Database getEncryptedWritableDb(char[] password);
}
private EncryptedHelper checkEncryptedHelper() {
if (encryptedHelper == null) {
try {
Class.forName("net.sqlcipher.database.SQLiteOpenHelper");
} catch (ClassNotFoundException e) {
throw new DaoException("Using an encrypted database requires SQLCipher, " +
"make sure to add it to dependencies: " +
"https://greenrobot.org/greendao/documentation/database-encryption/");
}
// Avoid referencing SqlCipherEncryptedHelper to avoid
// "Rejecting re-init on previously-failed class java.lang.NoClassDefFoundError" logs
// if SQLCipher is not in classpath.
try {
Class> helperClass = Class.forName(
"org.greenrobot.greendao.database.SqlCipherEncryptedHelper");
Constructor> constructor = helperClass.getConstructor(
DatabaseOpenHelper.class, Context.class, String.class, int.class, boolean.class);
encryptedHelper = (EncryptedHelper) constructor.newInstance(
this, context, name, version, loadSQLCipherNativeLibs);
} catch (Exception e) {
throw new DaoException(e);
}
}
return encryptedHelper;
}
/**
* Use this to initialize an encrypted SQLCipher database.
*
* @see #onCreate(Database)
* @see #onUpgrade(Database, int, int)
*/
public Database getEncryptedWritableDb(String password) {
EncryptedHelper encryptedHelper = checkEncryptedHelper();
return encryptedHelper.getEncryptedWritableDb(password);
}
/**
* Use this to initialize an encrypted SQLCipher database.
*
* @see #onCreate(Database)
* @see #onUpgrade(Database, int, int)
*/
public Database getEncryptedWritableDb(char[] password) {
EncryptedHelper encryptedHelper = checkEncryptedHelper();
return encryptedHelper.getEncryptedWritableDb(password);
}
/**
* Use this to initialize an encrypted SQLCipher database.
*
* @see #onCreate(Database)
* @see #onUpgrade(Database, int, int)
*/
public Database getEncryptedReadableDb(String password) {
EncryptedHelper encryptedHelper = checkEncryptedHelper();
return encryptedHelper.getEncryptedReadableDb(password);
}
/**
* Use this to initialize an encrypted SQLCipher database.
*
* @see #onCreate(Database)
* @see #onUpgrade(Database, int, int)
*/
public Database getEncryptedReadableDb(char[] password) {
EncryptedHelper encryptedHelper = checkEncryptedHelper();
return encryptedHelper.getEncryptedReadableDb(password);
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/database/DatabaseStatement.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.database;
public interface DatabaseStatement {
void execute();
long simpleQueryForLong();
void bindNull(int index);
long executeInsert();
void bindString(int index, String value);
void bindBlob(int index, byte[] value);
void bindLong(int index, long value);
void clearBindings();
void bindDouble(int index, double value);
void close();
Object getRawStatement();
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/database/EncryptedDatabase.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.database;
import android.database.Cursor;
import android.database.SQLException;
import net.sqlcipher.database.SQLiteDatabase;
public class EncryptedDatabase implements Database {
private final SQLiteDatabase delegate;
public EncryptedDatabase(SQLiteDatabase delegate) {
this.delegate = delegate;
}
@Override
public Cursor rawQuery(String sql, String[] selectionArgs) {
return delegate.rawQuery(sql, selectionArgs);
}
@Override
public void execSQL(String sql) throws SQLException {
delegate.execSQL(sql);
}
@Override
public void beginTransaction() {
delegate.beginTransaction();
}
@Override
public void endTransaction() {
delegate.endTransaction();
}
@Override
public boolean inTransaction() {
return delegate.inTransaction();
}
@Override
public void setTransactionSuccessful() {
delegate.setTransactionSuccessful();
}
@Override
public void execSQL(String sql, Object[] bindArgs) throws SQLException {
delegate.execSQL(sql, bindArgs);
}
@Override
public DatabaseStatement compileStatement(String sql) {
return new EncryptedDatabaseStatement(delegate.compileStatement(sql));
}
@Override
public boolean isDbLockedByCurrentThread() {
return delegate.isDbLockedByCurrentThread();
}
@Override
public boolean isOpen() {
return delegate.isOpen();
}
@Override
public void close() {
delegate.close();
}
@Override
public Object getRawDatabase() {
return delegate;
}
public SQLiteDatabase getSQLiteDatabase() {
return delegate;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/database/EncryptedDatabaseStatement.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.database;
import net.sqlcipher.database.SQLiteStatement;
public class EncryptedDatabaseStatement implements DatabaseStatement {
private final SQLiteStatement delegate;
public EncryptedDatabaseStatement(SQLiteStatement delegate) {
this.delegate = delegate;
}
@Override
public void execute() {
delegate.execute();
}
@Override
public long simpleQueryForLong() {
return delegate.simpleQueryForLong();
}
@Override
public void bindNull(int index) {
delegate.bindNull(index);
}
@Override
public long executeInsert() {
return delegate.executeInsert();
}
@Override
public void bindString(int index, String value) {
delegate.bindString(index, value);
}
@Override
public void bindBlob(int index, byte[] value) {
delegate.bindBlob(index, value);
}
@Override
public void bindLong(int index, long value) {
delegate.bindLong(index, value);
}
@Override
public void clearBindings() {
delegate.clearBindings();
}
@Override
public void bindDouble(int index, double value) {
delegate.bindDouble(index, value);
}
@Override
public void close() {
delegate.close();
}
@Override
public Object getRawStatement() {
return delegate;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/database/SqlCipherEncryptedHelper.java
================================================
package org.greenrobot.greendao.database;
import android.content.Context;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteOpenHelper;
class SqlCipherEncryptedHelper extends SQLiteOpenHelper implements DatabaseOpenHelper.EncryptedHelper {
private final DatabaseOpenHelper delegate;
public SqlCipherEncryptedHelper(DatabaseOpenHelper delegate, Context context, String name, int version, boolean loadLibs) {
super(context, name, null, version);
this.delegate = delegate;
if (loadLibs) {
SQLiteDatabase.loadLibs(context);
}
}
private Database wrap(SQLiteDatabase sqLiteDatabase) {
return new EncryptedDatabase(sqLiteDatabase);
}
@Override
public void onCreate(SQLiteDatabase db) {
delegate.onCreate(wrap(db));
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
delegate.onUpgrade(wrap(db), oldVersion, newVersion);
}
@Override
public void onOpen(SQLiteDatabase db) {
delegate.onOpen(wrap(db));
}
@Override
public Database getEncryptedReadableDb(String password) {
return wrap(getReadableDatabase(password));
}
@Override
public Database getEncryptedReadableDb(char[] password) {
return wrap(getReadableDatabase(password));
}
@Override
public Database getEncryptedWritableDb(String password) {
return wrap(getWritableDatabase(password));
}
@Override
public Database getEncryptedWritableDb(char[] password) {
return wrap(getWritableDatabase(password));
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/database/StandardDatabase.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.database;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
public class StandardDatabase implements Database {
private final SQLiteDatabase delegate;
public StandardDatabase(SQLiteDatabase delegate) {
this.delegate = delegate;
}
@Override
public Cursor rawQuery(String sql, String[] selectionArgs) {
return delegate.rawQuery(sql, selectionArgs);
}
@Override
public void execSQL(String sql) throws SQLException {
delegate.execSQL(sql);
}
@Override
public void beginTransaction() {
delegate.beginTransaction();
}
@Override
public void endTransaction() {
delegate.endTransaction();
}
@Override
public boolean inTransaction() {
return delegate.inTransaction();
}
@Override
public void setTransactionSuccessful() {
delegate.setTransactionSuccessful();
}
@Override
public void execSQL(String sql, Object[] bindArgs) throws SQLException {
delegate.execSQL(sql, bindArgs);
}
@Override
public DatabaseStatement compileStatement(String sql) {
return new StandardDatabaseStatement(delegate.compileStatement(sql));
}
@Override
public boolean isDbLockedByCurrentThread() {
return delegate.isDbLockedByCurrentThread();
}
@Override
public boolean isOpen() {
return delegate.isOpen();
}
@Override
public void close() {
delegate.close();
}
@Override
public Object getRawDatabase() {
return delegate;
}
public SQLiteDatabase getSQLiteDatabase() {
return delegate;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/database/StandardDatabaseStatement.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.database;
import android.database.sqlite.SQLiteStatement;
public class StandardDatabaseStatement implements DatabaseStatement {
private final SQLiteStatement delegate;
public StandardDatabaseStatement(SQLiteStatement delegate) {
this.delegate = delegate;
}
@Override
public void execute() {
delegate.execute();
}
@Override
public long simpleQueryForLong() {
return delegate.simpleQueryForLong();
}
@Override
public void bindNull(int index) {
delegate.bindNull(index);
}
@Override
public long executeInsert() {
return delegate.executeInsert();
}
@Override
public void bindString(int index, String value) {
delegate.bindString(index, value);
}
@Override
public void bindBlob(int index, byte[] value) {
delegate.bindBlob(index, value);
}
@Override
public void bindLong(int index, long value) {
delegate.bindLong(index, value);
}
@Override
public void clearBindings() {
delegate.clearBindings();
}
@Override
public void bindDouble(int index, double value) {
delegate.bindDouble(index, value);
}
@Override
public void close() {
delegate.close();
}
@Override
public Object getRawStatement() {
return delegate;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/identityscope/IdentityScope.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.identityscope;
/**
* Common interface for a identity scopes needed internally by greenDAO. Identity scopes let greenDAO re-use Java
* objects.
*
* @author Markus
*
* @param
* Key
* @param
* Entity
*/
public interface IdentityScope {
T get(K key);
void put(K key, T entity);
T getNoLock(K key);
void putNoLock(K key, T entity);
boolean detach(K key, T entity);
void remove(K key);
void remove(Iterable key);
void clear();
void lock();
void unlock();
void reserveRoom(int count);
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/identityscope/IdentityScopeLong.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.identityscope;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.concurrent.locks.ReentrantLock;
import org.greenrobot.greendao.internal.LongHashMap;
/**
* The context for entity identities. Provides the scope in which entities will be tracked and managed.
*
* @author Markus
* @param
* Entity
*/
public class IdentityScopeLong implements IdentityScope {
private final LongHashMap> map;
private final ReentrantLock lock;
public IdentityScopeLong() {
map = new LongHashMap>();
lock = new ReentrantLock();
}
@Override
public T get(Long key) {
return get2(key);
}
@Override
public T getNoLock(Long key) {
return get2NoLock(key);
}
public T get2(long key) {
lock.lock();
Reference ref;
try {
ref = map.get(key);
} finally {
lock.unlock();
}
if (ref != null) {
return ref.get();
} else {
return null;
}
}
public T get2NoLock(long key) {
Reference ref = map.get(key);
if (ref != null) {
return ref.get();
} else {
return null;
}
}
@Override
public void put(Long key, T entity) {
put2(key, entity);
}
@Override
public void putNoLock(Long key, T entity) {
put2NoLock(key, entity);
}
public void put2(long key, T entity) {
lock.lock();
try {
map.put(key, new WeakReference(entity));
} finally {
lock.unlock();
}
}
public void put2NoLock(long key, T entity) {
map.put(key, new WeakReference(entity));
}
@Override
public boolean detach(Long key, T entity) {
lock.lock();
try {
if (get(key) == entity && entity != null) {
remove(key);
return true;
} else {
return false;
}
} finally {
lock.unlock();
}
}
@Override
public void remove(Long key) {
lock.lock();
try {
map.remove(key);
} finally {
lock.unlock();
}
}
@Override
public void remove(Iterable keys) {
lock.lock();
try {
for (Long key : keys) {
map.remove(key);
}
} finally {
lock.unlock();
}
}
@Override
public void clear() {
lock.lock();
try {
map.clear();
} finally {
lock.unlock();
}
}
@Override
public void lock() {
lock.lock();
}
@Override
public void unlock() {
lock.unlock();
}
@Override
public void reserveRoom(int count) {
map.reserveRoom(count);
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/identityscope/IdentityScopeObject.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.identityscope;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
* The context for entity identities. Provides the scope in which entities will be tracked and managed.
*
* @author Markus
* @param
* @param
*/
public class IdentityScopeObject implements IdentityScope {
private final HashMap> map;
private final ReentrantLock lock;
public IdentityScopeObject() {
map = new HashMap>();
lock = new ReentrantLock();
}
@Override
public T get(K key) {
Reference ref;
lock.lock();
try {
ref = map.get(key);
} finally {
lock.unlock();
}
if (ref != null) {
return ref.get();
} else {
return null;
}
}
@Override
public T getNoLock(K key) {
Reference ref = map.get(key);
if (ref != null) {
return ref.get();
} else {
return null;
}
}
@Override
public void put(K key, T entity) {
lock.lock();
try {
map.put(key, new WeakReference(entity));
} finally {
lock.unlock();
}
}
@Override
public void putNoLock(K key, T entity) {
map.put(key, new WeakReference(entity));
}
@Override
public boolean detach(K key, T entity) {
lock.lock();
try {
if (get(key) == entity && entity != null) {
remove(key);
return true;
} else {
return false;
}
} finally {
lock.unlock();
}
}
@Override
public void remove(K key) {
lock.lock();
try {
map.remove(key);
} finally {
lock.unlock();
}
}
@Override
public void remove(Iterable< K> keys) {
lock.lock();
try {
for (K key : keys) {
map.remove(key);
}
} finally {
lock.unlock();
}
}
@Override
public void clear() {
lock.lock();
try {
map.clear();
} finally {
lock.unlock();
}
}
@Override
public void lock() {
lock.lock();
}
@Override
public void unlock() {
lock.unlock();
}
@Override
public void reserveRoom(int count) {
// HashMap does not allow
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/identityscope/IdentityScopeType.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.identityscope;
public enum IdentityScopeType {
Session, None
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/internal/DaoConfig.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.internal;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.DaoException;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.Property;
import org.greenrobot.greendao.identityscope.IdentityScope;
import org.greenrobot.greendao.identityscope.IdentityScopeLong;
import org.greenrobot.greendao.identityscope.IdentityScopeObject;
import org.greenrobot.greendao.identityscope.IdentityScopeType;
/**
* Internal class used by greenDAO. DaoConfig stores essential data for DAOs, and is hold by AbstractDaoMaster. This
* class will retrieve the required information from the DAO classes.
*/
public final class DaoConfig implements Cloneable {
public final Database db;
public final String tablename;
public final Property[] properties;
public final String[] allColumns;
public final String[] pkColumns;
public final String[] nonPkColumns;
/** Single property PK or null if there's no PK or a multi property PK. */
public final Property pkProperty;
public final boolean keyIsNumeric;
public final TableStatements statements;
private IdentityScope, ?> identityScope;
public DaoConfig(Database db, Class extends AbstractDao, ?>> daoClass) {
this.db = db;
try {
this.tablename = (String) daoClass.getField("TABLENAME").get(null);
Property[] properties = reflectProperties(daoClass);
this.properties = properties;
allColumns = new String[properties.length];
List pkColumnList = new ArrayList();
List nonPkColumnList = new ArrayList();
Property lastPkProperty = null;
for (int i = 0; i < properties.length; i++) {
Property property = properties[i];
String name = property.columnName;
allColumns[i] = name;
if (property.primaryKey) {
pkColumnList.add(name);
lastPkProperty = property;
} else {
nonPkColumnList.add(name);
}
}
String[] nonPkColumnsArray = new String[nonPkColumnList.size()];
nonPkColumns = nonPkColumnList.toArray(nonPkColumnsArray);
String[] pkColumnsArray = new String[pkColumnList.size()];
pkColumns = pkColumnList.toArray(pkColumnsArray);
pkProperty = pkColumns.length == 1 ? lastPkProperty : null;
statements = new TableStatements(db, tablename, allColumns, pkColumns);
if (pkProperty != null) {
Class> type = pkProperty.type;
keyIsNumeric = type.equals(long.class) || type.equals(Long.class) || type.equals(int.class)
|| type.equals(Integer.class) || type.equals(short.class) || type.equals(Short.class)
|| type.equals(byte.class) || type.equals(Byte.class);
} else {
keyIsNumeric = false;
}
} catch (Exception e) {
throw new DaoException("Could not init DAOConfig", e);
}
}
private static Property[] reflectProperties(Class extends AbstractDao, ?>> daoClass)
throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
Class> propertiesClass = Class.forName(daoClass.getName() + "$Properties");
Field[] fields = propertiesClass.getDeclaredFields();
ArrayList propertyList = new ArrayList();
final int modifierMask = Modifier.STATIC | Modifier.PUBLIC;
for (Field field : fields) {
// There might be other fields introduced by some tools, just ignore them (see issue #28)
if ((field.getModifiers() & modifierMask) == modifierMask) {
Object fieldValue = field.get(null);
if (fieldValue instanceof Property) {
propertyList.add((Property) fieldValue);
}
}
}
Property[] properties = new Property[propertyList.size()];
for (Property property : propertyList) {
if (properties[property.ordinal] != null) {
throw new DaoException("Duplicate property ordinals");
}
properties[property.ordinal] = property;
}
return properties;
}
/** Does not copy identity scope. */
public DaoConfig(DaoConfig source) {
db = source.db;
tablename = source.tablename;
properties = source.properties;
allColumns = source.allColumns;
pkColumns = source.pkColumns;
nonPkColumns = source.nonPkColumns;
pkProperty = source.pkProperty;
statements = source.statements;
keyIsNumeric = source.keyIsNumeric;
}
/** Does not copy identity scope. */
@Override
public DaoConfig clone() {
return new DaoConfig(this);
}
public IdentityScope, ?> getIdentityScope() {
return identityScope;
}
/**
* Clears the identify scope if it exists.
*/
public void clearIdentityScope() {
IdentityScope, ?> identityScope = this.identityScope;
if(identityScope != null) {
identityScope.clear();
}
}
public void setIdentityScope(IdentityScope, ?> identityScope) {
this.identityScope = identityScope;
}
@SuppressWarnings("rawtypes")
public void initIdentityScope(IdentityScopeType type) {
if (type == IdentityScopeType.None) {
identityScope = null;
} else if (type == IdentityScopeType.Session) {
if (keyIsNumeric) {
identityScope = new IdentityScopeLong();
} else {
identityScope = new IdentityScopeObject();
}
} else {
throw new IllegalArgumentException("Unsupported type: " + type);
}
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/internal/FastCursor.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.internal;
import android.content.ContentResolver;
import android.database.CharArrayBuffer;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
/** Internal class used by greenDAO. */
final public class FastCursor implements Cursor {
private final CursorWindow window;
private int position;
private final int count;
public FastCursor(CursorWindow window) {
this.window = window;
count = window.getNumRows();
}
@Override
public int getCount() {
return window.getNumRows();
}
@Override
public int getPosition() {
return position;
}
@Override
public boolean move(int offset) {
return moveToPosition(position + offset);
}
@Override
public boolean moveToPosition(int position) {
if (position >= 0 && position < count) {
this.position = position;
return true;
} else {
return false;
}
}
@Override
public boolean moveToFirst() {
position = 0;
return count > 0;
}
@Override
public boolean moveToLast() {
if (count > 0) {
position = count - 1;
return true;
} else {
return false;
}
}
@Override
public boolean moveToNext() {
if (position < count - 1) {
position++;
return true;
} else {
return false;
}
}
@Override
public boolean moveToPrevious() {
if (position > 0) {
position--;
return true;
} else {
return false;
}
}
@Override
public boolean isFirst() {
return position == 0;
}
@Override
public boolean isLast() {
return position == count - 1;
}
@Override
public boolean isBeforeFirst() {
throw new UnsupportedOperationException();
}
@Override
public boolean isAfterLast() {
throw new UnsupportedOperationException();
}
@Override
public int getColumnIndex(String columnName) {
throw new UnsupportedOperationException();
}
@Override
public int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException {
throw new UnsupportedOperationException();
}
@Override
public String getColumnName(int columnIndex) {
throw new UnsupportedOperationException();
}
@Override
public String[] getColumnNames() {
throw new UnsupportedOperationException();
}
@Override
public int getColumnCount() {
throw new UnsupportedOperationException();
}
@Override
public byte[] getBlob(int columnIndex) {
return window.getBlob(position, columnIndex);
}
@Override
public String getString(int columnIndex) {
return window.getString(position, columnIndex);
}
@Override
public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
throw new UnsupportedOperationException();
}
@Override
public short getShort(int columnIndex) {
return window.getShort(position, columnIndex);
}
@Override
public int getInt(int columnIndex) {
return window.getInt(position, columnIndex);
}
@Override
public long getLong(int columnIndex) {
return window.getLong(position, columnIndex);
}
@Override
public float getFloat(int columnIndex) {
return window.getFloat(position, columnIndex);
}
@Override
public double getDouble(int columnIndex) {
return window.getDouble(position, columnIndex);
}
@SuppressWarnings("deprecation")
@Override
public boolean isNull(int columnIndex) {
return window.isNull(position, columnIndex);
}
@Override
public void deactivate() {
throw new UnsupportedOperationException();
}
@Override
public boolean requery() {
throw new UnsupportedOperationException();
}
@Override
public void close() {
throw new UnsupportedOperationException();
}
@Override
public boolean isClosed() {
throw new UnsupportedOperationException();
}
@Override
public void registerContentObserver(ContentObserver observer) {
throw new UnsupportedOperationException();
}
@Override
public void unregisterContentObserver(ContentObserver observer) {
throw new UnsupportedOperationException();
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
throw new UnsupportedOperationException();
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
throw new UnsupportedOperationException();
}
@Override
public void setNotificationUri(ContentResolver cr, Uri uri) {
throw new UnsupportedOperationException();
}
@Override
public boolean getWantsAllOnMoveCalls() {
throw new UnsupportedOperationException();
}
@Override
public Bundle getExtras() {
throw new UnsupportedOperationException();
}
@Override
public Bundle respond(Bundle extras) {
throw new UnsupportedOperationException();
}
/** Since API level 11 */
public int getType(int columnIndex) {
throw new UnsupportedOperationException();
}
/** Since API level 19 */
public Uri getNotificationUri() {
return null;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/internal/LongHashMap.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.internal;
import java.util.Arrays;
import org.greenrobot.greendao.DaoLog;
/**
* An minimalistic hash map optimized for long keys.
*
* @author Markus
*
* @param
* The class to store.
*/
public final class LongHashMap {
final static class Entry {
final long key;
T value;
Entry next;
Entry(long key, T value, Entry next) {
this.key = key;
this.value = value;
this.next = next;
}
}
private Entry[] table;
private int capacity;
private int threshold;
private int size;
public LongHashMap() {
this(16);
}
@SuppressWarnings("unchecked")
public LongHashMap(int capacity) {
this.capacity = capacity;
this.threshold = capacity * 4 / 3;
this.table = new Entry[capacity];
}
public boolean containsKey(long key) {
final int index = ((((int) (key >>> 32)) ^ ((int) (key))) & 0x7fffffff) % capacity;
for (Entry entry = table[index]; entry != null; entry = entry.next) {
if (entry.key == key) {
return true;
}
}
return false;
}
public T get(long key) {
final int index = ((((int) (key >>> 32)) ^ ((int) (key))) & 0x7fffffff) % capacity;
for (Entry entry = table[index]; entry != null; entry = entry.next) {
if (entry.key == key) {
return entry.value;
}
}
return null;
}
public T put(long key, T value) {
final int index = ((((int) (key >>> 32)) ^ ((int) (key))) & 0x7fffffff) % capacity;
final Entry entryOriginal = table[index];
for (Entry entry = entryOriginal; entry != null; entry = entry.next) {
if (entry.key == key) {
T oldValue = entry.value;
entry.value = value;
return oldValue;
}
}
table[index] = new Entry(key, value, entryOriginal);
size++;
if (size > threshold) {
setCapacity(2 * capacity);
}
return null;
}
public T remove(long key) {
int index = ((((int) (key >>> 32)) ^ ((int) (key))) & 0x7fffffff) % capacity;
Entry previous = null;
Entry entry = table[index];
while (entry != null) {
Entry next = entry.next;
if (entry.key == key) {
if (previous == null) {
table[index] = next;
} else {
previous.next = next;
}
size--;
return entry.value;
}
previous = entry;
entry = next;
}
return null;
}
public void clear() {
size = 0;
Arrays.fill(table, null);
}
public int size() {
return size;
}
public void setCapacity(int newCapacity) {
@SuppressWarnings("unchecked")
Entry[] newTable = new Entry[newCapacity];
int length = table.length;
for (int i = 0; i < length; i++) {
Entry entry = table[i];
while (entry != null) {
long key = entry.key;
int index = ((((int) (key >>> 32)) ^ ((int) (key))) & 0x7fffffff) % newCapacity;
Entry originalNext = entry.next;
entry.next = newTable[index];
newTable[index] = entry;
entry = originalNext;
}
}
table = newTable;
capacity = newCapacity;
threshold = newCapacity * 4 / 3;
}
/** Target load: 0,6 */
public void reserveRoom(int entryCount) {
setCapacity(entryCount * 5 / 3);
}
public void logStats() {
int collisions = 0;
for (Entry entry : table) {
while (entry != null && entry.next != null) {
collisions++;
entry = entry.next;
}
}
DaoLog.d("load: " + ((float) size) / capacity + ", size: " + size + ", capa: " + capacity + ", collisions: "
+ collisions + ", collision ratio: " + ((float) collisions) / size);
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/internal/SqlUtils.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.internal;
import org.greenrobot.greendao.DaoException;
import org.greenrobot.greendao.Property;
/** Helper class to create SQL statements as used by greenDAO internally. */
public class SqlUtils {
private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static StringBuilder appendProperty(StringBuilder builder, String tablePrefix, Property property) {
if (tablePrefix != null) {
builder.append(tablePrefix).append('.');
}
builder.append('"').append(property.columnName).append('"');
return builder;
}
public static StringBuilder appendColumn(StringBuilder builder, String column) {
builder.append('"').append(column).append('"');
return builder;
}
public static StringBuilder appendColumn(StringBuilder builder, String tableAlias, String column) {
builder.append(tableAlias).append(".\"").append(column).append('"');
return builder;
}
public static StringBuilder appendColumns(StringBuilder builder, String tableAlias, String[] columns) {
int length = columns.length;
for (int i = 0; i < length; i++) {
appendColumn(builder, tableAlias, columns[i]);
if (i < length - 1) {
builder.append(',');
}
}
return builder;
}
public static StringBuilder appendColumns(StringBuilder builder, String[] columns) {
int length = columns.length;
for (int i = 0; i < length; i++) {
builder.append('"').append(columns[i]).append('"');
if (i < length - 1) {
builder.append(',');
}
}
return builder;
}
public static StringBuilder appendPlaceholders(StringBuilder builder, int count) {
for (int i = 0; i < count; i++) {
if (i < count - 1) {
builder.append("?,");
} else {
builder.append('?');
}
}
return builder;
}
public static StringBuilder appendColumnsEqualPlaceholders(StringBuilder builder, String[] columns) {
for (int i = 0; i < columns.length; i++) {
appendColumn(builder, columns[i]).append("=?");
if (i < columns.length - 1) {
builder.append(',');
}
}
return builder;
}
public static StringBuilder appendColumnsEqValue(StringBuilder builder, String tableAlias, String[] columns) {
for (int i = 0; i < columns.length; i++) {
appendColumn(builder, tableAlias, columns[i]).append("=?");
if (i < columns.length - 1) {
builder.append(',');
}
}
return builder;
}
public static String createSqlInsert(String insertInto, String tablename, String[] columns) {
StringBuilder builder = new StringBuilder(insertInto);
builder.append('"').append(tablename).append('"').append(" (");
appendColumns(builder, columns);
builder.append(") VALUES (");
appendPlaceholders(builder, columns.length);
builder.append(')');
return builder.toString();
}
/** Creates an select for given columns with a trailing space */
public static String createSqlSelect(String tablename, String tableAlias, String[] columns, boolean distinct) {
if (tableAlias == null || tableAlias.length() < 0) {
throw new DaoException("Table alias required");
}
StringBuilder builder = new StringBuilder(distinct ? "SELECT DISTINCT " : "SELECT ");
SqlUtils.appendColumns(builder, tableAlias, columns).append(" FROM ");
builder.append('"').append(tablename).append('"').append(' ').append(tableAlias).append(' ');
return builder.toString();
}
/** Creates SELECT COUNT(*) with a trailing space. */
public static String createSqlSelectCountStar(String tablename, String tableAliasOrNull) {
StringBuilder builder = new StringBuilder("SELECT COUNT(*) FROM ");
builder.append('"').append(tablename).append('"').append(' ');
if (tableAliasOrNull != null) {
builder.append(tableAliasOrNull).append(' ');
}
return builder.toString();
}
/** Remember: SQLite does not support joins nor table alias for DELETE. */
public static String createSqlDelete(String tablename, String[] columns) {
String quotedTablename = '"' + tablename + '"';
StringBuilder builder = new StringBuilder("DELETE FROM ");
builder.append(quotedTablename);
if (columns != null && columns.length > 0) {
builder.append(" WHERE ");
appendColumnsEqValue(builder, quotedTablename, columns);
}
return builder.toString();
}
public static String createSqlUpdate(String tablename, String[] updateColumns, String[] whereColumns) {
String quotedTablename = '"' + tablename + '"';
StringBuilder builder = new StringBuilder("UPDATE ");
builder.append(quotedTablename).append(" SET ");
appendColumnsEqualPlaceholders(builder, updateColumns);
builder.append(" WHERE ");
appendColumnsEqValue(builder, quotedTablename, whereColumns);
return builder.toString();
}
public static String createSqlCount(String tablename) {
return "SELECT COUNT(*) FROM \"" + tablename +'"';
}
public static String escapeBlobArgument(byte[] bytes) {
return "X'" + toHex(bytes) + '\'';
}
public static String toHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int i = 0; i < bytes.length; i++) {
int byteValue = bytes[i] & 0xFF;
hexChars[i * 2] = HEX_ARRAY[byteValue >>> 4];
hexChars[i * 2 + 1] = HEX_ARRAY[byteValue & 0x0F];
}
return new String(hexChars);
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/internal/TableStatements.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.internal;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.database.DatabaseStatement;
/** Helper class to create SQL statements for specific tables (used by greenDAO internally). */
// Note: avoid locking while compiling any statement (accessing the db) to avoid deadlocks on lock-savvy DBs like
// SQLCipher.
public class TableStatements {
private final Database db;
private final String tablename;
private final String[] allColumns;
private final String[] pkColumns;
private DatabaseStatement insertStatement;
private DatabaseStatement insertOrReplaceStatement;
private DatabaseStatement updateStatement;
private DatabaseStatement deleteStatement;
private DatabaseStatement countStatement;
private volatile String selectAll;
private volatile String selectByKey;
private volatile String selectByRowId;
private volatile String selectKeys;
public TableStatements(Database db, String tablename, String[] allColumns, String[] pkColumns) {
this.db = db;
this.tablename = tablename;
this.allColumns = allColumns;
this.pkColumns = pkColumns;
}
public DatabaseStatement getInsertStatement() {
if (insertStatement == null) {
String sql = SqlUtils.createSqlInsert("INSERT INTO ", tablename, allColumns);
DatabaseStatement newInsertStatement = db.compileStatement(sql);
synchronized (this) {
if (insertStatement == null) {
insertStatement = newInsertStatement;
}
}
if (insertStatement != newInsertStatement) {
newInsertStatement.close();
}
}
return insertStatement;
}
public DatabaseStatement getInsertOrReplaceStatement() {
if (insertOrReplaceStatement == null) {
String sql = SqlUtils.createSqlInsert("INSERT OR REPLACE INTO ", tablename, allColumns);
DatabaseStatement newInsertOrReplaceStatement = db.compileStatement(sql);
synchronized (this) {
if (insertOrReplaceStatement == null) {
insertOrReplaceStatement = newInsertOrReplaceStatement;
}
}
if (insertOrReplaceStatement != newInsertOrReplaceStatement) {
newInsertOrReplaceStatement.close();
}
}
return insertOrReplaceStatement;
}
public DatabaseStatement getDeleteStatement() {
if (deleteStatement == null) {
String sql = SqlUtils.createSqlDelete(tablename, pkColumns);
DatabaseStatement newDeleteStatement = db.compileStatement(sql);
synchronized (this) {
if (deleteStatement == null) {
deleteStatement = newDeleteStatement;
}
}
if (deleteStatement != newDeleteStatement) {
newDeleteStatement.close();
}
}
return deleteStatement;
}
public DatabaseStatement getUpdateStatement() {
if (updateStatement == null) {
String sql = SqlUtils.createSqlUpdate(tablename, allColumns, pkColumns);
DatabaseStatement newUpdateStatement = db.compileStatement(sql);
synchronized (this) {
if (updateStatement == null) {
updateStatement = newUpdateStatement;
}
}
if (updateStatement != newUpdateStatement) {
newUpdateStatement.close();
}
}
return updateStatement;
}
public DatabaseStatement getCountStatement() {
if (countStatement == null) {
String sql = SqlUtils.createSqlCount(tablename);
countStatement = db.compileStatement(sql);
}
return countStatement;
}
/** ends with an space to simplify appending to this string. */
public String getSelectAll() {
if (selectAll == null) {
selectAll = SqlUtils.createSqlSelect(tablename, "T", allColumns, false);
}
return selectAll;
}
/** ends with an space to simplify appending to this string. */
public String getSelectKeys() {
if (selectKeys == null) {
selectKeys = SqlUtils.createSqlSelect(tablename, "T", pkColumns, false);
}
return selectKeys;
}
// TODO precompile
public String getSelectByKey() {
if (selectByKey == null) {
StringBuilder builder = new StringBuilder(getSelectAll());
builder.append("WHERE ");
SqlUtils.appendColumnsEqValue(builder, "T", pkColumns);
selectByKey = builder.toString();
}
return selectByKey;
}
public String getSelectByRowId() {
if (selectByRowId == null) {
selectByRowId = getSelectAll() + "WHERE ROWID=?";
}
return selectByRowId;
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/query/AbstractQuery.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.query;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.DaoException;
import org.greenrobot.greendao.InternalQueryDaoAccess;
import java.util.Date;
/**
* A repeatable query returning entities.
*
* @author Markus
*
* @param
* The entity class the query will return results for.
*/
// TODO support long, double and other types, not just Strings, for parameters
// TODO Make parameters setable by Property (if unique in parameters)
// TODO Make query compilable
abstract class AbstractQuery {
protected final AbstractDao dao;
protected final InternalQueryDaoAccess daoAccess;
protected final String sql;
protected final String[] parameters;
protected final Thread ownerThread;
protected static String[] toStringArray(Object[] values) {
int length = values.length;
String[] strings = new String[length];
for (int i = 0; i < length; i++) {
Object object = values[i];
if (object != null) {
strings[i] = object.toString();
} else {
strings[i] = null;
}
}
return strings;
}
protected AbstractQuery(AbstractDao dao, String sql, String[] parameters) {
this.dao = dao;
this.daoAccess = new InternalQueryDaoAccess(dao);
this.sql = sql;
this.parameters = parameters;
ownerThread = Thread.currentThread();
}
// public void compile() {
// // TODO implement compile
// }
/**
* Sets the parameter (0 based) using the position in which it was added during building the query.
*/
public AbstractQuery setParameter(int index, Object parameter) {
checkThread();
if (parameter != null) {
parameters[index] = parameter.toString();
} else {
parameters[index] = null;
}
return this;
}
/**
* @see #setParameter(int, Object)
*/
public AbstractQuery setParameter(int index, Date parameter) {
Long converted = parameter != null ? parameter.getTime() : null;
return setParameter(index, converted);
}
/**
* @see #setParameter(int, Object)
*/
public AbstractQuery setParameter(int index, Boolean parameter) {
Integer converted = parameter != null ? (parameter ? 1 : 0) : null;
return setParameter(index, converted);
}
protected void checkThread() {
if (Thread.currentThread() != ownerThread) {
throw new DaoException(
"Method may be called only in owner thread, use forCurrentThread to get an instance for this thread");
}
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/query/AbstractQueryData.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.query;
import org.greenrobot.greendao.AbstractDao;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
abstract class AbstractQueryData> {
final String sql;
final AbstractDao dao;
final String[] initialValues;
final Map> queriesForThreads;
AbstractQueryData(AbstractDao dao, String sql, String[] initialValues) {
this.dao = dao;
this.sql = sql;
this.initialValues = initialValues;
queriesForThreads = new HashMap<>();
}
/**
* Just an optimized version, which performs faster if the current thread is already the query's owner thread.
* Note: all parameters are reset to their initial values specified in {@link QueryBuilder}.
*/
Q forCurrentThread(Q query) {
if (Thread.currentThread() == query.ownerThread) {
System.arraycopy(initialValues, 0, query.parameters, 0, initialValues.length);
return query;
} else {
return forCurrentThread();
}
}
/**
* Note: all parameters are reset to their initial values specified in {@link QueryBuilder}.
*/
Q forCurrentThread() {
// Process.myTid() seems to have issues on some devices (see Github #376) and Robolectric (#171):
// We use currentThread().getId() instead (unfortunately return a long, can not use SparseArray).
// PS.: thread ID may be reused, which should be fine because old thread will be gone anyway.
long threadId = Thread.currentThread().getId();
synchronized (queriesForThreads) {
WeakReference queryRef = queriesForThreads.get(threadId);
Q query = queryRef != null ? queryRef.get() : null;
if (query == null) {
gc();
query = createQuery();
queriesForThreads.put(threadId, new WeakReference(query));
} else {
System.arraycopy(initialValues, 0, query.parameters, 0, initialValues.length);
}
return query;
}
}
abstract protected Q createQuery();
void gc() {
synchronized (queriesForThreads) {
Iterator>> iterator = queriesForThreads.entrySet().iterator();
while (iterator.hasNext()) {
Entry> entry = iterator.next();
if (entry.getValue().get() == null) {
iterator.remove();
}
}
}
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/query/AbstractQueryWithLimit.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.query;
import org.greenrobot.greendao.AbstractDao;
/**
* Base class for queries returning data (entities or cursor).
*
* @param The entity class the query will return results for.
* @author Markus
*/
// TODO Query for PKs/ROW IDs
abstract class AbstractQueryWithLimit extends AbstractQuery {
protected final int limitPosition;
protected final int offsetPosition;
protected AbstractQueryWithLimit(AbstractDao dao, String sql, String[] initialValues, int limitPosition,
int offsetPosition) {
super(dao, sql, initialValues);
this.limitPosition = limitPosition;
this.offsetPosition = offsetPosition;
}
/**
* Sets the parameter (0 based) using the position in which it was added during building the query. Note: all
* standard WHERE parameters come first. After that come the WHERE parameters of joins (if any).
*/
public AbstractQueryWithLimit setParameter(int index, Object parameter) {
if (index >= 0 && (index == limitPosition || index == offsetPosition)) {
throw new IllegalArgumentException("Illegal parameter index: " + index);
}
return (AbstractQueryWithLimit) super.setParameter(index, parameter);
}
/**
* Sets the limit of the maximum number of results returned by this Query. {@link
* org.greenrobot.greendao.query.QueryBuilder#limit(int)} must
* have been called on the QueryBuilder that created this Query object.
*/
public void setLimit(int limit) {
checkThread();
if (limitPosition == -1) {
throw new IllegalStateException("Limit must be set with QueryBuilder before it can be used here");
}
parameters[limitPosition] = Integer.toString(limit);
}
/**
* Sets the offset for results returned by this Query. {@link org.greenrobot.greendao.query.QueryBuilder#offset(int)} must
* have been called on
* the QueryBuilder that created this Query object.
*/
public void setOffset(int offset) {
checkThread();
if (offsetPosition == -1) {
throw new IllegalStateException("Offset must be set with QueryBuilder before it can be used here");
}
parameters[offsetPosition] = Integer.toString(offset);
}
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/query/CloseableListIterator.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.query;
import java.io.Closeable;
import java.util.ListIterator;
/**
* A list iterator that needs to be closed (or the associated list) to free underlying resources like a database cursor.
* Typically used with LazyList.
*
* @author Markus
*
* @param
*/
public interface CloseableListIterator extends ListIterator, Closeable {
}
================================================
FILE: DaoCore/src/main/java/org/greenrobot/greendao/query/CountQuery.java
================================================
/*
* Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* 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 org.greenrobot.greendao.query;
import android.database.Cursor;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.DaoException;
import java.util.Date;
public class CountQuery extends AbstractQuery {
private final static class QueryData extends AbstractQueryData> {
private QueryData(AbstractDao dao, String sql, String[] initialValues) {
super(dao, sql, initialValues);
}
@Override
protected CountQuery createQuery() {
return new CountQuery(this, dao, sql, initialValues.clone());
}
}
static CountQuery create(AbstractDao dao, String sql, Object[] initialValues) {
QueryData queryData = new QueryData(dao, sql, toStringArray(initialValues));
return queryData.forCurrentThread();
}
private final QueryData queryData;
private CountQuery(QueryData queryData, AbstractDao dao, String sql, String[] initialValues) {
super(dao, sql, initialValues);
this.queryData = queryData;
}
public CountQuery forCurrentThread() {
return queryData.forCurrentThread(this);
}
/** Returns the count (number of results matching the query). Uses SELECT COUNT (*) sematics. */
public long count() {
checkThread();
Cursor cursor = dao.getDatabase().rawQuery(sql, parameters);
try {
if (!cursor.moveToNext()) {
throw new DaoException("No result for count");
} else if (!cursor.isLast()) {
throw new DaoException("Unexpected row count: " + cursor.getCount());
} else if (cursor.getColumnCount() != 1) {
throw new DaoException("Unexpected column count: " + cursor.getColumnCount());
}
return cursor.getLong(0);
} finally {
cursor.close();
}
}
// copy setParameter methods to allow easy chaining
@Override
public CountQuery