├── .gitattributes
├── .gitignore
├── .travis.decrypt.sh
├── .travis.yml
├── LICENSE
├── Makefile
├── README.md
├── build.gradle
├── gradle.properties.enc
├── gradle
├── secring.gpg
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── rethinkdb-orm-annotations
├── build.gradle
└── src
│ └── main
│ └── java
│ └── de
│ └── jakobjarosch
│ └── rethinkdb
│ └── orm
│ └── annotation
│ ├── Index.java
│ ├── PrimaryKey.java
│ └── RethinkDBModel.java
├── rethinkdb-orm-samples
├── build.gradle
└── src
│ └── main
│ └── java
│ ├── EntryPoint.java
│ ├── SubModel.java
│ └── TestModel.java
├── rethinkdb-orm
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── de
│ │ └── jakobjarosch
│ │ └── rethinkdb
│ │ └── orm
│ │ ├── RethinkDBDAOProcessor.java
│ │ ├── dao
│ │ ├── DAOIterator.java
│ │ ├── GenericDAO.java
│ │ └── ModelMapper.java
│ │ └── model
│ │ ├── ChangeFeedElement.java
│ │ ├── IndexModel.java
│ │ ├── PrimaryKeyModel.java
│ │ └── geo
│ │ ├── GeoFactory.java
│ │ ├── ReqlGeo.java
│ │ ├── ReqlLine.java
│ │ ├── ReqlPoint.java
│ │ └── ReqlPolygon.java
│ └── test
│ └── java
│ └── de
│ └── jakobjarosch
│ └── rethinkdb
│ └── orm
│ └── dao
│ ├── GenericDAOTest.java
│ └── ModelMapperTest.java
├── rethinkdb-pool
├── build.gradle
└── src
│ └── main
│ └── java
│ └── de
│ └── jakobjarosch
│ └── rethinkdb
│ └── pool
│ ├── ConnectionFactory.java
│ ├── ConnectionPoolMetrics.java
│ ├── ConnectionStats.java
│ ├── PersistentConnection.java
│ ├── RethinkDBPool.java
│ └── RethinkDBPoolBuilder.java
└── settings.gradle
/.gitattributes:
--------------------------------------------------------------------------------
1 | # By default we handle everything with LF line endings
2 | * text eol=lf
3 |
4 | # Some filetypes should be handled as binary
5 | *.png binary
6 |
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # IntelliJ
2 | .idea/
3 | *.iml
4 |
5 | # Gradle
6 | build/
7 | .gradle/
8 | gradle.properties
9 |
10 | # Defaults
11 | tmp/
12 |
--------------------------------------------------------------------------------
/.travis.decrypt.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | [[ -n "$TRAVIS_TAG" ]] && openssl aes-256-cbc -K $encrypted_65aa329e7553_key -iv $encrypted_65aa329e7553_iv -in gradle.properties.enc -out gradle.properties -d || true
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 |
3 | services:
4 | - docker
5 |
6 | language: java
7 | jdk: oraclejdk8
8 |
9 | install: true
10 |
11 | before_script:
12 | - sudo docker run -d -p 28015:28015 rethinkdb:2.3.4
13 | - ./.travis.decrypt.sh
14 |
15 | script:
16 | - make build
17 |
18 | deploy:
19 | provider: script
20 | script:
21 | - make travis-deploy
22 | on:
23 | tags: true
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SHELL:=/bin/bash
2 |
3 | build:
4 | ./gradlew build
5 |
6 | travis-deploy:
7 | ./gradlew upload closeRepository
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RethinkDB ORM for Java
2 |
3 | [](https://travis-ci.org/foxylion/rethinkdb-orm-java)
4 | [](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.jakobjarosch.rethinkdb%22)
5 | 
6 | 
7 |
8 | This is a lightweight OR mapper for [RethinkDB](https://www.rethinkdb.com/) and Java.
9 | It automatically maps your POJOs to a RethinkDB compatible data structure and vice versa.
10 |
11 | ## What do I get?
12 |
13 | - Lightweight OR mapper using annotation processors
14 | - Support to map fields to other database field names
15 | - Support to ignore fields from model or database
16 | - Possibility to automatically create tables and inidices
17 | - Connection pooling support across threads (also standalone available)
18 |
19 | ## How to use?
20 |
21 | The integration is using annotation processors to generate the DAO classes.
22 | Ensure that your IDE has [enabled annotation processing](https://immutables.github.io/apt.html).
23 |
24 | To get started you've to annotate your POJO.
25 |
26 | ```java
27 | @RethinkDBModel
28 | public class MyModel {
29 | @PrimaryKey private String id;
30 | private ReqlPoint location;
31 | }
32 | ```
33 |
34 | The annotation processor will automatically generate a `MyModelDAO` class which
35 | can be used to create, read, update, delete your model (CRUD). It is also possible
36 | to stream the change sets.
37 |
38 | The DAO can be used very easily.
39 |
40 | ```java
41 | try (Connection connection = RethinkDB.r.connection().connect()) {
42 | MyModelDAO dao = new MyModelDAO(connection);
43 | MyModel model = dao.read("2a22fda0");
44 | model.location = new ReqlPoint(12.234, 23.764);
45 | dao.update("2a22fda0", model);
46 | }
47 | ```
48 |
49 | **More examples can be found [here](rethinkdb-orm-samples/src/main/java/EntryPoint.java).**
50 |
51 | ### Configure as a dependency
52 |
53 | The current version can be found [here](https://github.com/foxylion/rethinkdb-orm-java/releases).
54 |
55 | #### Maven
56 | ```xml
57 |
58 | de.jakobjarosch.rethinkdb
59 | rethinkdb-orm
60 | {{ current-version }}
61 |
62 | ```
63 |
64 | #### Gradle
65 | ```
66 | compile 'de.jakobjarosch.rethinkdb:rethinkdb-orm:{{ current-version }}'
67 | ```
68 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | mavenCentral()
4 | }
5 | dependencies {
6 | classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.5.3"
7 | }
8 | }
9 |
10 | apply plugin: 'idea'
11 | apply plugin: 'io.codearte.nexus-staging'
12 |
13 | idea {
14 | module {
15 | // Add automatically generated classes (by apt) to classpath
16 | sourceDirs += file(project.projectDir.absolutePath + '/build/generated/source/apt/main')
17 | downloadJavadoc = true
18 | downloadSources = true
19 | }
20 | }
21 |
22 | def artifactRelease = (boolean) System.getenv('TRAVIS_TAG');
23 |
24 | configure([project(':rethinkdb-orm'), project(':rethinkdb-orm-annotations'), project(':rethinkdb-pool')]) {
25 | apply plugin: 'java'
26 | apply plugin: 'signing'
27 | apply plugin: 'maven'
28 |
29 | task javadocJar(type: Jar, dependsOn: javadoc) {
30 | classifier = 'javadoc'
31 | from 'build/docs/javadoc'
32 | }
33 |
34 | task sourcesJar(type: Jar) {
35 | from sourceSets.main.allSource
36 | classifier = 'sources'
37 | }
38 |
39 | artifacts {
40 | archives jar
41 | archives javadocJar
42 | archives sourcesJar
43 | }
44 |
45 | if (artifactRelease) {
46 | signing {
47 | sign configurations.archives
48 | }
49 | }
50 |
51 | group = 'de.jakobjarosch.rethinkdb'
52 | version = System.getenv('TRAVIS_TAG') ?: 'master-SNAPSHOT'
53 |
54 | uploadArchives {
55 | repositories {
56 | if (artifactRelease) {
57 | mavenDeployer {
58 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
59 |
60 | repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2') {
61 | authentication(userName: ossrhUser, password: ossrhPass)
62 | }
63 | pom.project {
64 | name 'RethinkDB ORM for Java'
65 | description 'A lightweight OR mapper for RethinkDB, written in Java.'
66 | url 'https://github.com/foxylion/rethinkdb-orm-java'
67 | scm {
68 | url 'https://github.com/foxylion/rethinkdb-orm-java'
69 | connection 'scm:git@github.com:foxylion/rethinkdb-orm-java.git'
70 | developerConnection 'scm:git@github.com:foxylion/rethinkdb-orm-java.git'
71 | }
72 | licenses {
73 | license {
74 | name 'The Apache License, Version 2.0'
75 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
76 | }
77 | }
78 | developers {
79 | developer {
80 | name 'Jakob Jarosch'
81 | email 'dev@jakobjarosch.de'
82 | organizationUrl 'https://www.jakobjarosch.de'
83 | }
84 | }
85 | }
86 | }
87 | } else {
88 | mavenInstaller {
89 | }
90 | }
91 | }
92 | }
93 | }
94 |
95 | if (artifactRelease) {
96 | nexusStaging {
97 | username = ossrhUser
98 | password = ossrhPass
99 | packageGroup = 'de.jakobjarosch'
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/gradle.properties.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/foxylion/rethinkdb-orm-java/c15fd5b89db365712f81acc5009b2584aac6bf08/gradle.properties.enc
--------------------------------------------------------------------------------
/gradle/secring.gpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/foxylion/rethinkdb-orm-java/c15fd5b89db365712f81acc5009b2584aac6bf08/gradle/secring.gpg
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/foxylion/rethinkdb-orm-java/c15fd5b89db365712f81acc5009b2584aac6bf08/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jun 15 20:52:15 CEST 2016
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn ( ) {
37 | echo "$*"
38 | }
39 |
40 | die ( ) {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/rethinkdb-orm-annotations/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'idea'
4 | }
5 |
6 | sourceCompatibility = 1.8
7 | targetCompatibility = 1.8
8 |
--------------------------------------------------------------------------------
/rethinkdb-orm-annotations/src/main/java/de/jakobjarosch/rethinkdb/orm/annotation/Index.java:
--------------------------------------------------------------------------------
1 | package de.jakobjarosch.rethinkdb.orm.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Target(value = {ElementType.ANNOTATION_TYPE})
9 | @Retention(RetentionPolicy.CLASS)
10 | public @interface Index {
11 |
12 | String[] fields();
13 |
14 | boolean geo() default false;
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/rethinkdb-orm-annotations/src/main/java/de/jakobjarosch/rethinkdb/orm/annotation/PrimaryKey.java:
--------------------------------------------------------------------------------
1 | package de.jakobjarosch.rethinkdb.orm.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | @Target(ElementType.FIELD)
9 | @Retention(RetentionPolicy.CLASS)
10 | public @interface PrimaryKey {
11 | }
12 |
--------------------------------------------------------------------------------
/rethinkdb-orm-annotations/src/main/java/de/jakobjarosch/rethinkdb/orm/annotation/RethinkDBModel.java:
--------------------------------------------------------------------------------
1 | package de.jakobjarosch.rethinkdb.orm.annotation;
2 |
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | @Target(ElementType.TYPE)
10 | @Retention(RetentionPolicy.CLASS)
11 | public @interface RethinkDBModel {
12 |
13 | String tableName() default "";
14 |
15 | Index[] indices() default {};
16 | }
17 |
--------------------------------------------------------------------------------
/rethinkdb-orm-samples/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'idea'
4 | id 'net.ltgt.apt' version '0.6'
5 | }
6 |
7 | sourceCompatibility = 1.8
8 | targetCompatibility = 1.8
9 |
10 | repositories {
11 | mavenCentral()
12 | }
13 |
14 | dependencies {
15 | compile 'org.slf4j:slf4j-simple:1.7.21'
16 |
17 | compile project(':rethinkdb-orm')
18 | apt project(':rethinkdb-orm')
19 | }
20 |
--------------------------------------------------------------------------------
/rethinkdb-orm-samples/src/main/java/EntryPoint.java:
--------------------------------------------------------------------------------
1 | import de.jakobjarosch.rethinkdb.orm.model.geo.ReqlPoint;
2 | import de.jakobjarosch.rethinkdb.pool.RethinkDBPool;
3 | import de.jakobjarosch.rethinkdb.pool.RethinkDBPoolBuilder;
4 | import rx.Subscription;
5 | import rx.schedulers.Schedulers;
6 |
7 | import java.time.ZonedDateTime;
8 | import java.util.Optional;
9 |
10 | public class EntryPoint {
11 |
12 | public static void main(String[] args) throws InterruptedException {
13 | final RethinkDBPool pool = new RethinkDBPoolBuilder().build();
14 | try {
15 | TestModelDAO dao = new TestModelDAO(pool);
16 |
17 | // Initialize the table (creates the table, and indices)
18 | dao.initTable();
19 |
20 | TestModel model = new TestModel("1");
21 | model.setSubModel(new SubModel());
22 | model.getSubModel().setLastUpdate(ZonedDateTime.now());
23 |
24 | // Create the model in the database
25 | dao.create(model);
26 |
27 | model.setLocation(new ReqlPoint(127.0, 10.0));
28 |
29 | // Update the model in the database
30 | dao.update("1", model);
31 |
32 | // Read the model from the database
33 | Optional dbModel = dao.read("1");
34 |
35 | // Delete the model from the database
36 | dbModel.ifPresent(m -> {
37 | dao.delete("1");
38 | });
39 |
40 | // Subscriptions are handled by RxJava
41 | // This sample subscribes to the change feed in an async mode
42 | Subscription subscription = dao.changes()
43 | .subscribeOn(Schedulers.newThread())
44 | .subscribe(change -> {
45 | System.out.println(Thread.currentThread().toString() + ": " + change);
46 | });
47 |
48 | // Listen for 10 seconds on changes.
49 | Thread.sleep(10000);
50 |
51 | // Stop getting updates.
52 | subscription.unsubscribe();
53 |
54 | Thread.sleep(1000);
55 | } finally {
56 | pool.shutdown();
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/rethinkdb-orm-samples/src/main/java/SubModel.java:
--------------------------------------------------------------------------------
1 | import java.time.LocalDateTime;
2 | import java.time.ZonedDateTime;
3 |
4 | public class SubModel {
5 |
6 | private ZonedDateTime lastUpdate;
7 |
8 | public ZonedDateTime getLastUpdate() {
9 | return lastUpdate;
10 | }
11 |
12 | public void setLastUpdate(ZonedDateTime lastUpdate) {
13 | this.lastUpdate = lastUpdate;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/rethinkdb-orm-samples/src/main/java/TestModel.java:
--------------------------------------------------------------------------------
1 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
2 | import de.jakobjarosch.rethinkdb.orm.annotation.Index;
3 | import de.jakobjarosch.rethinkdb.orm.annotation.PrimaryKey;
4 | import de.jakobjarosch.rethinkdb.orm.annotation.RethinkDBModel;
5 | import de.jakobjarosch.rethinkdb.orm.model.geo.ReqlPoint;
6 |
7 | @RethinkDBModel(
8 | tableName = "my_table",
9 | indices = {
10 | @Index(fields = {"location"}, geo = true),
11 | @Index(fields = {"field1", "field2"})
12 | }
13 | )
14 | public class TestModel {
15 |
16 | @PrimaryKey
17 | private String id;
18 | private ReqlPoint location;
19 | private SubModel subModel;
20 |
21 | TestModel() {
22 | }
23 |
24 | public TestModel(String id) {
25 | this.id = id;
26 | }
27 |
28 | public String getId() {
29 | return id;
30 | }
31 |
32 | public ReqlPoint getLocation() {
33 | return location;
34 | }
35 |
36 | public void setLocation(ReqlPoint location) {
37 | this.location = location;
38 | }
39 |
40 | public SubModel getSubModel() {
41 | return subModel;
42 | }
43 |
44 | public void setSubModel(SubModel subModel) {
45 | this.subModel = subModel;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/rethinkdb-orm/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'idea'
4 | id 'net.ltgt.apt' version '0.6'
5 | }
6 |
7 | sourceCompatibility = 1.8
8 | targetCompatibility = 1.8
9 |
10 | repositories {
11 | mavenCentral()
12 | }
13 |
14 | dependencies {
15 | compile 'com.fasterxml.jackson.core:jackson-databind:2.7.5'
16 | compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.7.5'
17 |
18 | compile 'io.reactivex:rxjava:1.0.10'
19 | compile project(':rethinkdb-pool')
20 | compile project(':rethinkdb-orm-annotations')
21 |
22 | testCompile 'org.mockito:mockito-all:2.0.2-beta'
23 | testCompile 'org.assertj:assertj-core:3.4.1'
24 | testCompile 'org.slf4j:slf4j-simple:1.7.21'
25 |
26 | // Annotation processor specific dependencies
27 | compile 'com.squareup:javapoet:1.7.0'
28 | compile 'com.google.auto.service:auto-service:1.0-rc2'
29 | apt 'com.google.auto.service:auto-service:1.0-rc2'
30 | }
31 |
--------------------------------------------------------------------------------
/rethinkdb-orm/src/main/java/de/jakobjarosch/rethinkdb/orm/RethinkDBDAOProcessor.java:
--------------------------------------------------------------------------------
1 | package de.jakobjarosch.rethinkdb.orm;
2 |
3 | import com.google.auto.service.AutoService;
4 | import com.google.common.base.Joiner;
5 | import com.google.common.collect.Sets;
6 | import com.rethinkdb.net.Connection;
7 | import com.squareup.javapoet.*;
8 | import de.jakobjarosch.rethinkdb.orm.annotation.PrimaryKey;
9 | import de.jakobjarosch.rethinkdb.orm.annotation.RethinkDBModel;
10 | import de.jakobjarosch.rethinkdb.orm.dao.GenericDAO;
11 | import de.jakobjarosch.rethinkdb.orm.model.IndexModel;
12 | import de.jakobjarosch.rethinkdb.orm.model.PrimaryKeyModel;
13 | import de.jakobjarosch.rethinkdb.pool.PersistentConnection;
14 | import de.jakobjarosch.rethinkdb.pool.RethinkDBPool;
15 |
16 | import javax.annotation.processing.AbstractProcessor;
17 | import javax.annotation.processing.ProcessingEnvironment;
18 | import javax.annotation.processing.Processor;
19 | import javax.annotation.processing.RoundEnvironment;
20 | import javax.inject.Provider;
21 | import javax.lang.model.SourceVersion;
22 | import javax.lang.model.element.*;
23 | import javax.lang.model.type.TypeMirror;
24 | import javax.lang.model.util.ElementFilter;
25 | import javax.tools.Diagnostic.Kind;
26 | import javax.tools.JavaFileObject;
27 | import java.io.Writer;
28 | import java.util.Arrays;
29 | import java.util.List;
30 | import java.util.Set;
31 | import java.util.stream.Collectors;
32 |
33 | @AutoService(Processor.class)
34 | public class RethinkDBDAOProcessor extends AbstractProcessor {
35 |
36 | @Override
37 | public synchronized void init(ProcessingEnvironment processingEnvironment) {
38 | super.init(processingEnvironment);
39 | }
40 |
41 | @Override
42 | public Set getSupportedAnnotationTypes() {
43 | return Sets.newHashSet(
44 | RethinkDBModel.class.getCanonicalName()
45 | );
46 | }
47 |
48 | @Override
49 | public SourceVersion getSupportedSourceVersion() {
50 | return SourceVersion.RELEASE_8;
51 | }
52 |
53 | @Override
54 | public boolean process(final Set extends TypeElement> annotations,
55 | final RoundEnvironment roundEnv) {
56 | try {
57 | process(roundEnv);
58 | } catch (Exception e) {
59 | processingEnv.getMessager().printMessage(Kind.ERROR, "Something went wrong: " + e);
60 | }
61 | return true;
62 | }
63 |
64 | private void process(RoundEnvironment roundEnv) throws Exception {
65 | for (final Element element : roundEnv.getElementsAnnotatedWith(RethinkDBModel.class)) {
66 | if (element instanceof TypeElement) {
67 | final TypeElement typeElement = (TypeElement) element;
68 |
69 | final RethinkDBModel modelAnnotation = typeElement.getAnnotation(RethinkDBModel.class);
70 |
71 | final PackageElement packageElement = (PackageElement) typeElement.getEnclosingElement();
72 |
73 | final String packageName = packageElement.getQualifiedName().toString();
74 | final String daoClassName = typeElement.getSimpleName() + "DAO";
75 | final String daoQualifiedName = packageName.isEmpty() ? daoClassName : packageName + "." + daoClassName;
76 |
77 | final PrimaryKeyModel primaryKey = scanPrimaryKey(typeElement);
78 | final Set indices = scanIndices(modelAnnotation);
79 |
80 | final JavaFileObject fileObject = processingEnv.getFiler().createSourceFile(daoQualifiedName);
81 | try (Writer w = fileObject.openWriter()) {
82 |
83 | ClassName modelType = ClassName.get(typeElement);
84 | ClassName primaryKeyType = ClassName.get(primaryKey.getPackageName(), primaryKey.getClassName());
85 | TypeName connectionProviderType = ParameterizedTypeName.get(ClassName.get(Provider.class), ClassName.get(Connection.class));
86 | ParameterizedTypeName genericDAO = ParameterizedTypeName.get(ClassName.get(GenericDAO.class), modelType, primaryKeyType);
87 |
88 | TypeSpec type = TypeSpec.classBuilder(daoClassName)
89 | .addModifiers(Modifier.PUBLIC)
90 | .superclass(genericDAO)
91 |
92 | .addMethod(MethodSpec.constructorBuilder()
93 | .addModifiers(Modifier.PUBLIC)
94 | .addParameter(RethinkDBPool.class, "pool")
95 | .addStatement("this(() -> pool.getConnection())")
96 | .build())
97 |
98 | .addMethod(MethodSpec.constructorBuilder()
99 | .addModifiers(Modifier.PUBLIC)
100 | .addParameter(Connection.class, "connection")
101 | .addStatement("this(() -> new $T(connection))", PersistentConnection.class)
102 | .build())
103 |
104 | .addMethod(MethodSpec.constructorBuilder()
105 | .addModifiers(Modifier.PUBLIC)
106 | .addParameter(connectionProviderType, "connectionProvider")
107 | .addStatement("super(connectionProvider, $T.class, $S, $S)",
108 | modelType, modelAnnotation.tableName(), primaryKey.getVariableName())
109 | .addCode(createIndiceCodeBlock(indices))
110 | .build())
111 |
112 | .build();
113 |
114 | JavaFile.builder(packageElement.getQualifiedName().toString(), type)
115 | .build().writeTo(w);
116 | }
117 | }
118 | }
119 | }
120 |
121 | private CodeBlock createIndiceCodeBlock(Set indices) {
122 | final CodeBlock.Builder builder = CodeBlock.builder();
123 | for (IndexModel index : indices) {
124 | builder.addStatement("addIndex(" + index.isGeo() + ", $S)", Joiner.on(",").join(index.getFields()));
125 | }
126 | return builder.build();
127 | }
128 |
129 | private PrimaryKeyModel scanPrimaryKey(TypeElement element) {
130 | final List variables = ElementFilter.fieldsIn(element.getEnclosedElements());
131 | final Set primaryKeys = variables.stream().filter(v -> v.getAnnotation(PrimaryKey.class) != null).collect(Collectors.toSet());
132 |
133 | if (primaryKeys.size() > 1) {
134 | log(Kind.ERROR, "Only one @PrimaryKey allowed.");
135 | throw new IllegalArgumentException();
136 | }
137 |
138 | return primaryKeys.stream().findFirst()
139 | .map(v -> new PrimaryKeyModel(getTypeElement(v.asType()), v.getSimpleName().toString()))
140 | .orElse(new PrimaryKeyModel("java.lang", "String", "id"));
141 | }
142 |
143 | private Set scanIndices(RethinkDBModel element) {
144 | return Arrays.stream(element.indices()).map(i -> new IndexModel(i.geo(), i.fields())).collect(Collectors.toSet());
145 | }
146 |
147 | private TypeElement getTypeElement(TypeMirror type) {
148 | return (TypeElement) processingEnv.getTypeUtils().asElement(type);
149 | }
150 |
151 | private void log(Kind level, String message, Object... arguments) {
152 | processingEnv.getMessager().printMessage(level, String.format(message, arguments));
153 | }
154 | }
--------------------------------------------------------------------------------
/rethinkdb-orm/src/main/java/de/jakobjarosch/rethinkdb/orm/dao/DAOIterator.java:
--------------------------------------------------------------------------------
1 | package de.jakobjarosch.rethinkdb.orm.dao;
2 |
3 |
4 | import com.rethinkdb.net.Cursor;
5 |
6 | import java.io.Closeable;
7 | import java.io.IOException;
8 | import java.util.Iterator;
9 | import java.util.Map;
10 | import java.util.Optional;
11 |
12 |
13 | public class DAOIterator implements Iterator, Closeable {
14 |
15 | private final Iterator> iterator;
16 | private final Optional closable;
17 | private final Class clazz;
18 | private final ModelMapper mapper;
19 |
20 | public DAOIterator(Iterator> iterator, Class clazz, ModelMapper mapper) {
21 | this.iterator = iterator;
22 | this.closable = Optional.empty();
23 | this.clazz = clazz;
24 | this.mapper = mapper;
25 | }
26 |
27 | public DAOIterator(Cursor> cursor, Class clazz, ModelMapper mapper) {
28 | this.iterator = cursor;
29 | this.closable = Optional.of(cursor::close);
30 | this.clazz = clazz;
31 | this.mapper = mapper;
32 | }
33 |
34 | @Override
35 | public void close() throws IOException {
36 | if (closable.isPresent()) {
37 | closable.get().close();
38 | }
39 | }
40 |
41 | @Override
42 | public boolean hasNext() {
43 | return iterator.hasNext();
44 | }
45 |
46 | @Override
47 | public T next() {
48 | return mapper.map((Map) iterator.next(), clazz);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/rethinkdb-orm/src/main/java/de/jakobjarosch/rethinkdb/orm/dao/GenericDAO.java:
--------------------------------------------------------------------------------
1 | package de.jakobjarosch.rethinkdb.orm.dao;
2 |
3 | import com.google.common.base.Joiner;
4 | import com.google.common.collect.Lists;
5 | import com.rethinkdb.RethinkDB;
6 | import com.rethinkdb.gen.ast.GetField;
7 | import com.rethinkdb.gen.ast.IndexCreate;
8 | import com.rethinkdb.gen.ast.ReqlExpr;
9 | import com.rethinkdb.gen.ast.Table;
10 | import com.rethinkdb.gen.exc.ReqlClientError;
11 | import com.rethinkdb.gen.exc.ReqlDriverError;
12 | import com.rethinkdb.gen.exc.ReqlInternalError;
13 | import com.rethinkdb.model.OptArgs;
14 | import com.rethinkdb.net.Connection;
15 | import com.rethinkdb.net.Cursor;
16 | import de.jakobjarosch.rethinkdb.orm.model.ChangeFeedElement;
17 | import de.jakobjarosch.rethinkdb.orm.model.IndexModel;
18 | import rx.Observable;
19 |
20 | import javax.inject.Provider;
21 | import java.util.*;
22 | import java.util.function.Function;
23 | import java.util.stream.Collectors;
24 |
25 | public class GenericDAO {
26 |
27 | private static final RethinkDB R = RethinkDB.r;
28 | private static final ModelMapper MAPPER = new ModelMapper();
29 |
30 |
31 | private final Provider connectionProvider;
32 | private final Class clazz;
33 | private final String tableName;
34 | private final String primaryKey;
35 |
36 | private final Set indices = new HashSet<>();
37 |
38 | public GenericDAO(Provider connection, Class clazz, String tableName, String primaryKey) {
39 | this.connectionProvider = connection;
40 | this.clazz = clazz;
41 | this.tableName = tableName;
42 | this.primaryKey = primaryKey;
43 | }
44 |
45 | protected void addIndex(boolean geo, String fields) {
46 | this.indices.add(new IndexModel(geo, fields.split(",")));
47 | }
48 |
49 | /**
50 | * Initialize the table, automatically create the table and indices if they do not yet exist.
51 | */
52 | public void initTable() {
53 | try (Connection connection = connectionProvider.get()) {
54 | if (!hasTable(connection, tableName)) {
55 | R.tableCreate(tableName).optArg("primary_key", primaryKey).run(connection);
56 | }
57 |
58 | for (IndexModel index : indices) {
59 | String indexName = Joiner.on("_").join(index.getFields());
60 | if (!hasIndex(connection, indexName)) {
61 | IndexCreate indexCreate = R.table(tableName)
62 | .indexCreate(indexName, row -> indexFieldsToReQL(row, index.getFields()));
63 | if (index.isGeo()) {
64 | indexCreate = indexCreate.optArg("geo", true);
65 | }
66 |
67 | indexCreate.run(connection);
68 | }
69 | }
70 | }
71 | }
72 |
73 | /**
74 | * Creates a model in the RethinkDB table.
75 | *
76 | * @param model Model which should be created.
77 | * @throws ReqlClientError Error is thrown when there was an error.
78 | * E.g. there was already a model with the same primary key.
79 | */
80 | public void create(T model) {
81 | try (Connection connection = connectionProvider.get()) {
82 | Map, ?> map = MAPPER.map(model);
83 | Map result = R.table(tableName).insert(map).run(connection);
84 |
85 | if (((Long) result.get("errors")) > 0) {
86 | throw new ReqlClientError("Failed to create model: %s", ((String) result.get("first_error")).split("\n")[0]);
87 | }
88 | }
89 | }
90 |
91 | /**
92 | * Retrieves a model with the given primary key.
93 | *
94 | * @param id The primary key of the model which should be retrieved.
95 | * @return Maybe the model matching the given primary key.
96 | */
97 | public Optional read(PK id) {
98 | try (Connection connection = connectionProvider.get()) {
99 | Map, ?> map = R.table(tableName).get(id).run(connection);
100 | return Optional.ofNullable(MAPPER.map(map, clazz));
101 | }
102 | }
103 |
104 | /**
105 | * Returns all models in the table, use this with caution,
106 | * without filtering it could return a huge amount of data.
107 | *
108 | * @return Returns a list of all models in the table.
109 | */
110 | public DAOIterator read() {
111 | return read(t -> t);
112 | }
113 |
114 | /**
115 | * Retrieves a iterator returning all models matching the given filter.
116 | *
117 | * Be sure to call {@link DAOIterator#close()} after finishing the iterator.
118 | *
119 | * @param filter The filter function which should be applied when executing the query.
120 | * @return An iterator for models matching the given filter.
121 | */
122 | public DAOIterator read(Function filter) {
123 | try (Connection connection = connectionProvider.get()) {
124 | final Table table = R.table(tableName);
125 | Object result = filter.apply(table).run(connection);
126 | if (result instanceof List) {
127 | List list = ((List>) result).stream()
128 | .map(map -> MAPPER.map((Map) map, clazz))
129 | .collect(Collectors.toList());
130 | return new DAOIterator<>(list.iterator(), clazz, MAPPER);
131 | } else if (result instanceof Map) {
132 | return new DAOIterator<>(Lists.newArrayList(result).iterator(), clazz, MAPPER);
133 | } else if (result instanceof Cursor) {
134 | Cursor> cursor = (Cursor>) result;
135 | return new DAOIterator<>(cursor, clazz, MAPPER);
136 | } else {
137 | throw new ReqlInternalError("Unknown return type for query: " + result.getClass());
138 | }
139 | }
140 | }
141 |
142 | /**
143 | * Updates a model.
144 | *
145 | * @param id The id of the model which should be updated.
146 | * @param model The model which should be updated.
147 | */
148 | public void update(PK id, T model) {
149 | try (Connection connection = connectionProvider.get()) {
150 | Map, ?> map = MAPPER.map(model);
151 | Map result = R.table(tableName).get(id).update(map).run(connection);
152 |
153 | if (((Long) result.get("errors")) > 0) {
154 | throw new ReqlClientError("Failed to update model. %s", ((String) result.get("first_error")).split("\n")[0]);
155 | }
156 | }
157 | }
158 |
159 | /**
160 | * Updates a model in the non atomic way. See ReQL command: update
161 | * for more details.
162 | *
163 | * @param id The id of the model which should be updated.
164 | * @param model The model which should be updated.
165 | */
166 | public void updateNonAtomic(PK id, T model) {
167 | try (Connection connection = connectionProvider.get()) {
168 | R.table(tableName).get(id).update(model).run(connection, OptArgs.of("non_atomic", true));
169 | }
170 | }
171 |
172 | /**
173 | * Deletes a model from the table.
174 | *
175 | * @param id The primary key of the model which should be removed.
176 | */
177 | public void delete(PK id) {
178 | try (Connection connection = connectionProvider.get()) {
179 | R.table(tableName).get(id).delete().run(connection);
180 | }
181 | }
182 |
183 | /**
184 | * Provides a change feed of all changes which occur after subscribing to the returned {@link Observable}.
185 | *
186 | * @return Returns an {@link Observable} which subscribes to all changes made after the subscription started.
187 | */
188 | public Observable> changes() {
189 | return changes(t -> t);
190 | }
191 |
192 | /**
193 | * Provides a change feed of all matching changes which occur after subscribing to the returned {@link Observable}.
194 | *
195 | * @param filter A filter for the change feed to only show changes matching the filter.
196 | * @return Returns an {@link Observable} which subscribes to all matching changes made after the subscription started.
197 | */
198 | @SuppressWarnings("unchecked")
199 | public Observable> changes(Function filter) {
200 | return Observable.create(subscriber -> {
201 | Cursor