├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── libraries │ ├── Gradle__joda_time_joda_time_2_3.xml │ ├── Gradle__junit_junit_4_11.xml │ ├── Gradle__org_hamcrest_hamcrest_core_1_3.xml │ ├── Gradle__org_jetbrains_kotlin_kotlin_reflect_1_0_0.xml │ ├── Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_0.xml │ ├── Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_0.xml │ ├── Gradle__org_jetbrains_kotlin_kotlin_test_1_0_0.xml │ ├── Gradle__org_jetbrains_spek_spek_0_1_195.xml │ └── Gradle__org_mongodb_mongo_java_driver_3_0_3.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── kotlin-nosql-mongodb ├── build.gradle ├── kotlin-nosql-mongodb.iml └── src │ ├── main │ └── kotlin │ │ └── kotlinx │ │ └── nosql │ │ └── mongodb │ │ ├── DocumentSchema.kt │ │ ├── MongoDB.kt │ │ ├── MongoDBIndex.kt │ │ └── MongoDBSession.kt │ └── test │ └── kotlin │ └── kotlinx │ └── nosql │ └── mongodb │ └── test │ └── MongoDBSpek.kt ├── kotlin-nosql.iml ├── settings.gradle └── src └── main └── kotlin └── kotlinx └── nosql ├── AbstractColumn.kt ├── AbstractIndex.kt ├── AbstractNullableColumn.kt ├── AbstractSchema.kt ├── AbstractTableSchema.kt ├── AndQuery.kt ├── Column.kt ├── ColumnDecuple.kt ├── ColumnNonuple.kt ├── ColumnOctuple.kt ├── ColumnPair.kt ├── ColumnQuadruple.kt ├── ColumnQueryWrapper.kt ├── ColumnQuintuple.kt ├── ColumnSeptuple.kt ├── ColumnSextuple.kt ├── ColumnTriple.kt ├── ColumnType.kt ├── Database.kt ├── Decuple.kt ├── Discriminator.kt ├── DocumentSchema.kt ├── DocumentSchemaIdQueryWrapper.kt ├── DocumentSchemaOperations.kt ├── DocumentSchemaQueryParams.kt ├── DocumentSchemaQueryWrapper.kt ├── Expression.kt ├── Id.kt ├── IdListColumn.kt ├── IdSetColumn.kt ├── IndexOperations.kt ├── KeyValueDocumentSchemaOperations.kt ├── KeyValueSchema.kt ├── KeyValueSchemaOperations.kt ├── ListColumn.kt ├── LiteralExpression.kt ├── Nonuple.kt ├── NotEqualQuery.kt ├── NotMemberOfQuery.kt ├── NullableColumn.kt ├── NullableIdColumn.kt ├── Octuple.kt ├── PrimaryKey.kt ├── Quadruple.kt ├── Query.kt ├── Quintuple.kt ├── SchemaGenerationAction.kt ├── Septuple.kt ├── Session.kt ├── SetColumn.kt ├── Sextuple.kt ├── TableSchema.kt ├── TableSchemaOperations.kt ├── TableSchemaProjectionQueryParams.kt ├── TableSchemaProjectionQueryWrapper.kt ├── query ├── EqualQuery.kt ├── GreateQuery.kt ├── GreaterEqualQuery.kt ├── IsNotNullQuery.kt ├── IsNullQuery.kt ├── LessEqualQuery.kt ├── LessQuery.kt ├── MatchesQuery.kt ├── MemberOfQuery.kt ├── NoQuery.kt ├── OrQuery.kt └── TextQuery.kt └── util └── SchemaUtils.kt /.idea/.name: -------------------------------------------------------------------------------- 1 | kotlin-nosql -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 26 | 27 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__joda_time_joda_time_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__junit_junit_4_11.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_reflect_1_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_test_1_0_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_jetbrains_spek_spek_0_1_195.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/libraries/Gradle__org_mongodb_mongo_java_driver_3_0_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kotlin NoSQL 2 | 3 | Kotlin NoSQL is a reactive and type-safe DSL for working with NoSQL databases. 4 | 5 | ## Status 6 | 7 | Under development (POC). The following NoSQL databases are supported now: 8 | 9 | - [MongoDB](https://www.mongodb.org/) 10 | 11 | Feedback is welcome. 12 | 13 | ## Download 14 | 15 | To use it with Maven insert the following code in your pom.xml file: 16 | 17 | ```xml 18 | 19 | org.jetbrains.kotlin 20 | kotlin-nosql-mongodb 21 | 0.1-SNAPSHOT 22 | 23 | 24 | 25 | 26 | kotlin-nosql 27 | http://repository.jetbrains.com/kotlin-nosql 28 | 29 | 30 | ``` 31 | 32 | To use it with Gradle insert the following code in your build.gradle: 33 | 34 | ```groovy 35 | repositories { 36 | maven { 37 | url "http://repository.jetbrains.com/kotlin-nosql" 38 | } 39 | } 40 | 41 | dependencies { 42 | compile 'org.jetbrains.kotlin:kotlin-nosql-mongodb:0.1-SNAPSHOT' 43 | } 44 | ``` 45 | 46 | ## Getting Started 47 | 48 | Demo: http://www.youtube.com/watch?v=80xgl3KThvM 49 | 50 | ### Basics 51 | 52 | #### Define a schema 53 | 54 | ```kotlin 55 | object Comments: DocumentSchema("comments", Comment::class) { 56 | val discussionId = id("discussion_id", Discussions) 57 | val slug = string("slug") 58 | val fullSlug = string("full_slug") 59 | val posted = dateTime("posted") 60 | val text = string("text") 61 | 62 | val AuthorInfo = AuthorInfoColumn() 63 | 64 | class AuthorInfoColumn() : Column("author", AuthorInfo::class) { 65 | val authorId = id("id", Authors) 66 | val name = string("name") 67 | } 68 | } 69 | 70 | class Comment(val discussionId: Id, val slug: String, 71 | val fullSlug: String, posted: DateTime, text: String, authorInfo: AuthorInfo) { 72 | val id: Id? = null 73 | } 74 | 75 | class AuthorInfo(val authorId: Id, val name: String) 76 | ``` 77 | 78 | #### Define a database 79 | 80 | ```kotlin 81 | val db = MongoDB(database = "test", schemas = arrayOf(Comments), action = CreateDrop(onCreate = { 82 | // ... 83 | })) 84 | 85 | db.withSession { 86 | // ... 87 | } 88 | ``` 89 | 90 | #### Insert a document 91 | 92 | ```kotlin 93 | Comments.insert(Comment(DiscussionId, slug, fullSlug, posted, text, AuthorInfo(author.id, author.name))) 94 | ``` 95 | 96 | #### Get a document by id 97 | 98 | ```kotlin 99 | val comment = Comments.find { id.equal(commentId) }.single() 100 | ``` 101 | 102 | #### Get a list of documents by a filter expression 103 | 104 | ```kotlin 105 | val comments = Comments.find { authorInfo.id.equal(authorId) }.sortBy { posted }.skip(10).take(5).toList() 106 | ``` 107 | 108 | #### Get selected fields by document id 109 | 110 | ```kotlin 111 | val authorInfo = Comments.find { id.equal(commentId) }.projection { authorInfo }.single() 112 | ``` 113 | 114 | #### Get selected fields by a filter expression 115 | 116 | ```kotlin 117 | Comments.find { discussionId.equal(id) }).projection { slug + fullSlug + posted + text + authorInfo }.forEach { 118 | val (slug, fullSlug, posted, text, authorInfo) = it 119 | } 120 | ``` 121 | 122 | #### Update selected fields by document id 123 | 124 | ```kotlin 125 | Comments.find { id.equal(commentId) }.projection { posted }.update(newDate) 126 | ``` 127 | 128 | ```kotlin 129 | Comments.find { id.equal(commentId) }.projection { posted + text }.update(newDate, newText) 130 | ``` 131 | 132 | ### Inheritance 133 | 134 | #### Define a base schema 135 | 136 | ```kotlin 137 | open class ProductSchema(javaClass: Class, discriminator: String) : DocumentSchema("products", 138 | discriminator = Discriminator(string("type"), discriminator)) { 139 | val sku = string("sku") 140 | val title = string("title") 141 | val description = string("description") 142 | val asin = string("asin") 143 | 144 | val Shipping = ShippingColumn() 145 | val Pricing = PricingColumn() 146 | 147 | inner class ShippingColumn>() : Column("shipping", Shipping::class) { 148 | val weight = integer("weight") 149 | val dimensions = DimensionsColumn() 150 | } 151 | 152 | inner class DimensionsColumn>() : Column("dimensions", Dimensions::class) { 153 | val width = integer("width") 154 | val height = integer("height") 155 | val depth = integer("depth") 156 | } 157 | 158 | inner class PricingColumn>() : Column("pricing", Pricing::class) { 159 | val list = integer("list") 160 | val retail = integer("retail") 161 | val savings = integer("savings") 162 | val ptcSavings = integer("pct_savings") 163 | } 164 | } 165 | 166 | object Products : ProductSchema(Product::class, "") 167 | 168 | abstract class Product(val id: Id? = null, val sku: String, val title: String, val description: String, 169 | val asin: String, val shipping: Shipping, val pricing: Pricing) { 170 | val id: Id? = null 171 | } 172 | 173 | class Shipping(val weight: Int, val dimensions: Dimensions) 174 | 175 | class Dimensions(val width: Int, val height: Int, val depth: Int) 176 | 177 | class Pricing(val list: Int, val retail: Int, val savings: Int, val pctSavings: Int) 178 | ``` 179 | 180 | #### Define an inherited schema 181 | 182 | ```kotlin 183 | object Albums : ProductSchema(Album::class, discriminator = "Audio Album") { 184 | val details = DetailsColumn() 185 | 186 | class DetailsColumn() : Column("details", Details::class) { 187 | val title = string("title") 188 | val artistId = id("artistId", Artists) 189 | val genre = setOfString("genre") 190 | 191 | val tracks = TracksColumn() 192 | } 193 | 194 | class TracksColumn() : ListColumn("tracks", Track::class) { 195 | val title = string("title") 196 | val duration = integer("duration") 197 | } 198 | } 199 | 200 | class Album(sku: String, title: String, description: String, asin: String, shipping: Shipping, 201 | pricing: Pricing, val details: Details) : Product(sku, title, description, asin, shipping, pricing) 202 | 203 | class Details(val title: String, val artistId: Id, val genre: Set, val tracks: List) 204 | ``` 205 | 206 | #### Insert a document 207 | 208 | ```kotlin 209 | val productId = Products.insert(Album(sku = "00e8da9b", title = "A Love Supreme", description = "by John Coltrane", 210 | asin = "B0000A118M", shipping = Shipping(weight = 6, dimensions = Dimensions(10, 10, 1)), 211 | pricing = Pricing(list = 1200, retail = 1100, savings = 100, pctSavings = 8), 212 | details = Details(title = "A Love Supreme [Original Recording Reissued]", 213 | artistId = artistId, genre = setOf("Jazz", "General"), 214 | tracks = listOf(Track("A Love Supreme Part I: Acknowledgement", 100), 215 | Track("A Love Supreme Part II: Resolution", 200), 216 | Track("A Love Supreme, Part III: Pursuance", 300))))) 217 | } 218 | ``` 219 | 220 | #### Access documents via an abstract schema 221 | 222 | ```kotlin 223 | for (product in Products.find { id.equal(productId) }) { 224 | if (product is Album) { 225 | } 226 | } 227 | ``` 228 | 229 | #### Access documents via an inherited schema 230 | 231 | ```kotlin 232 | 233 | val album = Albums.find { details.artistId.equal(artistId) }.single() 234 | ``` 235 | 236 | ## Examples 237 | 238 | - [PetClinic Sample Application](http://kotlin-nosql-mongodb-petclinic.herokuapp.com) ([GitHub](https://github.com/cheptsov/kotlin-nosql-mongodb-petclinic)) 239 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | configurations.all { 2 | // check for updates every build 3 | resolutionStrategy.cacheChangingModulesFor 0, 'seconds' 4 | } 5 | 6 | buildscript { 7 | repositories { 8 | mavenCentral() 9 | maven { 10 | url "http://oss.sonatype.org/content/repositories/snapshots" 11 | } 12 | } 13 | dependencies { 14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.0" 15 | } 16 | } 17 | 18 | allprojects { 19 | apply plugin: "kotlin" 20 | 21 | group = "org.jetbrains.kotlin" 22 | version = "0.1-SNAPSHOT" 23 | 24 | repositories { 25 | mavenCentral() 26 | maven { 27 | url "http://repository.jetbrains.com/spek" 28 | } 29 | maven { 30 | url "http://oss.sonatype.org/content/repositories/snapshots" 31 | } 32 | } 33 | 34 | apply plugin: "maven" 35 | 36 | dependencies { 37 | compile 'joda-time:joda-time:2.3' 38 | compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: '1.0.0', changing: true 39 | testCompile group: 'org.jetbrains.spek', name: 'spek', version: '0.1.195', changing: true 40 | } 41 | 42 | task sourcesJar(type: Jar, dependsOn: classes) { 43 | classifier 'sources' 44 | from sourceSets.main.allSource 45 | } 46 | 47 | artifacts { 48 | archives sourcesJar 49 | } 50 | 51 | /* 52 | uploadArchives { 53 | repositories { 54 | mavenDeployer { 55 | repository(url: "http://repository.jetbrains.com/kotlin-nosql") { 56 | authentication(userName: deploy_username, password: deploy_password) 57 | } 58 | pom.groupId = project.group 59 | pom.artifactId = project.name 60 | pom.version = project.version 61 | } 62 | } 63 | } 64 | */ 65 | } 66 | 67 | project(':kotlin-nosql-mongodb') { 68 | dependencies { 69 | compile project(':') 70 | compile 'org.mongodb:mongo-java-driver:3.0.3' 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheptsov/kotlin-nosql/58ec5e5834f7a679ab48dd91919b8047674204f4/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Sep 30 10:02:29 PDT 2014 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.1-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 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 Windowz 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 | -------------------------------------------------------------------------------- /kotlin-nosql-mongodb/build.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheptsov/kotlin-nosql/58ec5e5834f7a679ab48dd91919b8047674204f4/kotlin-nosql-mongodb/build.gradle -------------------------------------------------------------------------------- /kotlin-nosql-mongodb/kotlin-nosql-mongodb.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /kotlin-nosql-mongodb/src/main/kotlin/kotlinx/nosql/mongodb/DocumentSchema.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.mongodb 2 | 3 | import kotlinx.nosql.AbstractColumn 4 | import kotlinx.nosql.Discriminator 5 | import kotlinx.nosql.string 6 | import kotlin.reflect.KClass 7 | 8 | abstract class DocumentSchema(name: String, valueClass: KClass, discriminator: Discriminator>? = null) : kotlinx.nosql.DocumentSchema(name, valueClass, string("_id"), discriminator) { 9 | fun ensureIndex(name: String = "", unique: Boolean = false, 10 | ascending: Array> = arrayOf>(), 11 | descending: Array> = arrayOf>(), 12 | text: Array> = arrayOf>()) { 13 | indices.add(MongoDBIndex(name, unique, ascending, descending, text)) 14 | } 15 | } -------------------------------------------------------------------------------- /kotlin-nosql-mongodb/src/main/kotlin/kotlinx/nosql/mongodb/MongoDB.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.mongodb 2 | 3 | import kotlinx.nosql.Database 4 | import kotlinx.nosql.Session 5 | import com.mongodb.MongoClient 6 | import kotlinx.nosql.AbstractColumn 7 | import kotlinx.nosql.util.* 8 | import java.util.concurrent.ConcurrentHashMap 9 | import com.mongodb.ServerAddress 10 | import com.mongodb.MongoClientOptions 11 | import com.mongodb.MongoClientURI 12 | import kotlinx.nosql.SchemaGenerationAction 13 | import kotlinx.nosql.Create 14 | import kotlinx.nosql.CreateDrop 15 | import kotlinx.nosql.Validate 16 | import kotlinx.nosql.Update 17 | import kotlinx.nosql.AbstractSchema 18 | import com.mongodb.MongoCredential 19 | 20 | fun MongoDB(uri: MongoClientURI, schemas: Array, initialization: SchemaGenerationAction = Validate()): MongoDB { 21 | val seeds: Array = uri.getHosts()!!.map { host -> 22 | if (host.indexOf(':') > 0) { 23 | val tokens = host.split(':') 24 | ServerAddress(tokens[0], tokens[1].toInt()) 25 | } else 26 | ServerAddress(host) 27 | }.toTypedArray() 28 | val database: String = if (uri.getDatabase() != null) uri.getDatabase()!! else "test" 29 | val options: MongoClientOptions = uri.getOptions()!! 30 | val credentials = if (uri.getUsername() != null) 31 | arrayOf(MongoCredential.createMongoCRCredential(uri.getUsername(), database, uri.getPassword())!!) 32 | else arrayOf() 33 | return MongoDB(seeds, database, credentials, options, schemas, initialization) 34 | } 35 | 36 | // TODO: Allow use more than one database 37 | class MongoDB(seeds: Array = arrayOf(ServerAddress()), val database: String = "test", 38 | val credentials: Array = arrayOf(), val options: MongoClientOptions = MongoClientOptions.Builder().build()!!, 39 | schemas: Array, action: SchemaGenerationAction = Validate()) : Database(schemas, action) { 40 | val seeds = seeds 41 | val db = MongoClient(seeds.toList(), credentials.toList(), options).getDB(database)!! 42 | var session = MongoDBSession(db) 43 | 44 | init { 45 | initialize() 46 | } 47 | 48 | // TODO: Use session pool 49 | override fun withSession(statement: MongoDBSession.() -> R): R { 50 | Session.threadLocale.set(session) 51 | val r = session.statement() 52 | Session.threadLocale.set(null) 53 | return r 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /kotlin-nosql-mongodb/src/main/kotlin/kotlinx/nosql/mongodb/MongoDBIndex.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.mongodb 2 | 3 | import kotlinx.nosql.AbstractColumn 4 | import kotlinx.nosql.AbstractIndex 5 | 6 | class MongoDBIndex(name: String = "", unique: Boolean = false, val ascending: Array>, 7 | val descending: Array>, 8 | val text: Array>) : AbstractIndex(name) -------------------------------------------------------------------------------- /kotlin-nosql-mongodb/src/main/kotlin/kotlinx/nosql/mongodb/MongoDBSession.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.mongodb 2 | 3 | import com.mongodb.DB 4 | import com.mongodb.BasicDBObject 5 | import java.lang.reflect.Field 6 | import java.util.ArrayList 7 | import java.util.HashMap 8 | import com.mongodb.DBObject 9 | import java.util.Arrays 10 | import org.bson.types.ObjectId 11 | import com.mongodb.BasicDBList 12 | import kotlinx.nosql.* 13 | import kotlinx.nosql.util.* 14 | import java.util.regex.Pattern 15 | import java.util.Date 16 | import java.util.concurrent.atomic.AtomicReference 17 | import org.joda.time.DateTime 18 | import org.joda.time.format.ISODateTimeFormat 19 | import org.joda.time.LocalDate 20 | import org.joda.time.LocalTime 21 | import com.mongodb.DBCollection 22 | import com.mongodb.DBCursor 23 | import kotlinx.nosql.query.* 24 | import kotlin.collections.* 25 | import kotlin.text.* 26 | 27 | class MongoDBSession(val db: DB) : Session, DocumentSchemaOperations, TableSchemaOperations, IndexOperations { 28 | override fun incr(schema: KeyValueSchema, column: AbstractColumn, value: T): T { 29 | throw UnsupportedOperationException() 30 | } 31 | /*override fun incr(schema: AbstractSchema, column: AbstractColumn, value: T, op: Query): T { 32 | throw UnsupportedOperationException() 33 | }*/ 34 | val dbVersion : String 35 | val searchOperatorSupported: Boolean 36 | 37 | init { 38 | val results = db.command("buildInfo") 39 | dbVersion = results!!.get("version")!!.toString() 40 | val versions = dbVersion.split('.') 41 | searchOperatorSupported = versions[0].toInt() > 2 || (versions[0].toInt() == 2 && versions[1].toInt() >= 6) 42 | } 43 | 44 | override fun createIndex(schema: AbstractSchema, index: AbstractIndex) { 45 | val collection = db.getCollection(schema.schemaName)!! 46 | val dbObject = BasicDBObject() 47 | val i = (index as MongoDBIndex) 48 | for (column in i.ascending) { 49 | dbObject.append(column.name, 1) 50 | } 51 | for (column in i.descending) { 52 | dbObject.append(column.name, -1) 53 | } 54 | for (column in i.text) { 55 | dbObject.append(column.name, "text") 56 | } 57 | if (i.name.isNotEmpty()) 58 | collection.createIndex(dbObject, i.name) 59 | else 60 | collection.createIndex(dbObject) 61 | } 62 | 63 | override fun T.create() { 64 | db.createCollection(this.schemaName, BasicDBObject()) 65 | } 66 | 67 | override fun T.drop() { 68 | val collection = db.getCollection(this.schemaName)!! 69 | collection.drop() 70 | } 71 | 72 | override fun , P: Any, V: Any> T.insert(v: V): Id { 73 | val collection = db.getCollection(this.schemaName)!! 74 | val doc = getDBObject(v, this) 75 | if (discriminator != null) { 76 | var dominatorValue: Any? = null 77 | for (entry in kotlinx.nosql.DocumentSchema.discriminatorClasses.entries) { 78 | if (entry.value.java.equals(v.javaClass)) { 79 | dominatorValue = entry.key.value 80 | } 81 | } 82 | doc.set(this.discriminator!!.column.name, dominatorValue!!) 83 | } 84 | collection.insert(doc) 85 | return Id(doc.get("_id").toString() as P) 86 | } 87 | 88 | private fun getDBObject(o: Any, schema: Any): BasicDBObject { 89 | val doc = BasicDBObject() 90 | val javaClass = o.javaClass 91 | val fields = getAllFields(javaClass) 92 | var sc: Class? = null 93 | var s: AbstractSchema? = null 94 | if (schema is kotlinx.nosql.DocumentSchema<*, *> && schema.discriminator != null) { 95 | for (entry in kotlinx.nosql.DocumentSchema.discriminatorClasses.entries) { 96 | if (entry.value.java.equals(o.javaClass)) { 97 | sc = kotlinx.nosql.DocumentSchema.discriminatorSchemaClasses.get(entry.key)!! 98 | s = kotlinx.nosql.DocumentSchema.discriminatorSchemas.get(entry.key)!! 99 | } 100 | } 101 | } 102 | val schemaClass: Class = if (schema is kotlinx.nosql.DocumentSchema<*, *> && schema.discriminator != null) sc!! else schema.javaClass 103 | val objectSchema: Any = if (schema is kotlinx.nosql.DocumentSchema<*, *> && schema.discriminator != null) s!! else schema 104 | val schemaFields = getAllFieldsMap(schemaClass as Class, { f -> f.isColumn }) 105 | for (field in fields) { 106 | val schemaField = schemaFields.get(field.getName()!!.toLowerCase()) 107 | if (schemaField != null && schemaField.isColumn) { 108 | field.setAccessible(true) 109 | schemaField.setAccessible(true) 110 | val column = schemaField.asColumn(objectSchema) 111 | val value = field.get(o) 112 | if (value != null) { 113 | if (column.columnType.primitive) { 114 | doc.append(column.name, when (value) { 115 | is DateTime, is LocalDate, is LocalTime -> value.toString() 116 | is Id<*, *> -> ObjectId(value.value.toString()) 117 | else -> value 118 | }) 119 | } else if (column.columnType.iterable) { 120 | val list = BasicDBList() 121 | for (v in (value as Iterable)) { 122 | list.add(if (column.columnType.custom) getDBObject(v, column) else 123 | (if (v is Id<*, *>) ObjectId(v.toString()) else v)) 124 | } 125 | doc.append(column.name, list) 126 | } else doc.append(column.name, getDBObject(value, column)) 127 | } 128 | } 129 | } 130 | return doc 131 | } 132 | 133 | override fun , P: Any, C: Any> find(params: DocumentSchemaQueryParams): Iterator { 134 | if (params.query != null && !searchOperatorSupported && params.query!!.usesSearch()) 135 | return params.schema.runCommandText(params.query!!) 136 | else 137 | return object : Iterator { 138 | var cursor: DBCursor? = null 139 | var pos = 0 140 | override fun next(): C { 141 | if (cursor == null) { 142 | val collection = db.getCollection(params.schema.schemaName) 143 | val query = if (params.query != null) getQuery(params.query!!) else BasicDBObject() 144 | cursor = collection!!.find(query)!! 145 | if (params.skip != null) { 146 | cursor!!.skip(params.skip!!) 147 | } 148 | } 149 | val value = getObject(cursor!!.next(), params.schema) as C 150 | pos++ 151 | if (!cursor!!.hasNext() || (params.take != null && pos == params.take!!)) { 152 | cursor!!.close() 153 | pos = -1 154 | } 155 | return value 156 | } 157 | override fun hasNext(): Boolean { 158 | if (cursor == null) { 159 | val collection = db.getCollection(params.schema.schemaName) 160 | val query = if (params.query != null) getQuery(params.query!!) else BasicDBObject() 161 | cursor = collection!!.find(query)!! 162 | if (params.skip != null) { 163 | cursor!!.skip(params.skip!!) 164 | } 165 | } 166 | return pos != -1 && cursor!!.hasNext() && (params.take == null || pos < params.take!!) 167 | } 168 | } 169 | } 170 | 171 | private fun , P: Any, C: Any> T.runCommandText(op: Query): Iterator { 172 | val searchCmd = BasicDBObject() 173 | searchCmd.append("text", this.schemaName) 174 | // TODO: Only supports text(...) and other condition 175 | searchCmd.append("search", when (op) { 176 | is TextQuery -> op.search 177 | is AndQuery -> if (op.expr1 is TextQuery) (op.expr1 as TextQuery).search else throw UnsupportedOperationException() 178 | else -> throw UnsupportedOperationException() 179 | }) 180 | val schema = this 181 | if (op is AndQuery) { 182 | searchCmd.append("filter", getQuery(op.expr2)) 183 | } 184 | val result = db.command(searchCmd)!! 185 | 186 | val objects = ArrayList() 187 | for (doc in result.get("results") as BasicDBList) { 188 | objects.add(getObject((doc as DBObject).get("obj") as DBObject, schema)) 189 | } 190 | 191 | return objects.iterator() 192 | } 193 | 194 | override fun , P: Any, V: Any> find(params: TableSchemaProjectionQueryParams): Iterator { 195 | return object:Iterator { 196 | var cursor: DBCursor? = null 197 | var pos = 0 198 | override fun next(): V { 199 | if (cursor == null) { 200 | val collection = db.getCollection(params.table.schemaName) 201 | val fields = BasicDBObject() 202 | params.projection.forEach { 203 | fields.append(it.fullName, "1") 204 | } 205 | val query = if (params.query != null) getQuery(params.query!!) else BasicDBObject() 206 | cursor = collection!!.find(query, fields)!! 207 | if (params.skip != null) { 208 | cursor!!.skip(params.skip!!) 209 | } 210 | } 211 | val doc = cursor!!.next() 212 | val values = ArrayList() 213 | params.projection.forEach { 214 | values.add(getColumnObject(doc, it)) 215 | } 216 | val value = when (values.size) { 217 | 1 -> values[0] as V 218 | 2 -> Pair(values[0], values[1]) as V 219 | 3 -> Triple(values[0], values[1], values[2]) as V 220 | 4 -> Quadruple(values[0], values[1], values[2], values[3]) as V 221 | 5 -> Quintuple(values[0], values[1], values[2], values[3], values[4]) as V 222 | 6 -> Sextuple(values[0], values[1], values[2], values[3], values[4], values[5]) as V 223 | 7 -> Septuple(values[0], values[1], values[2], values[3], values[4], values[5], values[6]) as V 224 | 8 -> Octuple(values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7]) as V 225 | 9 -> Nonuple(values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8]) as V 226 | 10 -> Decuple(values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8], values[9]) as V 227 | else -> throw UnsupportedOperationException() 228 | } 229 | pos++ 230 | if (!cursor!!.hasNext() || (params.take != null && pos == params.take!!)) { 231 | cursor!!.close() 232 | pos = -1 233 | } 234 | return value 235 | } 236 | override fun hasNext(): Boolean { 237 | if (cursor == null) { 238 | val collection = db.getCollection(params.table.schemaName) 239 | val fields = BasicDBObject() 240 | params.projection.forEach { 241 | fields.append(it.fullName, "1") 242 | } 243 | val query = if (params.query != null) getQuery(params.query!!) else BasicDBObject() 244 | cursor = collection!!.find(query, fields)!! 245 | if (params.skip != null) { 246 | cursor!!.skip(params.skip!!) 247 | } 248 | } 249 | return pos != -1 && cursor!!.hasNext() && (params.take == null || pos < params.take!!) 250 | } 251 | } 252 | } 253 | 254 | private fun Query.usesSearch(): Boolean { 255 | return when (this) { 256 | is TextQuery -> true 257 | is OrQuery -> this.expr1.usesSearch() || this.expr2.usesSearch() 258 | is AndQuery -> this.expr1.usesSearch() || this.expr2.usesSearch() 259 | else -> false 260 | } 261 | } 262 | 263 | protected fun getQuery(op: Query, removePrefix: String = ""): BasicDBObject { 264 | val query = BasicDBObject() 265 | when (op) { 266 | is EqualQuery -> { 267 | if (op.expr1 is AbstractColumn<*, *, *>) { 268 | if (op.expr2 is LiteralExpression) { 269 | if ((op.expr1 as AbstractColumn<*, *, *>).columnType.primitive) { 270 | if ((op.expr1 as AbstractColumn<*, *, *>).columnType.id) { 271 | query.append((op.expr1 as AbstractColumn<*, *, *>).fullName, ObjectId((op.expr2 as LiteralExpression).value.toString())) 272 | } else { 273 | var columnName = (op.expr1 as AbstractColumn<*, *, *>).fullName 274 | if (removePrefix.isNotEmpty() && columnName.startsWith(removePrefix)) { 275 | columnName = columnName.substring(removePrefix.length + 1) 276 | } 277 | query.append( columnName, (op.expr2 as LiteralExpression).value) 278 | } 279 | } else { 280 | throw UnsupportedOperationException() 281 | } 282 | } else if (op.expr2 is AbstractColumn<*, *, *>) { 283 | query.append("\$where", "this.${(op.expr1 as AbstractColumn<*, *, *>).fullName} == this.${(op.expr2 as AbstractColumn<*, *, *>).fullName}") 284 | } else { 285 | throw UnsupportedOperationException() 286 | } 287 | } else { 288 | throw UnsupportedOperationException() 289 | } 290 | } 291 | is MatchesQuery -> { 292 | if (op.expr1 is AbstractColumn<*, *, *>) { 293 | if (op.expr2 is LiteralExpression) { 294 | if ((op.expr2 as LiteralExpression).value is Pattern) { 295 | query.append((op.expr1 as AbstractColumn<*, *, *>).fullName, BasicDBObject().append("\$regex", (op.expr2 as LiteralExpression).value)) 296 | } else { 297 | throw UnsupportedOperationException() 298 | } 299 | } else { 300 | throw UnsupportedOperationException() 301 | } 302 | } else { 303 | throw UnsupportedOperationException() 304 | } 305 | } 306 | is NotEqualQuery -> { 307 | if (op.expr1 is AbstractColumn<*, *, *>) { 308 | if (op.expr2 is LiteralExpression) { 309 | if ((op.expr2 as LiteralExpression).value is String || (op.expr2 as LiteralExpression).value is Int) { 310 | if ((op.expr1 as AbstractColumn<*, *, *>).columnType.id) { 311 | query.append((op.expr1 as AbstractColumn<*, *, *>).fullName, BasicDBObject().append("\$ne", ObjectId((op.expr2 as LiteralExpression).value.toString()))) 312 | } else { 313 | query.append((op.expr1 as AbstractColumn<*, *, *>).fullName, BasicDBObject().append("\$ne", (op.expr2 as LiteralExpression).value)) 314 | } 315 | } else { 316 | throw UnsupportedOperationException() 317 | } 318 | } else if (op.expr2 is AbstractColumn<*, *, *>) { 319 | query.append("\$where", "this.${(op.expr1 as AbstractColumn<*, *, *>).fullName} != this.${(op.expr2 as AbstractColumn<*, *, *>).fullName}") 320 | } else { 321 | throw UnsupportedOperationException() 322 | } 323 | } else { 324 | throw UnsupportedOperationException() 325 | } 326 | } 327 | is GreaterQuery -> { 328 | if (op.expr1 is AbstractColumn<*, *, *>) { 329 | if (op.expr2 is LiteralExpression) { 330 | if ((op.expr2 as LiteralExpression).value is String || (op.expr2 as LiteralExpression).value is Int) { 331 | query.append((op.expr1 as AbstractColumn<*, *, *>).fullName, BasicDBObject().append("\$gt", (op.expr2 as LiteralExpression).value)) 332 | } else { 333 | throw UnsupportedOperationException() 334 | } 335 | } else if (op.expr2 is AbstractColumn<*, *, *>) { 336 | query.append("\$where", "this.${(op.expr1 as AbstractColumn<*, *, *>).fullName} > this.${(op.expr2 as AbstractColumn<*, *, *>).fullName}") 337 | } else { 338 | throw UnsupportedOperationException() 339 | } 340 | } else { 341 | throw UnsupportedOperationException() 342 | } 343 | } 344 | is LessQuery -> { 345 | if (op.expr1 is AbstractColumn<*, *, *>) { 346 | if (op.expr2 is LiteralExpression) { 347 | if ((op.expr2 as LiteralExpression).value is String || (op.expr2 as LiteralExpression).value is Int) { 348 | query.append((op.expr1 as AbstractColumn<*, *, *>).fullName, BasicDBObject().append("\$lt", (op.expr2 as LiteralExpression).value)) 349 | } else { 350 | throw UnsupportedOperationException() 351 | } 352 | } else if (op.expr2 is AbstractColumn<*, *, *>) { 353 | query.append("\$where", "this.${(op.expr1 as AbstractColumn<*, *, *>).fullName} < this.${(op.expr2 as AbstractColumn<*, *, *>).fullName}") 354 | } else { 355 | throw UnsupportedOperationException() 356 | } 357 | } else { 358 | throw UnsupportedOperationException() 359 | } 360 | } 361 | is GreaterEqualQuery -> { 362 | if (op.expr1 is AbstractColumn<*, *, *>) { 363 | if (op.expr2 is LiteralExpression) { 364 | if ((op.expr2 as LiteralExpression).value is String || (op.expr2 as LiteralExpression).value is Int) { 365 | query.append((op.expr1 as AbstractColumn<*, *, *>).fullName, BasicDBObject().append("\$gte", (op.expr2 as LiteralExpression).value)) 366 | } else { 367 | throw UnsupportedOperationException() 368 | } 369 | } else if (op.expr2 is AbstractColumn<*, *, *>) { 370 | query.append("\$where", "this.${(op.expr1 as AbstractColumn<*, *, *>).fullName} >= this.${(op.expr2 as AbstractColumn<*, *, *>).fullName}") 371 | } else { 372 | throw UnsupportedOperationException() 373 | } 374 | } else { 375 | throw UnsupportedOperationException() 376 | } 377 | } 378 | is LessEqualQuery -> { 379 | if (op.expr1 is AbstractColumn<*, *, *>) { 380 | if (op.expr2 is LiteralExpression) { 381 | if ((op.expr2 as LiteralExpression).value is String || (op.expr2 as LiteralExpression).value is Int) { 382 | query.append((op.expr1 as AbstractColumn<*, *, *>).fullName, BasicDBObject().append("\$lte", (op.expr2 as LiteralExpression).value)) 383 | } else { 384 | throw UnsupportedOperationException() 385 | } 386 | } else if (op.expr2 is AbstractColumn<*, *, *>) { 387 | query.append("\$where", "this.${(op.expr1 as AbstractColumn<*, *, *>).fullName} <= this.${(op.expr2 as AbstractColumn<*, *, *>).fullName}") 388 | } else { 389 | throw UnsupportedOperationException() 390 | } 391 | } else { 392 | throw UnsupportedOperationException() 393 | } 394 | } 395 | is MemberOfQuery -> { 396 | if (op.expr1 is AbstractColumn<*, *, *>) { 397 | if (op.expr2 is LiteralExpression) { 398 | if ((op.expr2 as LiteralExpression).value is List<*> || (op.expr2 as LiteralExpression).value is Array<*>) { 399 | query.append((op.expr1 as AbstractColumn<*, *, *>).fullName, BasicDBObject().append("\$in", (op.expr2 as LiteralExpression).value)) 400 | } else { 401 | throw UnsupportedOperationException() 402 | } 403 | } else { 404 | throw UnsupportedOperationException() 405 | } 406 | } else { 407 | throw UnsupportedOperationException() 408 | } 409 | } 410 | is NotMemberOfQuery -> { 411 | if (op.expr1 is AbstractColumn<*, *, *>) { 412 | if (op.expr2 is LiteralExpression) { 413 | if ((op.expr2 as LiteralExpression).value is List<*> || (op.expr2 as LiteralExpression).value is Array<*>) { 414 | query.append((op.expr1 as AbstractColumn<*, *, *>).fullName, BasicDBObject().append("\$nin", (op.expr2 as LiteralExpression).value)) 415 | } else { 416 | throw UnsupportedOperationException() 417 | } 418 | } else { 419 | throw UnsupportedOperationException() 420 | } 421 | } else { 422 | throw UnsupportedOperationException() 423 | } 424 | } 425 | // TODO TODO TODO eq expression and eq expression 426 | is AndQuery -> { 427 | val query1 = getQuery(op.expr1) 428 | val query2 = getQuery(op.expr2) 429 | for (entry in query1.entries) { 430 | query.append(entry.key, entry.value) 431 | } 432 | for (entry in query2.entries) { 433 | query.append(entry.key, entry.value) 434 | } 435 | return query 436 | } 437 | is OrQuery -> { 438 | query.append("\$or", Arrays.asList(getQuery(op.expr1), getQuery(op.expr2))) 439 | } 440 | is TextQuery -> { 441 | query.append("\$text", BasicDBObject().append("\$search", op.search)) 442 | } 443 | is NoQuery -> { 444 | // Do nothing 445 | } 446 | else -> { 447 | throw UnsupportedOperationException() 448 | } 449 | } 450 | return query 451 | } 452 | 453 | private fun , P: Any, V : Any /* not sure */> getObject(doc: DBObject, schema: T): V { 454 | var s: AbstractSchema? = null 455 | val valueInstance: Any = if (schema is kotlinx.nosql.DocumentSchema<*, *> && schema.discriminator != null) { 456 | var instance: Any? = null 457 | val discriminatorValue = doc.get(schema.discriminator!!.column.name) 458 | for (discriminator in kotlinx.nosql.DocumentSchema.tableDiscriminators.get(schema.schemaName)!!) { 459 | if (discriminator.value!!.equals(discriminatorValue)) { 460 | instance = newInstance(kotlinx.nosql.DocumentSchema.discriminatorClasses.get(discriminator)!!.java) 461 | s = kotlinx.nosql.DocumentSchema.discriminatorSchemas.get(discriminator)!! 462 | break 463 | } 464 | } 465 | instance!! 466 | } else { 467 | s = schema 468 | newInstance(schema.valueClass.java) 469 | } 470 | val schemaClass = s!!.javaClass 471 | val schemaFields = getAllFields(schemaClass as Class) 472 | val valueFields = getAllFieldsMap(valueInstance.javaClass as Class) 473 | for (schemaField in schemaFields) { 474 | if (AbstractColumn::class.java.isAssignableFrom(schemaField.getType()!!)) { 475 | val valueField = valueFields.get(if (schemaField.getName()!!.equals("pk")) "id" else schemaField.getName()!!.toLowerCase()) 476 | if (valueField != null) { 477 | schemaField.setAccessible(true) 478 | valueField.setAccessible(true) 479 | val column = schemaField.asColumn(s!!) 480 | val value = doc.get(column.name) 481 | val columnValue: Any? = if (value == null) { 482 | null 483 | } else if (column.columnType.id && !column.columnType.iterable) 484 | Id(value.toString() as P) 485 | else if (column.columnType.primitive) { 486 | when (column.columnType) { 487 | ColumnType.DATE -> LocalDate(value.toString()) 488 | ColumnType.TIME -> LocalTime(value.toString()) 489 | ColumnType.DATE_TIME -> DateTime(value.toString()) 490 | else -> doc.get(column.name) 491 | } 492 | } else if (column.columnType.list && !column.columnType.custom) { 493 | (doc.get(column.name) as BasicDBList).toList() 494 | } else if (column.columnType.set && !column.columnType.custom && !column.columnType.id) { 495 | (doc.get(column.name) as BasicDBList).toSet() 496 | } else if (column.columnType.id && column.columnType.set) { 497 | val list = doc.get(column.name) as BasicDBList 498 | list.map { Id>(it.toString()) }.toSet() 499 | } else if (column.columnType.custom && column.columnType.set) { 500 | val list = doc.get(column.name) as BasicDBList 501 | list.map { getObject(it as DBObject, column as ListColumn<*, out AbstractSchema>) }.toSet() 502 | } else if (column.columnType.custom && column.columnType.list) { 503 | val list = doc.get(column.name) as BasicDBList 504 | list.map { getObject(it as DBObject, column as ListColumn<*, out AbstractSchema>) }.toList() 505 | } else { 506 | getObject(doc.get(column.name) as DBObject, column as Column) 507 | } 508 | if (columnValue != null || column is AbstractNullableColumn) { 509 | valueField.set(valueInstance, columnValue) 510 | } else { 511 | throw NullPointerException() 512 | } 513 | } 514 | } 515 | } 516 | return valueInstance as V 517 | } 518 | 519 | private fun getObject(doc: DBObject, column: AbstractColumn<*, *, *>): Any? { 520 | val valueInstance = newInstance(column.valueClass.java) 521 | val schemaClass = column.javaClass 522 | val columnFields = schemaClass.getDeclaredFields()!! 523 | val valueFields = getAllFieldsMap(valueInstance.javaClass as Class) 524 | for (columnField in columnFields) { 525 | if (columnField.isColumn) { 526 | val valueField = valueFields.get(columnField.getName()!!.toLowerCase()) 527 | if (valueField != null) { 528 | columnField.setAccessible(true) 529 | valueField.setAccessible(true) 530 | val column = columnField.asColumn(column) 531 | val columnValue: Any? = if (column.columnType.id && !column.columnType.iterable) Id>(doc.get(column.name).toString()) 532 | else if (column.columnType.primitive) doc.get(column.name) 533 | else if (column.columnType.list && !column.columnType.custom) (doc.get(column.name) as BasicDBList).toList() 534 | else if (column.columnType.set && !column.columnType.custom && !column.columnType.id) (doc.get(column.name) as BasicDBList).toSet() 535 | else if (column.columnType.custom && column.columnType.list) { 536 | val list = doc.get(column.name) as BasicDBList 537 | list.map { getObject(it as DBObject, column as ListColumn<*, out AbstractSchema>) }.toList() 538 | } else if (column.columnType.id && column.columnType.set) { 539 | val list = doc.get(column.name) as BasicDBList 540 | list.map { Id>(it.toString()) }.toSet() 541 | } else if (column.columnType.custom && column.columnType.set) { 542 | val list = doc.get(column.name) as BasicDBList 543 | list.map { getObject(it as DBObject, column as ListColumn<*, out AbstractSchema>) }.toSet() 544 | } else { 545 | getObject(doc.get(column.name) as DBObject, column as Column<*, out AbstractSchema>) 546 | } 547 | if (columnValue != null || column is AbstractNullableColumn) { 548 | valueField.set(valueInstance, columnValue) 549 | } else { 550 | throw NullPointerException() 551 | } 552 | } 553 | } 554 | } 555 | return valueInstance 556 | } 557 | 558 | override fun insert(columns: Array, Any?>>) { 559 | throw UnsupportedOperationException() 560 | } 561 | 562 | override fun delete(table: T, op: Query): Int { 563 | val collection = db.getCollection(table.schemaName)!! 564 | val query = getQuery(op) 565 | return collection.remove(query)!!.getN() 566 | } 567 | 568 | override fun update(schema: AbstractSchema, columnValues: Array, *>>, op: Query): Int { 569 | val collection = db.getCollection(schema.schemaName)!! 570 | val statement = BasicDBObject() 571 | val doc = BasicDBObject().append("\$set", statement) 572 | for ((column, value) in columnValues) { 573 | statement.append(column.fullName, getDBValue(value, column)) 574 | } 575 | return collection.update(getQuery(op), doc)!!.getN() 576 | } 577 | 578 | override fun addAll(schema: AbstractSchema, column: AbstractColumn, *, *>, values: Collection, op: Query): Int { 579 | val collection = db.getCollection(schema.schemaName)!! 580 | val statement = BasicDBObject() 581 | val doc = BasicDBObject().append("\$pushAll", statement) 582 | statement.append(column.fullName, getDBValue(values, column)) 583 | return collection.update(getQuery(op), doc)!!.getN() 584 | } 585 | 586 | override fun removeAll(schema: AbstractSchema, column: AbstractColumn, *, *>, values: Collection, op: Query): Int { 587 | val collection = db.getCollection(schema.schemaName)!! 588 | val statement = BasicDBObject() 589 | val doc = BasicDBObject().append("\$pullAll", statement) 590 | statement.append(column.fullName, getDBValue(values, column)) 591 | return collection.update(getQuery(op), doc)!!.getN() 592 | } 593 | 594 | override fun removeAll(schema: AbstractSchema, column: AbstractColumn, *, *>, removeOp: Query, op: Query): Int { 595 | val collection = db.getCollection(schema.schemaName)!! 596 | val statement = BasicDBObject() 597 | val doc = BasicDBObject().append("\$pull", statement) 598 | statement.append(column.fullName, getQuery(removeOp, column.fullName)) 599 | return collection.update(getQuery(op), doc)!!.getN() 600 | } 601 | 602 | private fun getDBValue(value: Any?, column: AbstractColumn<*, *, *>, withinIterable: Boolean = false): Any? { 603 | return if (!column.columnType.custom && (!column.columnType.iterable || withinIterable )) { 604 | when (value) { 605 | is DateTime, is LocalDate, is LocalTime -> value.toString() 606 | is Id<*, *> -> ObjectId(value.value.toString()) 607 | else -> value 608 | } 609 | } else if (column.columnType.custom && !column.columnType.iterable) 610 | if (value != null) getDBObject(value, column) else null 611 | else if (column.columnType.list && column.columnType.custom) 612 | (value as List<*>).map { getDBObject(it!!, column) } 613 | else if (column.columnType.set && column.columnType.custom) 614 | (value as Set<*>).map { getDBObject(it!!, column) }.toSet() 615 | else if (column.columnType.list && !column.columnType.custom) 616 | (value as List<*>).map { getDBValue(it!!, column, true) } 617 | else if (column.columnType.set && !column.columnType.custom) 618 | (value as Set<*>).map { getDBValue(it!!, column, true) }.toSet() 619 | else throw UnsupportedOperationException() 620 | } 621 | 622 | private fun getColumnObject(doc: DBObject, column: AbstractColumn<*, *, *>): Any? { 623 | val columnObject = parse(doc, column.fullName.split(".").toTypedArray()) 624 | return if (column.columnType.id && !column.columnType.iterable) { 625 | Id>(columnObject.toString()) 626 | } else if (column.columnType.primitive && !column.columnType.iterable) when (column.columnType) { 627 | ColumnType.DATE -> LocalDate.parse(columnObject.toString()) 628 | ColumnType.TIME -> LocalTime.parse(columnObject.toString()) 629 | ColumnType.DATE_TIME -> DateTime.parse(columnObject.toString()) 630 | else -> columnObject 631 | } else if (column.columnType == ColumnType.STRING_SET) { 632 | (columnObject as BasicDBList).toSet() 633 | } else if (column.columnType == ColumnType.STRING_LIST) { 634 | (columnObject as BasicDBList).toList() 635 | } else if (column.columnType.id && column.columnType.set) { 636 | (columnObject as BasicDBList).map { Id>(it.toString()) }.toSet() 637 | } else if (column.columnType.id && column.columnType.list) { 638 | (columnObject as BasicDBList).map { Id>(it.toString()) } 639 | } else if (column.columnType.custom && column.columnType.list) { 640 | (columnObject as BasicDBList).map { getObject(it as DBObject, column as ListColumn) } 641 | } else if (column.columnType.custom && column.columnType.set) { 642 | (columnObject as BasicDBList).map { getObject(it as DBObject, column as ListColumn) }.toSet() 643 | } else if (column.columnType.custom) { 644 | getObject(columnObject as DBObject, column) 645 | } else { 646 | UnsupportedOperationException() 647 | } 648 | } 649 | 650 | private fun parse(doc: DBObject, path: Array, position: Int = 0): Any? { 651 | val value = doc.get(path[position]) 652 | if (position < path.size - 1) { 653 | return parse(value as DBObject, path, position + 1) 654 | } else { 655 | return value 656 | } 657 | } 658 | 659 | override fun , P: Any, C: Any> T.find(query: T.() -> Query): DocumentSchemaQueryWrapper { 660 | val params = DocumentSchemaQueryParams(this, query()) 661 | return DocumentSchemaQueryWrapper(params) 662 | } 663 | } 664 | -------------------------------------------------------------------------------- /kotlin-nosql-mongodb/src/test/kotlin/kotlinx/nosql/mongodb/test/MongoDBSpek.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.mongodb.test 2 | 3 | import kotlin.test.assertEquals 4 | import kotlinx.nosql.* 5 | import kotlinx.nosql.mongodb.* 6 | import kotlinx.nosql.mongodb.DocumentSchema 7 | import org.joda.time.LocalDate 8 | import org.jetbrains.spek.api.Spek 9 | import java.util.regex.Pattern 10 | import kotlin.reflect.KClass 11 | import kotlin.test.assertTrue 12 | 13 | class MongoDBSpek : Spek() { 14 | open class ProductSchema>(klass: KClass, discriminator: String) : DocumentSchema("products", 15 | klass, discriminator = Discriminator(string("type"), discriminator)) { 16 | val sku = string("sku") 17 | val title = string("title") 18 | val description = string("description") 19 | val asin = string("asin") 20 | val available = boolean("available") 21 | val createdAtDate = date("createdAtDate") 22 | val nullableBooleanNoValue = nullableBoolean("nullableBooleanNoValue") 23 | val nullableBooleanWithValue = nullableBoolean("nullableBooleanWithValue") 24 | val nullableDateNoValue = nullableDate("nullableDateNoValue") 25 | val nullableDateWithValue = nullableDate("nullableDateWithValue") 26 | val cost = double("cost") 27 | val nullableDoubleNoValue = nullableDouble("nullableDoubleNoValue") 28 | val nullableDoubleWithValue = nullableDouble("nullableDoubleWithValue") 29 | val setOfStrings = setOfString("setOfStrings") 30 | 31 | val shipping = ShippingColumn() 32 | val pricing = PricingColumn() 33 | 34 | inner class ShippingColumn>() : Column("shipping", Shipping::class) { 35 | val weight = integer("weight") 36 | val dimensions = DimensionsColumn() 37 | } 38 | 39 | inner class DimensionsColumn>() : Column("dimensions", Dimensions::class) { 40 | val width = integer("width") 41 | val height = integer("height") 42 | val depth = integer("depth") 43 | } 44 | 45 | inner class PricingColumn>() : Column("pricing", Pricing::class) { 46 | val list = integer("list") 47 | val retail = integer("retail") 48 | val savings = integer("savings") 49 | val pctSavings = integer("pct_savings") 50 | } 51 | 52 | init { 53 | ensureIndex(text = arrayOf(title, description)) 54 | ensureIndex(name = "asinIndex", unique = true, ascending = arrayOf(asin)) 55 | } 56 | } 57 | 58 | object Artists : DocumentSchema("artists", Artist::class) { 59 | val name = string("name") 60 | } 61 | 62 | object Products : ProductSchema(Product::class, "") { 63 | } 64 | 65 | object Albums : ProductSchema(Album::class, discriminator = "Audio Album") { 66 | val details = DetailsColumn() 67 | 68 | class DetailsColumn() : Column("details", Details::class) { 69 | val title: AbstractColumn = string("title") 70 | val artistId = id("artistId", Artists) 71 | val artistIds = setOfId("artistIds", Artists) 72 | val genre = setOfString("genre") 73 | 74 | val tracks = TracksColumn() 75 | } 76 | 77 | class TracksColumn() : ListColumn("tracks", Track::class) { 78 | val title = string("title") 79 | val duration = integer("duration") 80 | } 81 | } 82 | 83 | abstract class Product(val sku: String, val title: String, val description: String, 84 | val asin: String, val available: Boolean, val cost: Double, 85 | val createdAtDate: LocalDate, val nullableBooleanNoValue: Boolean?, 86 | val nullableBooleanWithValue: Boolean?, 87 | val nullableDateNoValue: org.joda.time.LocalDate?, val nullableDateWithValue: LocalDate?, 88 | val nullableDoubleNoValue: Double?, val nullableDoubleWithValue: Double?, 89 | val setOfStrings: Set, val shipping: Shipping, val pricing: Pricing) { 90 | val id: Id? = null // How to define id for implementation classes? 91 | } 92 | 93 | class Shipping(val weight: Int, val dimensions: Dimensions) { 94 | } 95 | 96 | class Dimensions(val width: Int, val height: Int, val depth: Int) { 97 | } 98 | 99 | class Pricing(val list: Int, val retail: Int, val savings: Int, val pctSavings: Int) { 100 | } 101 | 102 | class Album(sku: String, title: String, description: String, asin: String, available: Boolean, 103 | cost: Double, createdAtDate: org.joda.time.LocalDate, 104 | nullableBooleanNoValue: Boolean?, nullableBooleanWithValue: Boolean?, 105 | nullableDateNoValue: LocalDate?, nullableDateWithValue: LocalDate?, 106 | nullableDoubleNoValue: Double?, nullableDoubleWithValue: Double?, 107 | setOfStrings: Set, shipping: Shipping, pricing: Pricing, 108 | val details: Details) : Product(sku, title, description, asin, available, cost, createdAtDate, 109 | nullableBooleanNoValue, nullableBooleanWithValue, nullableDateNoValue, nullableDateWithValue, 110 | nullableDoubleNoValue, nullableDoubleWithValue, setOfStrings, shipping, pricing) { 111 | } 112 | 113 | class Artist(val name: String) { 114 | val id: Id? = null 115 | } 116 | 117 | class Details(val title: String, val artistId: Id, val artistIds: Set>, 118 | val genre: Set, val tracks: List) { 119 | } 120 | 121 | class Track(val title: String, val duration: Int) { 122 | } 123 | 124 | init { 125 | given("a polymorhpic schema") { 126 | var artistId: Id? = null 127 | var artistId2: Id? = null 128 | var artistId3: Id? = null 129 | var albumId: Id? = null 130 | 131 | val db = MongoDB(schemas = arrayOf(Artists, Products, Albums), action = CreateDrop(onCreate = { 132 | val arId: Id = Artists.insert(Artist(name = "John Coltrane")) 133 | val arId2: Id = Artists.insert(Artist(name = "Andrey Cheptsov")) 134 | val arId3: Id = Artists.insert(Artist(name = "Daft Punk")) 135 | assert(arId.value.length > 0) 136 | val aId = Albums.insert(Album(sku = "00e8da9b", title = "A Love Supreme", description = "by John Coltrane", 137 | asin = "B0000A118M", available = true, cost = 1.23, createdAtDate = LocalDate(2014, 3, 8), nullableBooleanNoValue = null, 138 | nullableBooleanWithValue = false, nullableDateNoValue = null, nullableDateWithValue = LocalDate(2014, 3, 7), 139 | nullableDoubleNoValue = null, nullableDoubleWithValue = 1.24, 140 | setOfStrings = setOf("Something"), shipping = Shipping(weight = 6, dimensions = Dimensions(10, 10, 1)), 141 | pricing = Pricing(list = 1200, retail = 1100, savings = 100, pctSavings = 8), 142 | details = Details(title = "A Love Supreme [Original Recording Reissued]", 143 | artistId = arId, artistIds = setOf(arId, arId2), 144 | genre = setOf("Jazz", "General"), tracks = listOf(Track("A Love Supreme Part I: Acknowledgement", 100), 145 | Track("A Love Supreme Part II - Resolution", 200), 146 | Track("A Love Supreme, Part III: Pursuance", 300))))) 147 | assert(aId.value.length > 0) 148 | albumId = aId 149 | artistId = arId 150 | artistId2 = arId2 151 | artistId3 = arId3 152 | })) 153 | 154 | on("filtering a non-inherited schema") { 155 | val a = db.withSession { 156 | val artists = Artists.find { name.equal("John Coltrane") }.toList() 157 | it("should return a generated id for artist") { 158 | assert(artists.size == 1) 159 | } 160 | "a" 161 | } 162 | kotlin.test.assertEquals("a", a) 163 | } 164 | 165 | fun validate(results: List) { 166 | assert(results.size == 1) 167 | assert(results[0] is Album) 168 | val album = results[0] as Album 169 | assertEquals("00e8da9b", results[0].sku) 170 | assertEquals(true, results[0].available) 171 | assertEquals(1.23, results[0].cost) 172 | kotlin.test.assertEquals(LocalDate(2014, 3, 8), results[0].createdAtDate) 173 | assert(results[0].nullableDateNoValue == null) 174 | assertEquals(LocalDate(2014, 3, 7), results[0].nullableDateWithValue) 175 | assert(results[0].nullableDoubleNoValue == null) 176 | assertEquals(1.24, results[0].nullableDoubleWithValue) 177 | assert(results[0].nullableBooleanNoValue == null) 178 | assertEquals(false, results[0].nullableBooleanWithValue) 179 | kotlin.test.assertEquals("A Love Supreme", results[0].title) 180 | assertEquals("by John Coltrane", results[0].description) 181 | assertEquals("B0000A118M", results[0].asin) 182 | assert(album.setOfStrings.contains("Something")) 183 | kotlin.test.assertEquals(6, results[0].shipping.weight) 184 | kotlin.test.assertEquals(10, results[0].shipping.dimensions.width) 185 | kotlin.test.assertEquals(10, results[0].shipping.dimensions.height) 186 | kotlin.test.assertEquals(1, results[0].shipping.dimensions.depth) 187 | assertEquals(1200, results[0].pricing.list) 188 | kotlin.test.assertEquals(1100, results[0].pricing.retail) 189 | assertEquals(100, results[0].pricing.savings) 190 | kotlin.test.assertEquals(8, results[0].pricing.pctSavings) 191 | kotlin.test.assertEquals("A Love Supreme [Original Recording Reissued]", album.details.title) 192 | assertEquals(artistId!!, album.details.artistId) 193 | assert(album.details.artistIds.size == 2) 194 | assert(album.details.artistIds.contains(artistId as Id)) 195 | assert(album.details.artistIds.contains(artistId2)) 196 | assert(album.details.genre.size == 2) 197 | assert(album.details.genre.contains("Jazz")) 198 | assert(album.details.genre.contains("General")) 199 | assert(album.details.tracks.size == 3) 200 | assertEquals(album.details.tracks[0].title, "A Love Supreme Part I: Acknowledgement") 201 | assertEquals(album.details.tracks[0].duration, 100) 202 | assertEquals(album.details.tracks[1].title, "A Love Supreme Part II - Resolution") 203 | assertEquals(album.details.tracks[1].duration, 200) 204 | assertEquals(album.details.tracks[2].title, "A Love Supreme, Part III: Pursuance") 205 | kotlin.test.assertEquals(album.details.tracks[2].duration, 300) 206 | } 207 | 208 | /** 209 | * Remove Rxjava 210 | * Replace Observable with Iterable 211 | */ 212 | 213 | on("filtering an abstract schema") { 214 | db.withSession { 215 | val results = Products.find { (sku.equal("00e8da9b")).or(shipping.weight.equal(6)) }.toList() 216 | it("should return a correct object") { 217 | validate(results) 218 | } 219 | } 220 | } 221 | 222 | on("filtering a non-abstract schema") { 223 | db.withSession { 224 | val results: List = Albums.find { details.artistId.equal(artistId!!) }.toList() 225 | it("should return a correct object") { 226 | validate(results) 227 | } 228 | } 229 | } 230 | 231 | on("filtering a non-abstract schema drop take") { 232 | db.withSession { 233 | val results = Products.find { (sku.equal("00e8da9b")).or(shipping.weight.equal(6)) }.skip(1).take(1).toList() 234 | it("should return nothing") { 235 | assert(results.isEmpty()) 236 | } 237 | } 238 | } 239 | 240 | on("getting all elements from a non-abstract schema") { 241 | db.withSession { 242 | val results = Products.find().toList() 243 | it("should return a correct object") { 244 | validate(results) 245 | } 246 | } 247 | } 248 | 249 | on("getting a document by id") { 250 | db.withSession { 251 | val album = Albums.find { id.equal(albumId!!) }.single() 252 | it("should return a correct object") { 253 | validate(listOf(album)) 254 | } 255 | } 256 | } 257 | 258 | on("getting one column by id") { 259 | db.withSession { 260 | val title = Albums.find { id.equal(albumId!!) }.projection { details.title }.single() 261 | it("returns correct values") { 262 | assertEquals("A Love Supreme [Original Recording Reissued]", title) 263 | } 264 | } 265 | } 266 | 267 | on("getting two columns by id") { 268 | db.withSession { 269 | val (title, pricing) = Albums.find { id.equal(albumId!!) }.projection { details.title + pricing }.single() 270 | it("returns correct values") { 271 | assertEquals("A Love Supreme [Original Recording Reissued]", title) 272 | assertEquals(1200, pricing.list) 273 | assertEquals(1100, pricing.retail) 274 | assertEquals(100, pricing.savings) 275 | assertEquals(8, pricing.pctSavings) 276 | } 277 | } 278 | } 279 | 280 | on("getting three columns by id") { 281 | db.withSession { 282 | val (sku, title, pricing) = Albums.find { id.equal(albumId!!) }.projection { sku + details.title + pricing }.single() 283 | it("returns correct values") { 284 | assertEquals("00e8da9b", sku) 285 | assertEquals("A Love Supreme [Original Recording Reissued]", title) 286 | assertEquals(1200, pricing.list) 287 | assertEquals(1100, pricing.retail) 288 | assertEquals(100, pricing.savings) 289 | assertEquals(8, pricing.pctSavings) 290 | } 291 | } 292 | } 293 | 294 | on("getting four columns by id") { 295 | db.withSession { 296 | val (sku, title, description, pricing) = Albums.find{ id.equal(albumId!!) }.projection { sku + title + description + pricing }.single() 297 | it("returns correct values") { 298 | assertEquals("00e8da9b", sku) 299 | assertEquals("A Love Supreme", title) 300 | assertEquals("by John Coltrane", description) 301 | assertEquals(1200, pricing.list) 302 | assertEquals(1100, pricing.retail) 303 | assertEquals(100, pricing.savings) 304 | assertEquals(8, pricing.pctSavings) 305 | } 306 | } 307 | } 308 | 309 | on("getting five columns by id") { 310 | db.withSession { 311 | val (sku, title, description, asin, pricing) = Albums.find{ id.equal(albumId!!) }.projection { sku + title + description + asin + pricing }.single() 312 | it("returns correct values") { 313 | assertEquals("00e8da9b", sku) 314 | assertEquals("A Love Supreme", title) 315 | assertEquals("by John Coltrane", description) 316 | assertEquals("B0000A118M", asin) 317 | assertEquals(1200, pricing.list) 318 | assertEquals(1100, pricing.retail) 319 | assertEquals(100, pricing.savings) 320 | assertEquals(8, pricing.pctSavings) 321 | } 322 | } 323 | } 324 | 325 | on("getting six columns by id") { 326 | db.withSession { 327 | val (sku, title, description, asin, list, retail) = Albums.find { id.equal(albumId!!) }. projection { sku + title + description + asin + pricing.list + pricing.retail }.single() 328 | it("returns correct values") { 329 | assertEquals("00e8da9b", sku) 330 | assertEquals("A Love Supreme", title) 331 | assertEquals("by John Coltrane", description) 332 | assertEquals("B0000A118M", asin) 333 | assertEquals(1200, list) 334 | assertEquals(1100, retail) 335 | } 336 | } 337 | } 338 | 339 | on("getting seven columns by id") { 340 | db.withSession { 341 | val (sku, title, description, asin, list, retail, savings) = Albums.find { id.equal(albumId!!) }.projection { sku + title + description + asin + pricing.list + pricing.retail + pricing.savings}.single() 342 | it("returns correct values") { 343 | assertEquals("00e8da9b", sku) 344 | assertEquals("A Love Supreme", title) 345 | assertEquals("by John Coltrane", description) 346 | assertEquals("B0000A118M", asin) 347 | assertEquals(1200, list) 348 | assertEquals(1100, retail) 349 | assertEquals(100, savings) 350 | } 351 | } 352 | } 353 | 354 | on("getting eight columns by id") { 355 | db.withSession { 356 | val (sku, title, description, asin, list, retail, savings, pctSavings) = Albums.find { id.equal(albumId!!) }.projection { sku + title + description + asin + pricing.list + pricing.retail + pricing.savings + pricing.pctSavings }.single() 357 | it("returns correct values") { 358 | assertEquals("00e8da9b", sku) 359 | assertEquals("A Love Supreme", title) 360 | assertEquals("by John Coltrane", description) 361 | assertEquals("B0000A118M", asin) 362 | assertEquals(1200, list) 363 | assertEquals(1100, retail) 364 | assertEquals(100, savings) 365 | assertEquals(8, pctSavings) 366 | } 367 | } 368 | } 369 | 370 | on("getting nine columns by id") { 371 | db.withSession { 372 | val (sku, title, description, asin, list, retail, savings, pctSavings, shipping) = Albums.find { id.equal(albumId!!) }.projection { sku + title + description + asin + pricing.list + pricing.retail + pricing.savings + pricing.pctSavings + shipping }.single() 373 | it("returns correct values") { 374 | assertEquals("00e8da9b", sku) 375 | assertEquals("A Love Supreme", title) 376 | assertEquals("by John Coltrane", description) 377 | assertEquals("B0000A118M", asin) 378 | assertEquals(1200, list) 379 | assertEquals(1100, retail) 380 | assertEquals(100, savings) 381 | assertEquals(8, pctSavings) 382 | assertEquals(6, shipping.weight) 383 | assertEquals(10, shipping.dimensions.width) 384 | assertEquals(10, shipping.dimensions.height) 385 | assertEquals(1, shipping.dimensions.depth) 386 | } 387 | } 388 | } 389 | 390 | on("getting ten columns by id") { 391 | db.withSession { 392 | val a = with (Albums) { sku + title + description + asin + pricing.list + pricing.retail + pricing.savings + pricing.pctSavings + shipping.weight + shipping.dimensions } 393 | val (sku, title, description, asin, list, retail, savings, pctSavings, weight, dimensions) = Albums.find { id.equal(albumId!!) }.projection { a }.single() 394 | it("returns correct values") { 395 | assertEquals("00e8da9b", sku) 396 | assertEquals("A Love Supreme", title) 397 | assertEquals("by John Coltrane", description) 398 | assertEquals("B0000A118M", asin) 399 | assertEquals(1200, list) 400 | assertEquals(1100, retail) 401 | assertEquals(100, savings) 402 | assertEquals(8, pctSavings) 403 | assertEquals(6, weight) 404 | assertEquals(10, dimensions.width) 405 | assertEquals(10, dimensions.height) 406 | assertEquals(1, dimensions.depth) 407 | } 408 | } 409 | } 410 | 411 | on("getting one id-column by another id") { 412 | db.withSession { 413 | val aId = Albums.find { id.equal(albumId!!) }.projection { details.artistId }.single() 414 | it("returns correct values") { 415 | assertEquals(artistId, aId) 416 | } 417 | } 418 | } 419 | 420 | on("getting one column by filter expression") { 421 | db.withSession { 422 | val title = Albums.find { sku.equal("00e8da9b") }.projection { details.title }.single() 423 | it("returns correct values") { 424 | assertEquals("A Love Supreme [Original Recording Reissued]", title) 425 | } 426 | } 427 | } 428 | 429 | on("getting two columns by a filter expression") { 430 | db.withSession { 431 | val (title, pricing) = Albums.find { sku.equal("00e8da9b") }.projection { details.title + pricing }.single() 432 | it("returns correct values") { 433 | assertEquals("A Love Supreme [Original Recording Reissued]", title) 434 | assertEquals(1200, pricing.list) 435 | assertEquals(1100, pricing.retail) 436 | assertEquals(100, pricing.savings) 437 | assertEquals(8, pricing.pctSavings) 438 | } 439 | } 440 | } 441 | 442 | on("getting three columns by a filter expression") { 443 | db.withSession { 444 | val (sku, title, pricing) = Albums.find { sku.equal("00e8da9b") }.projection { sku + details.title + pricing }.single() 445 | it("returns correct values") { 446 | assertEquals("00e8da9b", sku) 447 | assertEquals("A Love Supreme [Original Recording Reissued]", title) 448 | assertEquals(1200, pricing.list) 449 | assertEquals(1100, pricing.retail) 450 | assertEquals(100, pricing.savings) 451 | assertEquals(8, pricing.pctSavings) 452 | } 453 | } 454 | } 455 | 456 | on("getting four columns by a filter expression") { 457 | db.withSession { 458 | val (sku, title, description, pricing) = Products.find { sku.equal("00e8da9b") }.projection { sku + title + description + pricing }.single() 459 | it("returns correct values") { 460 | assertEquals("00e8da9b", sku) 461 | assertEquals("A Love Supreme", title) 462 | assertEquals("by John Coltrane", description) 463 | assertEquals(1200, pricing.list) 464 | assertEquals(1100, pricing.retail) 465 | assertEquals(100, pricing.savings) 466 | assertEquals(8, pricing.pctSavings) 467 | } 468 | } 469 | } 470 | 471 | on("getting five columns by a filter expression") { 472 | db.withSession { 473 | val (sku, title, description, asin, pricing) = Products.find { sku.equal("00e8da9b") }.projection { sku + title + description + asin + pricing }.single() 474 | it("returns correct values") { 475 | assertEquals("00e8da9b", sku) 476 | assertEquals("A Love Supreme", title) 477 | assertEquals("by John Coltrane", description) 478 | assertEquals("B0000A118M", asin) 479 | assertEquals(1200, pricing.list) 480 | assertEquals(1100, pricing.retail) 481 | assertEquals(100, pricing.savings) 482 | assertEquals(8, pricing.pctSavings) 483 | } 484 | } 485 | } 486 | 487 | on("getting six columns by a filter expression") { 488 | db.withSession { 489 | val (sku, title, description, asin, list, retail) = Products.find { sku.equal("00e8da9b") }.projection { sku + title + description + asin + pricing.list + pricing.retail }.single() 490 | it("returns correct values") { 491 | assertEquals("00e8da9b", sku) 492 | assertEquals("A Love Supreme", title) 493 | assertEquals("by John Coltrane", description) 494 | assertEquals("B0000A118M", asin) 495 | assertEquals(1200, list) 496 | assertEquals(1100, retail) 497 | } 498 | } 499 | } 500 | 501 | on("getting seven columns by a filter expression") { 502 | db.withSession { 503 | val (sku, title, description, asin, list, retail, savings) = Products.find { sku.equal("00e8da9b") }.projection { sku + title + description + asin + pricing.list + pricing.retail + pricing.savings }.single() 504 | it("returns correct values") { 505 | assertEquals("00e8da9b", sku) 506 | assertEquals("A Love Supreme", title) 507 | assertEquals("by John Coltrane", description) 508 | assertEquals("B0000A118M", asin) 509 | assertEquals(1200, list) 510 | assertEquals(1100, retail) 511 | assertEquals(100, savings) 512 | } 513 | } 514 | } 515 | 516 | on("getting eight columns by a filter expression") { 517 | db.withSession { 518 | val (sku, title, description, asin, list, retail, savings, pctSavings) = Products.find { sku.equal("00e8da9b") }.projection { sku + title + description + asin + pricing.list + pricing.retail + pricing.savings + pricing.pctSavings }.single() 519 | it("returns correct values") { 520 | assertEquals("00e8da9b", sku) 521 | assertEquals("A Love Supreme", title) 522 | assertEquals("by John Coltrane", description) 523 | assertEquals("B0000A118M", asin) 524 | assertEquals(1200, list) 525 | assertEquals(1100, retail) 526 | assertEquals(100, savings) 527 | assertEquals(8, pctSavings) 528 | } 529 | } 530 | } 531 | 532 | on("getting nine columns by a filter expression") { 533 | db.withSession { 534 | val (sku, title, description, asin, list, retail, savings, pctSavings, shipping) = Products.find { sku.equal("00e8da9b") }.projection { sku + title + description + asin + pricing.list + pricing.retail + pricing.savings + pricing.pctSavings + shipping}.single() 535 | it("returns correct values") { 536 | assertEquals("00e8da9b", sku) 537 | assertEquals("A Love Supreme", title) 538 | assertEquals("by John Coltrane", description) 539 | assertEquals("B0000A118M", asin) 540 | assertEquals(1200, list) 541 | assertEquals(1100, retail) 542 | assertEquals(100, savings) 543 | assertEquals(8, pctSavings) 544 | assertEquals(6, shipping.weight) 545 | assertEquals(10, shipping.dimensions.width) 546 | assertEquals(10, shipping.dimensions.height) 547 | assertEquals(1, shipping.dimensions.depth) 548 | } 549 | } 550 | } 551 | 552 | on("getting ten columns by a filter expression") { 553 | db.withSession { 554 | val (sku, title, description, asin, list, retail, savings, pctSavings, weight, dimensions) = Products.find { sku.equal("00e8da9b") }.projection { sku + title + description + asin + pricing.list + pricing.retail + pricing.savings + pricing.pctSavings + shipping.weight + shipping.dimensions }.single() 555 | it("returns correct values") { 556 | assertEquals("00e8da9b", sku) 557 | assertEquals("A Love Supreme", title) 558 | assertEquals("by John Coltrane", description) 559 | assertEquals("B0000A118M", asin) 560 | assertEquals(1200, list) 561 | assertEquals(1100, retail) 562 | assertEquals(100, savings) 563 | assertEquals(8, pctSavings) 564 | assertEquals(6, weight) 565 | assertEquals(10, dimensions.width) 566 | assertEquals(10, dimensions.height) 567 | assertEquals(1, dimensions.depth) 568 | } 569 | } 570 | } 571 | 572 | on("filtering an abstract schema by search expression") { 573 | db.withSession { 574 | val results = Products.find { text("Love") }.toList() 575 | it("should return a correct object") { 576 | validate(results) 577 | } 578 | } 579 | } 580 | 581 | on("filtering an abstract schema by search expression") { 582 | db.withSession { 583 | val results = Products.find { text("Love") and shipping.weight.equal(16) }.toList() 584 | it("should return nothing") { 585 | assert(results.isEmpty()) 586 | } 587 | } 588 | } 589 | 590 | on("filtering an abstract schema by search expression (returns nothing)") { 591 | db.withSession { 592 | val results = Products.find { text("Love1") }.toList() 593 | it("should return nothing") { 594 | assert(results.isEmpty()) 595 | } 596 | } 597 | } 598 | 599 | on("filtering an abstract schema by equal expression") { 600 | db.withSession { 601 | val results = Products.find { shipping.weight.equal(6) }.toList() 602 | it("should return a correct object") { 603 | validate(results) 604 | } 605 | } 606 | } 607 | 608 | on("filtering an abstract schema by equal expression") { 609 | db.withSession { 610 | val results = Products.find { shipping.weight.equal(7) }.toList() 611 | it("should return nothing") { 612 | assert(results.isEmpty()) 613 | } 614 | } 615 | } 616 | 617 | on("filtering an abstract schema by notEqual expression") { 618 | db.withSession { 619 | val results = Products.find { shipping.weight.notEqual(7) }.toList() 620 | it("should return a correct object") { 621 | validate(results) 622 | } 623 | } 624 | } 625 | 626 | on("filtering an abstract schema by notEqual expression") { 627 | db.withSession { 628 | val results = Products.find { shipping.weight.notEqual(6) }.toList() 629 | it("should return nothing") { 630 | assert(results.isEmpty()) 631 | } 632 | } 633 | } 634 | 635 | on("filtering an abstract schema by gt expression") { 636 | db.withSession { 637 | val results = Products.find { shipping.weight.gt(5) }.toList() 638 | it("should return a correct object") { 639 | validate(results) 640 | } 641 | } 642 | } 643 | 644 | on("filtering an abstract schema by gt expression") { 645 | db.withSession { 646 | val results = Products.find { shipping.weight.gt(6) }.toList() 647 | it("should return nothing") { 648 | assert(results.isEmpty()) 649 | } 650 | } 651 | } 652 | 653 | on("filtering an abstract schema by lt expression") { 654 | db.withSession { 655 | val results = Products.find { shipping.weight.lt(7) }.toList() 656 | it("should return a correct object") { 657 | validate(results) 658 | } 659 | } 660 | } 661 | 662 | on("filtering an abstract schema by lt expression") { 663 | db.withSession { 664 | val results = Products.find { shipping.weight.lt(6) }.toList() 665 | it("should return nothing") { 666 | assert(results.isEmpty()) 667 | } 668 | } 669 | } 670 | 671 | on("filtering an abstract schema by ge expression") { 672 | db.withSession { 673 | val results = Products.find { shipping.weight.ge(6) }.toList() 674 | it("should return a correct object") { 675 | validate(results) 676 | } 677 | } 678 | } 679 | 680 | on("filtering an abstract schema by ge expression") { 681 | db.withSession { 682 | val results = Products.find { shipping.weight.ge(5) }.toList() 683 | it("should return a correct object") { 684 | validate(results) 685 | } 686 | } 687 | } 688 | 689 | on("filtering an abstract schema by ge expression") { 690 | db.withSession { 691 | val results = Products.find { shipping.weight.ge(7) }.toList() 692 | it("should return nothing") { 693 | assert(results.isEmpty()) 694 | } 695 | } 696 | } 697 | 698 | on("filtering an abstract schema by le expression") { 699 | db.withSession { 700 | val results = Products.find { shipping.weight.le(6) }.toList() 701 | it("should return a correct object") { 702 | validate(results) 703 | } 704 | } 705 | } 706 | 707 | on("filtering an abstract schema by le expression") { 708 | db.withSession { 709 | val results = Products.find { shipping.weight.le(7) }.toList() 710 | it("should return a correct object") { 711 | validate(results) 712 | } 713 | } 714 | } 715 | 716 | on("filtering an abstract schema by le expression") { 717 | db.withSession { 718 | val results = Products.find { shipping.weight.le(5) }.toList() 719 | it("should return nothing") { 720 | assert(results.isEmpty()) 721 | } 722 | } 723 | } 724 | 725 | on("filtering an abstract schema by mb expression") { 726 | db.withSession { 727 | val results = Products.find { shipping.weight.memberOf( arrayOf(5, 6)) }.toList() 728 | it("should return a correct object") { 729 | validate(results) 730 | } 731 | } 732 | } 733 | 734 | on("filtering an abstract schema by mb expression") { 735 | db.withSession { 736 | val results = Products.find { shipping.weight.memberOf( arrayOf(5, 7)) }.toList() 737 | it("should return nothing") { 738 | assert(results.isEmpty()) 739 | } 740 | } 741 | } 742 | 743 | on("filtering an abstract schema by nm expression") { 744 | db.withSession { 745 | val results = Products.find { shipping.weight.notMemberOf( arrayOf(5, 7)) }.toList() 746 | it("should return a correct object") { 747 | validate(results) 748 | } 749 | } 750 | } 751 | 752 | on("filtering an abstract schema by nm expression") { 753 | db.withSession { 754 | val results = Products.find { shipping.weight.notMemberOf( arrayOf(5, 6)) }.toList() 755 | it("should return nothing") { 756 | assert(results.isEmpty()) 757 | } 758 | } 759 | } 760 | 761 | on("filtering an abstract schema by equal expression - compare to a column") { 762 | db.withSession { 763 | val results = Products.find { with (shipping.dimensions) { width.equal(height) } }.toList() 764 | it("should return a correct object") { 765 | validate(results) 766 | } 767 | } 768 | } 769 | 770 | on("filtering an abstract schema by equal expression - compare to a column") { 771 | db.withSession { 772 | val results = Products.find { with (shipping.dimensions) { width.equal(depth) } }.toList() 773 | it("should return nothing") { 774 | assert(results.isEmpty()) 775 | } 776 | } 777 | } 778 | 779 | on("filtering an abstract schema by equal expression - compare to a column") { 780 | db.withSession { 781 | val results = Products.find { with (shipping.dimensions) { width.notEqual(depth) } }.toList() 782 | it("should return a correct object") { 783 | validate(results) 784 | } 785 | } 786 | } 787 | 788 | on("filtering an abstract schema by equal expression - compare to a column") { 789 | db.withSession { 790 | val results = Products.find { with (shipping.dimensions) { width.notEqual(height) } }.toList() 791 | it("should return nothing") { 792 | assert(results.isEmpty()) 793 | } 794 | } 795 | } 796 | 797 | // 798 | 799 | on("filtering an abstract schema by gt expression - compare to a column") { 800 | db.withSession { 801 | val results = Products.find { shipping.dimensions.width.gt(shipping.dimensions.depth) }.toList() 802 | it("should return a correct object") { 803 | validate(results) 804 | } 805 | } 806 | } 807 | 808 | on("filtering an abstract schema by gt expression - compare to a column") { 809 | db.withSession { 810 | val results = Products.find { shipping.dimensions.depth.gt(shipping.dimensions.width) }.toList() 811 | it("should return nothing") { 812 | assert(results.isEmpty()) 813 | } 814 | } 815 | } 816 | 817 | on("filtering an abstract schema by lt expression - compare to a column") { 818 | db.withSession { 819 | val results = Products.find { shipping.dimensions.depth.lt(shipping.dimensions.width) }.toList() 820 | it("should return a correct object") { 821 | validate(results) 822 | } 823 | } 824 | } 825 | 826 | on("filtering an abstract schema by lt expression - compare to a column") { 827 | db.withSession { 828 | val results = Products.find { shipping.dimensions.width.lt(shipping.dimensions.depth) }.toList() 829 | it("should return nothing") { 830 | assert(results.isEmpty()) 831 | } 832 | } 833 | } 834 | 835 | on("filtering an abstract schema by ge expression - compare to a column") { 836 | db.withSession { 837 | val results = Products.find { shipping.dimensions.width.ge(shipping.dimensions.height) }.toList() 838 | it("should return a correct object") { 839 | validate(results) 840 | } 841 | } 842 | } 843 | 844 | on("filtering an abstract schema by ge expression - compare to a column") { 845 | db.withSession { 846 | val results = Products.find { shipping.dimensions.width.ge(shipping.dimensions.depth) }.toList() 847 | it("should return a correct object") { 848 | validate(results) 849 | } 850 | } 851 | } 852 | 853 | on("filtering an abstract schema by ge expression - compare to a column") { 854 | db.withSession { 855 | val results = Products.find { shipping.dimensions.depth.ge(shipping.dimensions.width) }.toList() 856 | it("should return nothing") { 857 | assert(results.isEmpty()) 858 | } 859 | } 860 | } 861 | 862 | on("filtering an abstract schema by le expression - compare to a column") { 863 | db.withSession { 864 | val results = Products.find { shipping.dimensions.depth.le(shipping.dimensions.width) }.toList() 865 | it("should return a correct object") { 866 | validate(results) 867 | } 868 | } 869 | } 870 | 871 | on("filtering an abstract schema by le expression - compare to a column") { 872 | db.withSession { 873 | val results = Products.find { shipping.dimensions.width.le(shipping.dimensions.height) }.toList() 874 | it("should return a correct object") { 875 | validate(results) 876 | } 877 | } 878 | } 879 | 880 | on("filtering an abstract schema by le expression - compare to a column") { 881 | db.withSession { 882 | val results = Products.find { shipping.dimensions.width.le(shipping.dimensions.depth) }.toList() 883 | it("should return nothing") { 884 | assert(results.isEmpty()) 885 | } 886 | } 887 | } 888 | 889 | on("getting one column by regex filter expression") { 890 | db.withSession { 891 | val results = Albums.find { details.title.matches(Pattern.compile("Love Supreme")) }.toList() 892 | it("returns correct values") { 893 | validate(results) 894 | } 895 | } 896 | } 897 | 898 | on("getting one column by regex filter expression") { 899 | db.withSession { 900 | val results = Albums.find { details.title.matches(Pattern.compile("Love Supremex")) }.toList() 901 | it("should return nothing") { 902 | assert(results.isEmpty()) 903 | } 904 | } 905 | } 906 | 907 | on("setting a new value to a string column on a non-abstract schema by id") { 908 | db.withSession { 909 | Albums.find { id.equal(albumId!!) }.projection { details.title }.update("A Love Supreme. Original Recording Reissued") 910 | val title = Albums.find { id.equal(albumId!!) }.projection { details.title }.single() 911 | it("takes effect") { 912 | assertEquals("A Love Supreme. Original Recording Reissued", title) 913 | } 914 | } 915 | } 916 | 917 | on("setting a new value for a string column on a non-abstract schema by id") { 918 | db.withSession { 919 | Albums.find { id.equal(albumId!!) }.projection { details.title }.update("A Love Supreme. Original Recording Reissued") 920 | val title = Albums.find { id.equal(albumId!!) }.projection { details.title }.single() 921 | it("takes effect") { 922 | assertEquals("A Love Supreme. Original Recording Reissued", title) 923 | } 924 | } 925 | } 926 | 927 | on("setting values for two integer columns on an abstract schema by a filter expression") { 928 | db.withSession { 929 | Products.find { sku.equal("00e8da9b") }.projection { pricing.retail + pricing.savings }.update(1150, 50) 930 | val (retail, savings) = Albums.find { id.equal(albumId!!) }.projection { pricing.retail + pricing.savings }.single() 931 | it("takes effect") { 932 | assertEquals(1150, retail) 933 | assertEquals(50, savings) 934 | } 935 | } 936 | } 937 | 938 | on("setting values for three columns on an abstract schema by a filter expression") { 939 | db.withSession { 940 | Products.find { sku.equal("00e8da9b") }.projection { pricing.retail + pricing.savings + pricing.list }.update(1150, 50, 1250) 941 | val (retail, savings, list) = Albums.find { id.equal(albumId!!) }.projection { pricing.retail + pricing.savings + pricing.list }.single() 942 | it("takes effect") { 943 | assertEquals(1150, retail) 944 | assertEquals(50, savings) 945 | assertEquals(1250, list) 946 | } 947 | } 948 | } 949 | 950 | on("setting values for four columns on an abstract schema by a filter expression") { 951 | db.withSession { 952 | Products.find { sku.equal("00e8da9b") }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width }.update(1150, 50, 1250, 11) 953 | val (retail, savings, list, width) = Albums.find { id.equal(albumId!!) }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width }.single() 954 | it("takes effect") { 955 | assertEquals(1150, retail) 956 | assertEquals(50, savings) 957 | assertEquals(1250, list) 958 | assertEquals(11, width) 959 | } 960 | } 961 | } 962 | 963 | on("setting values for five columns on an abstract schema by a filter expression") { 964 | db.withSession { 965 | Products.find { sku.equal("00e8da9b") }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height }.update(1150, 50, 1250, 11, 13) 966 | val (retail, savings, list, width, height) = Albums.find { id.equal(albumId!!) }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height }.single() 967 | it("takes effect") { 968 | assertEquals(1150, retail) 969 | assertEquals(50, savings) 970 | assertEquals(1250, list) 971 | assertEquals(11, width) 972 | assertEquals(13, height) 973 | } 974 | } 975 | } 976 | 977 | on("setting values for six columns on an abstract schema by a filter expression") { 978 | db.withSession { 979 | Products.find { sku.equal("00e8da9b") }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height + shipping.dimensions.depth }.update(1150, 50, 1250, 11, 13, 2) 980 | val (retail, savings, list, width, height, depth) = Albums.find { id.equal(albumId!!) }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height + shipping.dimensions.depth }.single() 981 | it("takes effect") { 982 | assertEquals(1150, retail) 983 | assertEquals(50, savings) 984 | assertEquals(1250, list) 985 | assertEquals(11, width) 986 | assertEquals(13, height) 987 | assertEquals(2, depth) 988 | } 989 | } 990 | } 991 | 992 | on("setting values for seven columns on an abstract schema by a filter expression") { 993 | db.withSession { 994 | Products.find { sku.equal("00e8da9b") }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height + shipping.dimensions.depth + shipping.weight }.update(1150, 50, 1250, 11, 13, 2, 7) 995 | val (retail, savings, list, width, height, depth, weight) = Albums.find { id.equal(albumId!!) }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height + shipping.dimensions.depth + shipping.weight }.single() 996 | it("takes effect") { 997 | assertEquals(1150, retail) 998 | assertEquals(50, savings) 999 | assertEquals(1250, list) 1000 | assertEquals(11, width) 1001 | assertEquals(13, height) 1002 | assertEquals(2, depth) 1003 | assertEquals(7, weight) 1004 | } 1005 | } 1006 | } 1007 | 1008 | on("setting values for eight columns on an abstract schema by a filter expression") { 1009 | db.withSession { 1010 | Products.find { sku.equal("00e8da9b") }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height + shipping.dimensions.depth + shipping.weight + cost }.update(1150, 50, 1250, 11, 13, 2, 7, 1.25) 1011 | val (retail, savings, list, width, height, depth, weight, cost) = Albums.find { id.equal(albumId!!) }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height + shipping.dimensions.depth + shipping.weight + cost }.single() 1012 | it("takes effect") { 1013 | assertEquals(1150, retail) 1014 | assertEquals(50, savings) 1015 | assertEquals(1250, list) 1016 | assertEquals(11, width) 1017 | assertEquals(13, height) 1018 | assertEquals(2, depth) 1019 | assertEquals(7, weight) 1020 | assertEquals(1.25, cost) 1021 | } 1022 | } 1023 | } 1024 | 1025 | on("setting values for nine columns on an abstract schema by a filter expression") { 1026 | db.withSession { 1027 | Products.find { sku.equal("00e8da9b") }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height + shipping.dimensions.depth + shipping.weight + cost + available }.update(1150, 50, 1250, 11, 13, 2, 7, 1.25, false) 1028 | val (retail, savings, list, width, height, depth, weight, cost, available) = Albums.find { id.equal(albumId!!) }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height + shipping.dimensions.depth + shipping.weight + cost + available }.single() 1029 | it("takes effect") { 1030 | assertEquals(1150, retail) 1031 | assertEquals(50, savings) 1032 | assertEquals(1250, list) 1033 | assertEquals(11, width) 1034 | assertEquals(13, height) 1035 | assertEquals(2, depth) 1036 | assertEquals(7, weight) 1037 | assertEquals(1.25, cost) 1038 | assertEquals(false, available) 1039 | } 1040 | } 1041 | } 1042 | 1043 | on("setting values for ten columns on an abstract schema by a filter expression") { 1044 | db.withSession { 1045 | Products.find { sku.equal("00e8da9b") }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height + shipping.dimensions.depth + shipping.weight + cost + available + nullableDoubleWithValue }.update(1150, 50, 1250, 11, 13, 2, 7, 1.25, false, 10.1) 1046 | val (retail, savings, list, width, height, depth, weight, cost, available, nullableDoubleWithValue) = Albums.find { id.equal(albumId!!) }.projection { pricing.retail + pricing.savings + pricing.list + shipping.dimensions.width + shipping.dimensions.height + shipping.dimensions.depth + shipping.weight + cost + available + nullableDoubleWithValue }.single() 1047 | it("takes effect") { 1048 | assertEquals(1150, retail) 1049 | assertEquals(50, savings) 1050 | assertEquals(1250, list) 1051 | assertEquals(11, width) 1052 | assertEquals(13, height) 1053 | assertEquals(2, depth) 1054 | assertEquals(7, weight) 1055 | assertEquals(1.25, cost) 1056 | assertEquals(false, available) 1057 | assertEquals(10.1, nullableDoubleWithValue) 1058 | } 1059 | } 1060 | } 1061 | 1062 | on("setting a new value to a date column on a non-abstract schema by id") { 1063 | db.withSession { 1064 | Albums.find { id.equal(albumId!!) }.projection { nullableDateNoValue }.update(LocalDate(2014, 3, 20)) 1065 | // TODO: single is nullable here 1066 | val nullableDateNoValue = Albums.find { id.equal(albumId!!) }.projection { nullableDateNoValue }.single() 1067 | it("takes effect") { 1068 | assertEquals(LocalDate(2014, 3, 20), nullableDateNoValue!!) 1069 | } 1070 | } 1071 | } 1072 | 1073 | on("adding a new element to a list column on a non-abstract schema by id") { 1074 | db.withSession { 1075 | Albums.find { id.equal(albumId!!) }.projection { details.tracks }.add(Track("A Love Supreme, Part IV-Psalm", 400)) 1076 | val tracks = Albums.find { id.equal(albumId!!) }.projection { Albums.details.tracks }.single()!! 1077 | it("takes effect") { 1078 | assertEquals(4, tracks.size) 1079 | assertEquals("A Love Supreme, Part IV-Psalm", tracks[3].title) 1080 | assertEquals(400, tracks[3].duration) 1081 | } 1082 | } 1083 | } 1084 | 1085 | on("adding a new id to an id set column on a non-abstract schema by id") { 1086 | db.withSession { 1087 | Albums.find { id.equal(albumId!!) }.projection { details.artistIds }.add(artistId3) 1088 | val artistIds = Albums.find { id.equal(albumId!!) }.projection { details.artistIds }.single() 1089 | it("takes effect") { 1090 | assertEquals(3, artistIds.size) 1091 | assertTrue(artistIds.contains(artistId3)) 1092 | } 1093 | } 1094 | } 1095 | 1096 | on("removing sn element from a collection column on a non-abstract schema by id") { 1097 | db.withSession { 1098 | Albums.find { id.equal(albumId!!) }.projection { details.tracks }.remove { duration.equal(100) } 1099 | val tracks = Albums.find { id.equal(albumId!!) }.projection { details.tracks }.single() 1100 | it("takes effect") { 1101 | assertEquals(3, tracks.size) 1102 | } 1103 | } 1104 | } 1105 | 1106 | on("removing an element from a collection column on a non-abstract schema by a filter expression") { 1107 | db.withSession { 1108 | Albums.find { sku.equal("00e8da9b") }.projection { details.tracks }.remove { duration.equal(200) } 1109 | val tracks = Albums.find { id.equal(albumId!!) }.projection { Albums.details.tracks }.single() 1110 | it("takes effect") { 1111 | assertEquals(2, tracks.size) 1112 | } 1113 | } 1114 | } 1115 | 1116 | on("removing an element from a set column on a non-abstract schema by id") { 1117 | db.withSession { 1118 | Albums.find { id.equal(albumId!!) }.projection { details.genre }.remove("General") 1119 | val genre = Albums.find { id.equal(albumId!!) }.projection { Albums.details.genre }.single() 1120 | it("takes effect") { 1121 | assertEquals(1, genre.size) 1122 | } 1123 | } 1124 | } 1125 | 1126 | on("deleting a document") { 1127 | db.withSession { 1128 | Albums.find { id.equal(albumId!!) }.remove() 1129 | val results = Albums.find { id.equal(albumId!!) }.toList() 1130 | it("deletes the document from database") { 1131 | assert(results.isEmpty()) 1132 | } 1133 | } 1134 | } 1135 | } 1136 | } 1137 | } 1138 | 1139 | fun main(args: Array) { 1140 | MongoDBSpek() 1141 | } -------------------------------------------------------------------------------- /kotlin-nosql.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include 'kotlin-nosql-mongodb' 2 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/AbstractColumn.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import java.util.ArrayList 4 | import java.util.regex.Pattern 5 | import kotlinx.nosql.query.* 6 | import kotlin.collections.listOf 7 | import kotlin.collections.setOf 8 | import kotlin.reflect.KClass 9 | 10 | open class AbstractColumn(val name: String, val valueClass: KClass, val columnType: ColumnType) : ColumnQueryWrapper(), Expression { 11 | internal var _schema: AbstractSchema? = null 12 | 13 | val schema: T 14 | get() { 15 | return _schema!! as T 16 | } 17 | 18 | fun matches(other: Pattern): Query { 19 | return MatchesQuery(this, LiteralExpression(other)) 20 | } 21 | 22 | override fun toString(): String { 23 | return "$name" 24 | } 25 | 26 | operator fun plus(c: AbstractColumn): ColumnPair { 27 | return ColumnPair(this, c) as ColumnPair 28 | } 29 | } 30 | 31 | /* 32 | fun AbstractColumn.get(): C { 33 | throw UnsupportedOperationException() 34 | } 35 | */ 36 | 37 | fun AbstractColumn.update(value: C): Int { 38 | val wrapper = TableSchemaProjectionQueryWrapper.get() 39 | return Session.current().update(wrapper.params.table, arrayOf(wrapper.params.projection.get(0) to value), 40 | wrapper.params.query!!) 41 | } 42 | 43 | fun > AbstractColumn.addAll(values: S): Int { 44 | val wrapper = TableSchemaProjectionQueryWrapper.get() 45 | return Session.current().addAll(wrapper.params.table, 46 | wrapper.params.projection.get(0) 47 | as AbstractColumn, out AbstractSchema, out Any>, values, 48 | wrapper.params.query!!) 49 | } 50 | 51 | fun > AbstractColumn.add(value: C): Int { 52 | val wrapper = TableSchemaProjectionQueryWrapper.get() 53 | val values: Collection = if (wrapper.params.projection.get(0).columnType.list) listOf(value) else setOf(value) 54 | return Session.current().addAll(wrapper.params.table, 55 | wrapper.params.projection.get(0) 56 | as AbstractColumn, out AbstractSchema, out Any>, values, 57 | wrapper.params.query!!) 58 | } 59 | 60 | fun > AbstractColumn.removeAll(values: S): Int { 61 | val wrapper = TableSchemaProjectionQueryWrapper.get() 62 | return Session.current().removeAll(wrapper.params.table, 63 | wrapper.params.projection.get(0) 64 | as AbstractColumn, out AbstractSchema, out Any>, values, 65 | wrapper.params.query!!) 66 | } 67 | 68 | fun AbstractColumn, *, *>.remove(value: C): Int { 69 | val wrapper = TableSchemaProjectionQueryWrapper.get() 70 | val values: Collection = if (wrapper.params.projection.get(0).columnType.list) listOf(value) else setOf(value) 71 | return Session.current().removeAll(wrapper.params.table, 72 | wrapper.params.projection.get(0) 73 | as AbstractColumn, out AbstractSchema, out Any>, values, 74 | wrapper.params.query!!) 75 | } 76 | 77 | fun , *, *>> C.remove(removeOp: C.() -> Query): Int { 78 | val wrapper = TableSchemaProjectionQueryWrapper.get() 79 | val removeOpValue = with (wrapper.params.projection.get(0)) { 80 | removeOp() 81 | } 82 | return Session.current().removeAll(wrapper.params.table, 83 | wrapper.params.projection.get(0) 84 | as AbstractColumn, out AbstractSchema, out Any>, removeOpValue, 85 | wrapper.params.query!!) 86 | } 87 | 88 | fun AbstractColumn.isNull(): Query { 89 | return IsNullQuery(this) 90 | } 91 | 92 | fun AbstractColumn.notNull(): Query { 93 | return IsNotNullQuery(this) 94 | } 95 | 96 | fun AbstractColumn.equal(other: C): Query { 97 | return EqualQuery(this, LiteralExpression(other)) 98 | } 99 | 100 | fun AbstractColumn.notEqual(other: C): Query { 101 | return NotEqualQuery(this, LiteralExpression(other)) 102 | } 103 | 104 | fun AbstractColumn.memberOf(other: Iterable): Query { 105 | return MemberOfQuery(this, LiteralExpression(other)) 106 | } 107 | 108 | fun AbstractColumn.memberOf(other: Array): Query { 109 | return MemberOfQuery(this, LiteralExpression(other)) 110 | } 111 | 112 | // TODO TODO TODO: Expression should be typed 113 | fun AbstractColumn.memberOf(other: Expression>): Query { 114 | return MemberOfQuery(this, LiteralExpression(other)) 115 | } 116 | 117 | fun AbstractColumn.notMemberOf(other: Iterable): Query { 118 | return NotMemberOfQuery(this, LiteralExpression(other)) 119 | } 120 | 121 | fun AbstractColumn.notMemberOf(other: Array): Query { 122 | return NotMemberOfQuery(this, LiteralExpression(other)) 123 | } 124 | 125 | fun AbstractColumn.notMemberOf(other: Expression>): Query { 126 | return NotMemberOfQuery(this, LiteralExpression(other)) 127 | } 128 | 129 | fun AbstractColumn.equal(other: Expression): Query { 130 | return EqualQuery(this, other) 131 | } 132 | 133 | fun AbstractColumn.notEqual(other: Expression): Query { 134 | return NotEqualQuery(this, other) 135 | } 136 | 137 | fun AbstractColumn.gt(other: Expression): Query { 138 | return GreaterQuery(this, other) 139 | } 140 | 141 | fun AbstractColumn.gt(other: Int): Query { 142 | return GreaterQuery(this, LiteralExpression(other)) 143 | } 144 | 145 | fun AbstractColumn.ge(other: Expression): Query { 146 | return GreaterEqualQuery(this, other) 147 | } 148 | 149 | fun AbstractColumn.ge(other: Int): Query { 150 | return GreaterEqualQuery(this, LiteralExpression(other)) 151 | } 152 | 153 | fun AbstractColumn.le(other: Expression): Query { 154 | return LessEqualQuery(this, other) 155 | } 156 | 157 | fun AbstractColumn.le(other: Int): Query { 158 | return LessEqualQuery(this, LiteralExpression(other)) 159 | } 160 | 161 | fun AbstractColumn.lt(other: Expression): Query { 162 | return LessQuery(this, other) 163 | } 164 | 165 | fun AbstractColumn.lt(other: Int): Query { 166 | return LessQuery(this, LiteralExpression(other)) 167 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/AbstractIndex.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | abstract class AbstractIndex(val name: String) -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/AbstractNullableColumn.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | interface AbstractNullableColumn { 4 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/AbstractSchema.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import java.util.ArrayList 4 | import java.util.concurrent.ConcurrentHashMap 5 | import java.util.concurrent.CopyOnWriteArrayList 6 | import org.joda.time.LocalDate 7 | import org.joda.time.LocalTime 8 | import org.joda.time.DateTime 9 | import kotlinx.nosql.query.TextQuery 10 | 11 | abstract class AbstractSchema(val schemaName: String) { 12 | // TODO TODO TODO 13 | val indices = ArrayList() 14 | 15 | // TODO TODO TODO 16 | // val columns = ArrayList>() 17 | 18 | // TODO TODO TODO 19 | companion object { 20 | val threadLocale = ThreadLocal() 21 | 22 | fun current(): T { 23 | return threadLocale.get() as T 24 | } 25 | 26 | fun set(schema: AbstractSchema) { 27 | return threadLocale.set(schema) 28 | } 29 | } 30 | } 31 | 32 | // TODO 33 | fun text(search: String): Query { 34 | return TextQuery(search) 35 | } 36 | 37 | // Extension functions 38 | 39 | fun string(name: String): AbstractColumn = AbstractColumn(name, String::class, ColumnType.STRING) 40 | fun S.string(name: String): AbstractColumn = AbstractColumn(name, String::class, ColumnType.STRING) 41 | 42 | fun boolean(name: String): AbstractColumn = AbstractColumn(name, Boolean::class, ColumnType.BOOLEAN) 43 | fun S.boolean(name: String): AbstractColumn = AbstractColumn(name, Boolean::class, ColumnType.BOOLEAN) 44 | 45 | fun date(name: String): AbstractColumn = AbstractColumn(name, LocalDate::class, ColumnType.DATE) 46 | fun S.date(name: String): AbstractColumn = AbstractColumn(name, LocalDate::class, ColumnType.DATE) 47 | 48 | fun time(name: String): AbstractColumn = AbstractColumn(name, LocalTime::class, ColumnType.TIME) 49 | fun S.time(name: String): AbstractColumn = AbstractColumn(name, LocalTime::class, ColumnType.TIME) 50 | 51 | fun dateTime(name: String): AbstractColumn = AbstractColumn(name, DateTime::class, ColumnType.DATE_TIME) 52 | fun S.dateTime(name: String): AbstractColumn = AbstractColumn(name, DateTime::class, ColumnType.DATE_TIME) 53 | 54 | fun double(name: String): AbstractColumn = AbstractColumn(name, Double::class, ColumnType.DOUBLE) 55 | fun S.double(name: String): AbstractColumn = AbstractColumn(name, Double::class, ColumnType.DOUBLE) 56 | 57 | fun integer(name: String): AbstractColumn = AbstractColumn(name, Int::class, ColumnType.INTEGER) 58 | fun S.integer(name: String): AbstractColumn = AbstractColumn(name, Int::class, ColumnType.INTEGER) 59 | 60 | fun float(name: String): AbstractColumn = AbstractColumn(name, Float::class, ColumnType.FLOAT) 61 | fun S.float(name: String): AbstractColumn = AbstractColumn(name, Float::class, ColumnType.FLOAT) 62 | 63 | fun long(name: String): AbstractColumn = AbstractColumn(name, Long::class, ColumnType.LONG) 64 | fun S.long(name: String): AbstractColumn = AbstractColumn(name, Long::class, ColumnType.LONG) 65 | 66 | fun short(name: String): AbstractColumn = AbstractColumn(name, Short::class, ColumnType.SHORT) 67 | fun S.short(name: String): AbstractColumn = AbstractColumn(name, Short::class, ColumnType.SHORT) 68 | 69 | fun byte(name: String): AbstractColumn = AbstractColumn(name, Byte::class, ColumnType.BYTE) 70 | fun S.byte(name: String): AbstractColumn = AbstractColumn(name, Byte::class, ColumnType.BYTE) 71 | 72 | fun nullableString(name: String): NullableColumn = NullableColumn(name, String::class, ColumnType.STRING) 73 | fun S.nullableString(name: String): NullableColumn = NullableColumn(name, String::class, ColumnType.STRING) 74 | 75 | fun nullableInteger(name: String): NullableColumn = NullableColumn(name, Int::class, ColumnType.INTEGER) 76 | fun S.nullableInteger(name: String): NullableColumn = NullableColumn(name, Int::class, ColumnType.INTEGER) 77 | 78 | fun nullableBoolean(name: String): NullableColumn = NullableColumn(name, Boolean::class, ColumnType.BOOLEAN) 79 | fun S.nullableBoolean(name: String): NullableColumn = NullableColumn(name, Boolean::class, ColumnType.BOOLEAN) 80 | 81 | fun nullableDate(name: String): NullableColumn = NullableColumn(name, LocalDate::class, ColumnType.DATE) 82 | fun S.nullableDate(name: String): NullableColumn = NullableColumn(name, LocalDate::class, ColumnType.DATE) 83 | 84 | fun nullableTime(name: String): NullableColumn = NullableColumn(name, LocalTime::class, ColumnType.TIME) 85 | fun S.nullableTime(name: String): NullableColumn = NullableColumn(name, LocalTime::class, ColumnType.TIME) 86 | 87 | fun nullableDateTime(name: String): NullableColumn = NullableColumn(name, DateTime::class, ColumnType.DATE_TIME) 88 | fun S.nullableDateTime(name: String): NullableColumn = NullableColumn(name, DateTime::class, ColumnType.DATE_TIME) 89 | 90 | fun nullableDouble(name: String): NullableColumn = NullableColumn(name, Double::class, ColumnType.DOUBLE) 91 | fun S.nullableDouble(name: String): NullableColumn = NullableColumn(name, Double::class, ColumnType.DOUBLE) 92 | 93 | fun nullableFloat(name: String): NullableColumn = NullableColumn(name, Float::class, ColumnType.FLOAT) 94 | fun S.nullableFloat(name: String): NullableColumn = NullableColumn(name, Float::class, ColumnType.FLOAT) 95 | 96 | fun nullableLong(name: String): NullableColumn = NullableColumn(name, Long::class, ColumnType.LONG) 97 | fun S.nullableLong(name: String): NullableColumn = NullableColumn(name, Long::class, ColumnType.LONG) 98 | 99 | fun nullableShort(name: String): NullableColumn = NullableColumn(name, Short::class, ColumnType.SHORT) 100 | fun S.nullableShort(name: String): NullableColumn = NullableColumn(name, Short::class, ColumnType.SHORT) 101 | 102 | fun nullableByte(name: String): NullableColumn = NullableColumn(name, Byte::class, ColumnType.BYTE) 103 | fun S.nullableByte(name: String): NullableColumn = NullableColumn(name, Byte::class, ColumnType.BYTE) 104 | 105 | fun setOfString(name: String): AbstractColumn, S, String> = AbstractColumn, S, String>(name, String::class, ColumnType.STRING_SET) 106 | fun S.setOfString(name: String): AbstractColumn, S, String> = AbstractColumn, S, String>(name, String::class, ColumnType.STRING_SET) 107 | 108 | fun setOfInteger(name: String): AbstractColumn, S, Int> = AbstractColumn, S, Int>(name, Int::class, ColumnType.INTEGER_SET) 109 | fun S.setOfInteger(name: String): AbstractColumn, S, Int> = AbstractColumn, S, Int>(name, Int::class, ColumnType.INTEGER_SET) 110 | 111 | fun listOfString(name: String): AbstractColumn, S, String> = AbstractColumn, S, String>(name, String::class, ColumnType.STRING_LIST) 112 | fun S.listOfString(name: String): AbstractColumn, S, String> = AbstractColumn, S, String>(name, String::class, ColumnType.STRING_LIST) 113 | 114 | fun listOfInteger(name: String): AbstractColumn, S, Int> = AbstractColumn, S, Int>(name, Int::class, ColumnType.INTEGER_LIST) 115 | fun S.listOfInteger(name: String): AbstractColumn, S, Int> = AbstractColumn, S, Int>(name, Int::class, ColumnType.INTEGER_LIST) 116 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/AbstractTableSchema.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | abstract class AbstractTableSchema(name: String): AbstractSchema(name) { 4 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/AndQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class AndQuery(val expr1: kotlinx.nosql.Query, val expr2: kotlinx.nosql.Query): Query() { 4 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Column.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlin.reflect.KClass 4 | 5 | abstract class Column(name: String, valueClass: KClass, columnType: ColumnType = ColumnType.CUSTOM_CLASS) : AbstractColumn(name, valueClass, columnType) { 6 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnDecuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class ColumnDecuple(val a: AbstractColumn, val b: AbstractColumn, 4 | val c: AbstractColumn, val d: AbstractColumn, 5 | val e: AbstractColumn, val f: AbstractColumn, 6 | val g: AbstractColumn, val h: AbstractColumn, 7 | val i: AbstractColumn, val j: AbstractColumn): ColumnQueryWrapper>() { 8 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnNonuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class ColumnNonuple(val a: AbstractColumn, val b: AbstractColumn, 4 | val c: AbstractColumn, val d: AbstractColumn, 5 | val e: AbstractColumn, val f: AbstractColumn, 6 | val g: AbstractColumn, val h: AbstractColumn, 7 | val j: AbstractColumn): ColumnQueryWrapper>() { 8 | operator fun plus(k: AbstractColumn): ColumnDecuple { 9 | return ColumnDecuple(a, b, c, d, e, f, g, h, j, k) 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnOctuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class ColumnOctuple(val a: AbstractColumn, val b: AbstractColumn, 4 | val c: AbstractColumn, val d: AbstractColumn, 5 | val e: AbstractColumn, val f: AbstractColumn, 6 | val g: AbstractColumn, val h: AbstractColumn): ColumnQueryWrapper>() { 7 | operator fun plus(j: AbstractColumn): ColumnNonuple { 8 | return ColumnNonuple(a, b, c, d, e, f, g, h, j) 9 | } 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnPair.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class ColumnPair(val a: AbstractColumn, val b: AbstractColumn): ColumnQueryWrapper>() { 4 | operator fun plus(c: AbstractColumn): ColumnTriple { 5 | return ColumnTriple(a, b, c) 6 | } 7 | } 8 | 9 | /* 10 | fun ColumnPair.get(): Pair { 11 | throw UnsupportedOperationException() 12 | }*/ 13 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnQuadruple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class ColumnQuadruple(val a: AbstractColumn, val b: AbstractColumn, val c: AbstractColumn, val d: AbstractColumn): ColumnQueryWrapper>() { 4 | operator fun plus(e: AbstractColumn): ColumnQuintuple { 5 | return ColumnQuintuple(a, b, c, d, e) 6 | } 7 | 8 | fun insert(statement: () -> Quadruple) { 9 | val tt = statement() 10 | Session.current().insert(arrayOf(Pair(a, tt.component1()), Pair(b, tt.component2()), Pair(c, tt.component3()), Pair(d, tt.component4()))) 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnQueryWrapper.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | abstract class ColumnQueryWrapper : Iterable { 4 | override fun iterator(): Iterator { 5 | val wrapper = TableSchemaProjectionQueryWrapper.get() 6 | return wrapper.iterator() as Iterator 7 | } 8 | } 9 | 10 | fun ColumnQueryWrapper>.update(a: A, b: B): Int { 11 | val wrapper = TableSchemaProjectionQueryWrapper.get() 12 | return Session.current().update(wrapper.params.table, arrayOf(wrapper.params.projection.get(0) to a, 13 | wrapper.params.projection.get(1) to b), 14 | wrapper.params.query!!) 15 | } 16 | 17 | fun ColumnQueryWrapper>.update(a: A, b: B, c: C): Int { 18 | val wrapper = TableSchemaProjectionQueryWrapper.get() 19 | return Session.current().update(wrapper.params.table, arrayOf(wrapper.params.projection.get(0) to a, 20 | wrapper.params.projection.get(1) to b, 21 | wrapper.params.projection.get(2) to c), 22 | wrapper.params.query!!) 23 | } 24 | 25 | fun ColumnQueryWrapper>.update(a: A, b: B, c: C, d: D): Int { 26 | val wrapper = TableSchemaProjectionQueryWrapper.get() 27 | return Session.current().update(wrapper.params.table, arrayOf(wrapper.params.projection.get(0) to a, 28 | wrapper.params.projection.get(1) to b, 29 | wrapper.params.projection.get(2) to c, 30 | wrapper.params.projection.get(3) to d), 31 | wrapper.params.query!!) 32 | } 33 | 34 | fun ColumnQueryWrapper>.update(a: A, b: B, c: C, d: D, e: E): Int { 35 | val wrapper = TableSchemaProjectionQueryWrapper.get() 36 | return Session.current().update(wrapper.params.table, arrayOf(wrapper.params.projection.get(0) to a, 37 | wrapper.params.projection.get(1) to b, 38 | wrapper.params.projection.get(2) to c, 39 | wrapper.params.projection.get(3) to d, 40 | wrapper.params.projection.get(4) to e), 41 | wrapper.params.query!!) 42 | } 43 | 44 | fun ColumnQueryWrapper>.update(a: A, b: B, c: C, d: D, e: E, f: F): Int { 45 | val wrapper = TableSchemaProjectionQueryWrapper.get() 46 | return Session.current().update(wrapper.params.table, arrayOf(wrapper.params.projection.get(0) to a, 47 | wrapper.params.projection.get(1) to b, 48 | wrapper.params.projection.get(2) to c, 49 | wrapper.params.projection.get(3) to d, 50 | wrapper.params.projection.get(4) to e, 51 | wrapper.params.projection.get(5) to f), 52 | wrapper.params.query!!) 53 | } 54 | 55 | fun ColumnQueryWrapper>.update(a: A, b: B, c: C, d: D, e: E, f: F, g: G): Int { 56 | val wrapper = TableSchemaProjectionQueryWrapper.get() 57 | return Session.current().update(wrapper.params.table, arrayOf(wrapper.params.projection.get(0) to a, 58 | wrapper.params.projection.get(1) to b, 59 | wrapper.params.projection.get(2) to c, 60 | wrapper.params.projection.get(3) to d, 61 | wrapper.params.projection.get(4) to e, 62 | wrapper.params.projection.get(5) to f, 63 | wrapper.params.projection.get(6) to g), 64 | wrapper.params.query!!) 65 | } 66 | 67 | fun ColumnQueryWrapper>.update(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H): Int { 68 | val wrapper = TableSchemaProjectionQueryWrapper.get() 69 | return Session.current().update(wrapper.params.table, arrayOf(wrapper.params.projection.get(0) to a, 70 | wrapper.params.projection.get(1) to b, 71 | wrapper.params.projection.get(2) to c, 72 | wrapper.params.projection.get(3) to d, 73 | wrapper.params.projection.get(4) to e, 74 | wrapper.params.projection.get(5) to f, 75 | wrapper.params.projection.get(6) to g, 76 | wrapper.params.projection.get(7) to h), 77 | wrapper.params.query!!) 78 | } 79 | 80 | fun ColumnQueryWrapper>.update(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, j: J): Int { 81 | val wrapper = TableSchemaProjectionQueryWrapper.get() 82 | return Session.current().update(wrapper.params.table, arrayOf(wrapper.params.projection.get(0) to a, 83 | wrapper.params.projection.get(1) to b, 84 | wrapper.params.projection.get(2) to c, 85 | wrapper.params.projection.get(3) to d, 86 | wrapper.params.projection.get(4) to e, 87 | wrapper.params.projection.get(5) to f, 88 | wrapper.params.projection.get(6) to g, 89 | wrapper.params.projection.get(7) to h, 90 | wrapper.params.projection.get(8) to j), 91 | wrapper.params.query!!) 92 | } 93 | 94 | fun ColumnQueryWrapper>.update(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, j: J, k: K): Int { 95 | val wrapper = TableSchemaProjectionQueryWrapper.get() 96 | return Session.current().update(wrapper.params.table, arrayOf(wrapper.params.projection.get(0) to a, 97 | wrapper.params.projection.get(1) to b, 98 | wrapper.params.projection.get(2) to c, 99 | wrapper.params.projection.get(3) to d, 100 | wrapper.params.projection.get(4) to e, 101 | wrapper.params.projection.get(5) to f, 102 | wrapper.params.projection.get(6) to g, 103 | wrapper.params.projection.get(7) to h, 104 | wrapper.params.projection.get(8) to j, 105 | wrapper.params.projection.get(9) to k), 106 | wrapper.params.query!!) 107 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnQuintuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class ColumnQuintuple(val a: AbstractColumn, val b: AbstractColumn, 4 | val c: AbstractColumn, val d: AbstractColumn, 5 | val e: AbstractColumn): ColumnQueryWrapper>() { 6 | operator fun plus(f: AbstractColumn): ColumnSextuple { 7 | return ColumnSextuple(a, b, c, d, e, f) 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnSeptuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class ColumnSeptuple(val a: AbstractColumn, val b: AbstractColumn, 4 | val c: AbstractColumn, val d: AbstractColumn, 5 | val e: AbstractColumn, val f: AbstractColumn, 6 | val g: AbstractColumn): ColumnQueryWrapper>() { 7 | operator fun plus(h: AbstractColumn): ColumnOctuple { 8 | return ColumnOctuple(a, b, c, d, e, f, g, h) 9 | } 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnSextuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class ColumnSextuple(val a: AbstractColumn, val b: AbstractColumn, 4 | val c: AbstractColumn, val d: AbstractColumn, 5 | val e: AbstractColumn, val f: AbstractColumn): ColumnQueryWrapper>() { 6 | operator fun plus(g: AbstractColumn): ColumnSeptuple { 7 | return ColumnSeptuple(a, b, c, d, e, f, g) 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnTriple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class ColumnTriple(val a: AbstractColumn, val b: AbstractColumn, val c: AbstractColumn): ColumnQueryWrapper>() { 4 | operator fun plus(d: AbstractColumn): ColumnQuadruple { 5 | return ColumnQuadruple(a, b, c, d) 6 | } 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ColumnType.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | enum class ColumnType(val primitive: Boolean = false, 4 | val iterable: Boolean = false, 5 | val list: Boolean = false, 6 | val set: Boolean = false, 7 | val custom: Boolean = false, 8 | val id: Boolean = false) { 9 | INTEGER(primitive = true), 10 | PRIMARY_ID(primitive = true, id = true), 11 | FOREIGN_ID(primitive = true, id = true), 12 | STRING(primitive = true), 13 | BOOLEAN(primitive = true), 14 | DATE(primitive = true), 15 | TIME(primitive = true), 16 | DATE_TIME(primitive = true), 17 | DOUBLE(primitive = true), 18 | FLOAT(primitive = true), 19 | LONG(primitive = true), 20 | SHORT(primitive = true), 21 | BYTE(primitive = true), 22 | INTEGER_SET(iterable = true, set = true), 23 | ID_SET(iterable = true, set = true, id = true), 24 | ID_LIST(iterable = true, list = true, id = true), 25 | STRING_SET(iterable = true, set = true), 26 | INTEGER_LIST(iterable = true, list = true), 27 | STRING_LIST(iterable = true, list = true), 28 | CUSTOM_CLASS(custom = true), 29 | CUSTOM_CLASS_LIST(iterable = true, custom = true, list = true), 30 | CUSTOM_CLASS_SET(iterable = true, custom = true, set = true) 31 | } 32 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Database.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import java.util.concurrent.ConcurrentHashMap 4 | import kotlinx.nosql.util.getAllFields 5 | import kotlinx.nosql.util.isColumn 6 | import kotlinx.nosql.util.asColumn 7 | import kotlin.text.isNotEmpty 8 | 9 | abstract class Database(val schemas: Array, val action: SchemaGenerationAction) { 10 | abstract fun withSession(statement: S.() -> R): R 11 | 12 | fun initialize() { 13 | for (schema in schemas) { 14 | buildFullColumnNames(schema) 15 | when (action) { 16 | // TODO: implement validation 17 | is Create, is CreateDrop -> { 18 | withSession { 19 | schema.drop() 20 | schema.create() 21 | if (this is IndexOperations) 22 | for (index in schema.indices) 23 | createIndex(schema, index) 24 | } 25 | } 26 | is Update -> { 27 | withSession { 28 | if (this is IndexOperations) 29 | for (index in schema.indices) 30 | createIndex(schema, index) 31 | } 32 | } 33 | // TODO: implement drop after exit 34 | } 35 | } 36 | withSession { 37 | if (action is Create) { 38 | action.onCreate(this) 39 | } else if (action is CreateDrop) { 40 | action.onCreate(this) 41 | } 42 | } 43 | } 44 | 45 | private fun buildFullColumnNames(root: AbstractSchema, path: String = "", schema: Any = root) { 46 | val fields = getAllFields(schema.javaClass) 47 | for (field in fields) { 48 | if (field.isColumn) { 49 | val column = field.asColumn(schema) 50 | column._schema = root 51 | val columnFullName = path + (if (path.isNotEmpty()) "." else "") + column.name 52 | fullColumnNames.put(column, columnFullName) 53 | buildFullColumnNames(root, columnFullName, column) 54 | } 55 | } 56 | } 57 | 58 | companion object { 59 | val fullColumnNames = ConcurrentHashMap, String>() 60 | } 61 | } 62 | 63 | val AbstractColumn<*, *, *>.fullName: String 64 | get() { 65 | return Database.fullColumnNames.get(this)!! 66 | } 67 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Decuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class Decuple(val a1: A1, val a2: A2, val a3: A3, val a4: A4, val a5: A5, val a6: A6, val a7: A7, val a8: A8, val a9: A9, val a10: A10) { 4 | operator public fun component1(): A1 = a1 5 | operator public fun component2(): A2 = a2 6 | operator public fun component3(): A3 = a3 7 | operator public fun component4(): A4 = a4 8 | operator public fun component5(): A5 = a5 9 | operator public fun component6(): A6 = a6 10 | operator public fun component7(): A7 = a7 11 | operator public fun component8(): A8 = a8 12 | operator public fun component9(): A9 = a9 13 | operator public fun component10(): A10 = a10 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Discriminator.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class Discriminator>(val column: AbstractColumn, val value: D) { 4 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/DocumentSchema.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import java.util.concurrent.CopyOnWriteArrayList 4 | import java.util.concurrent.ConcurrentHashMap 5 | import kotlin.reflect.KClass 6 | 7 | abstract class DocumentSchema(name: String, val valueClass: KClass, primaryKey: AbstractColumn, I>, val discriminator: Discriminator>? = null) : TableSchema(name, primaryKey) { 9 | init { 10 | if (discriminator != null) { 11 | val emptyDiscriminators = CopyOnWriteArrayList>() 12 | val discriminators = tableDiscriminators.putIfAbsent(name, emptyDiscriminators) 13 | if (discriminators != null) 14 | discriminators.add(discriminator) 15 | else 16 | emptyDiscriminators.add(discriminator) 17 | // TODO TODO TODO 18 | discriminatorClasses.put(discriminator, this.valueClass) 19 | discriminatorSchemaClasses.put(discriminator, this.javaClass) 20 | discriminatorSchemas.put(discriminator, this) 21 | } 22 | } 23 | 24 | companion object { 25 | val tableDiscriminators = ConcurrentHashMap>>() 26 | val discriminatorClasses = ConcurrentHashMap, KClass<*>>() 27 | val discriminatorSchemaClasses = ConcurrentHashMap, Class<*>>() 28 | val discriminatorSchemas = ConcurrentHashMap, AbstractSchema>() 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/DocumentSchemaIdQueryWrapper.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import java.util.ArrayList 4 | import kotlin.collections.single 5 | 6 | class DocumentSchemaIdQueryWrapper, P: Any, C: Any>(val schema: T, val id: Id): DocumentSchemaQueryWrapper(DocumentSchemaQueryParams(schema, 7 | schema.id.equal(id)) 8 | ) { 9 | fun get(): C { 10 | return single() 11 | } 12 | 13 | override fun iterator(): Iterator { 14 | val list = ArrayList() 15 | val value = with (Session.current()) { schema.get(id) } 16 | if (value != null) { 17 | list.add(value) 18 | } 19 | return list.iterator() 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/DocumentSchemaOperations.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlinx.nosql.query.NoQuery 4 | 5 | interface DocumentSchemaOperations { 6 | fun , P: Any, V: Any> T.insert(v: V): Id 7 | fun , P: Any, C: Any> T.find(query: T.() -> Query = { NoQuery }): DocumentSchemaQueryWrapper 8 | // TODO: Implement find(id) -> Wrapper 9 | /*fun , P, C> T.find(id: Id): C? { 10 | val w = find { this.id.equal(id) } 11 | return if (w.count() > 0) w.single() else null 12 | }*/ 13 | 14 | fun , P: Any, C: Any> find(params: DocumentSchemaQueryParams): Iterator 15 | } 16 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/DocumentSchemaQueryParams.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class DocumentSchemaQueryParams, P: Any, C: Any>(val schema: T, val query: Query? = null, 4 | var skip: Int? = null, var take: Int? = null, var subscribed: Boolean = false) 5 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/DocumentSchemaQueryWrapper.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlin.collections.listOf 4 | 5 | open class DocumentSchemaQueryWrapper, P: Any, C: Any>(val params: kotlinx.nosql.DocumentSchemaQueryParams): Iterable { 6 | override fun iterator(): Iterator { 7 | return Session.current().find(params) 8 | } 9 | 10 | fun skip(num: Int): kotlinx.nosql.DocumentSchemaQueryWrapper { 11 | params.skip = num 12 | return this 13 | } 14 | 15 | fun take(num: Int): DocumentSchemaQueryWrapper { 16 | params.take = num 17 | return this 18 | } 19 | 20 | fun remove(): Int { 21 | return Session.current().delete(params.schema, params.query!!) 22 | } 23 | 24 | fun projection(x: T.() -> X): X { 25 | val xx = params.schema.x() 26 | val projectionParams = kotlinx.nosql.TableSchemaProjectionQueryParams, Any, Any>(params.schema as TableSchema, 27 | when (xx) { 28 | is AbstractColumn<*, *, *> -> listOf(xx) as List> 29 | is ColumnPair<*, *, *> -> listOf(xx.a, xx.b) 30 | is ColumnTriple<*, *, *, *> -> listOf(xx.a, xx.b, xx.c) 31 | is kotlinx.nosql.ColumnQuadruple<*, *, *, *, *> -> listOf(xx.a, xx.b, xx.c, xx.d) 32 | is ColumnQuintuple<*, *, *, *, *, *> -> listOf(xx.a, xx.b, xx.c, xx.d, xx.e) 33 | is ColumnSextuple<*, *, *, *, *, *, *> -> listOf(xx.a, xx.b, xx.c, xx.d, xx.e, xx.f) 34 | is ColumnSeptuple<*, *, *, *, *, *, *, *> -> listOf(xx.a, xx.b, xx.c, xx.d, xx.e, xx.f, xx.g) 35 | is ColumnOctuple<*, *, *, *, *, *, *, *, *> -> listOf(xx.a, xx.b, xx.c, xx.d, xx.e, xx.f, xx.g, xx.h) 36 | is ColumnNonuple<*, *, *, *, *, *, *, *, *, *> -> listOf(xx.a, xx.b, xx.c, xx.d, xx.e, xx.f, xx.g, xx.h, xx.j) 37 | is kotlinx.nosql.ColumnDecuple<*, *, *, *, *, *, *, *, *, *, *> -> listOf(xx.a, xx.b, xx.c, xx.d, xx.e, xx.f, xx.g, xx.h, xx.i, xx.j) 38 | else -> throw UnsupportedOperationException() 39 | }, params.query) 40 | TableSchemaProjectionQueryWrapper.set(TableSchemaProjectionQueryWrapper(projectionParams)) 41 | return params.schema.x() 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Expression.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | interface Expression { 4 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Id.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class Id>(val value: I) { 4 | override fun toString() = value.toString() 5 | 6 | override fun equals(other: Any?): Boolean { 7 | return if (other is Id<*, *>) value.equals(other.value) else false 8 | } 9 | override fun hashCode(): Int { 10 | return value.hashCode() 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/IdListColumn.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlin.reflect.KClass 4 | 5 | open class IdListColumn, R: TableSchema

, P: Any> (name: String, val refSchema: R) : AbstractColumn>, S, Id>(name, Id::class as KClass>, ColumnType.ID_LIST) { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/IdSetColumn.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlin.reflect.KClass 4 | 5 | open class IdSetColumn, R: TableSchema

, P: Any> (name: String, val refSchema: R) : AbstractColumn>, S, Id>(name, Id::class as KClass>, ColumnType.ID_SET) { 6 | } 7 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/IndexOperations.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | interface IndexOperations { 4 | fun createIndex(schema: AbstractSchema, index: AbstractIndex) 5 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/KeyValueDocumentSchemaOperations.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlinx.nosql.query.NoQuery 4 | 5 | interface KeyValueDocumentSchemaOperations { 6 | fun , P: Any, V: Any> T.insert(v: V): Id 7 | operator fun , P: Any, C: Any> T.get(id: Id): C? 8 | fun , P: Any, C: Any> T.find(id: Id): DocumentSchemaIdQueryWrapper { 9 | return DocumentSchemaIdQueryWrapper(this, id) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/KeyValueSchema.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | abstract class KeyValueSchema(name: String): AbstractSchema(name) { 4 | 5 | } 6 | 7 | fun T.projection(x: T.() -> X): X { 8 | return x() 9 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/KeyValueSchemaOperations.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | interface KeyValueSchemaOperations { 4 | operator fun T.get(c: T.() -> AbstractColumn): C? 5 | operator fun T.set(c: () -> AbstractColumn, v: C) 6 | 7 | fun AbstractColumn.incr(value: S = 1 as S): X { 8 | val value = Session.current().incr(schema, this, value) 9 | if (columnType.id) { 10 | return Id>(value) as X 11 | } else { 12 | return value as X 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/ListColumn.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlin.reflect.KClass 4 | 5 | open class ListColumn (name: String, valueClass: KClass) : AbstractColumn, S, C>(name, valueClass, ColumnType.CUSTOM_CLASS_LIST) { 6 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/LiteralExpression.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class LiteralExpression(val value: Any?): Expression { 4 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Nonuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class Nonuple(val a1: A1, val a2: A2, val a3: A3, val a4: A4, val a5: A5, val a6: A6, val a7: A7, val a8: A8, val a9: A9) { 4 | operator public fun component1(): A1 = a1 5 | operator public fun component2(): A2 = a2 6 | operator public fun component3(): A3 = a3 7 | operator public fun component4(): A4 = a4 8 | operator public fun component5(): A5 = a5 9 | operator public fun component6(): A6 = a6 10 | operator public fun component7(): A7 = a7 11 | operator public fun component8(): A8 = a8 12 | operator public fun component9(): A9 = a9 13 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/NotEqualQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class NotEqualQuery(val expr1: Expression<*>, val expr2: Expression<*>): Query() { 4 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/NotMemberOfQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class NotMemberOfQuery(val expr1: Expression<*>, val expr2: Expression<*>): Query() { 4 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/NullableColumn.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlin.reflect.KClass 4 | 5 | open class NullableColumn (name: String, valueClass: KClass, 6 | columnType: ColumnType) : AbstractColumn(name, valueClass, columnType), AbstractNullableColumn { 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/NullableIdColumn.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlin.reflect.KClass 4 | 5 | open class NullableIdColumn, R: TableSchema> (name: String, valueClass: KClass, 6 | columnType: ColumnType) : AbstractColumn?, S, I>(name, valueClass, columnType), AbstractNullableColumn { 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Octuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class Octuple(val a1: A1, val a2: A2, val a3: A3, val a4: A4, val a5: A5, val a6: A6, val a7: A7, val a8: A8) { 4 | operator public fun component1(): A1 = a1 5 | operator public fun component2(): A2 = a2 6 | operator public fun component3(): A3 = a3 7 | operator public fun component4(): A4 = a4 8 | operator public fun component5(): A5 = a5 9 | operator public fun component6(): A6 = a6 10 | operator public fun component7(): A7 = a7 11 | operator public fun component8(): A8 = a8 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/PrimaryKey.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | open class PrimaryKey(val name: String, val javaClass: Class, val columnType: ColumnType) { 4 | companion object { 5 | fun string(name: String) = PrimaryKey(name, String::class.java, ColumnType.STRING) 6 | fun integer(name: String) = PrimaryKey(name, Int::class.java, ColumnType.INTEGER) 7 | } 8 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Quadruple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class Quadruple(val a1: A1, val a2: A2, val a3: A3, val a4: A4) { 4 | operator public fun component1(): A1 = a1 5 | operator public fun component2(): A2 = a2 6 | operator public fun component3(): A3 = a3 7 | operator public fun component4(): A4 = a4 8 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Query.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlinx.nosql.query.OrQuery 4 | 5 | abstract class Query() { 6 | infix fun and(op: Query): Query { 7 | return AndQuery(this, op) 8 | } 9 | 10 | infix fun or(op: Query): Query { 11 | return OrQuery(this, op) 12 | } 13 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Quintuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class Quintuple(val a1: A1, val a2: A2, val a3: A3, val a4: A4, val a5: A5) { 4 | operator public fun component1(): A1 = a1 5 | operator public fun component2(): A2 = a2 6 | operator public fun component3(): A3 = a3 7 | operator public fun component4(): A4 = a4 8 | operator public fun component5(): A5 = a5 9 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/SchemaGenerationAction.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | abstract class SchemaGenerationAction() { 4 | } 5 | 6 | class Create(val onCreate: S.() -> Unit = { }) : SchemaGenerationAction() 7 | 8 | class CreateDrop(val onCreate: S.() -> Unit = { }, 9 | onDrop: S.() -> Unit = { }) : SchemaGenerationAction() 10 | 11 | class Update() : SchemaGenerationAction() 12 | 13 | class Validate() : SchemaGenerationAction() 14 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Septuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class Septuple(val a1: A1, val a2: A2, val a3: A3, val a4: A4, val a5: A5, val a6: A6, val a7: A7) { 4 | operator public fun component1(): A1 = a1 5 | operator public fun component2(): A2 = a2 6 | operator public fun component3(): A3 = a3 7 | operator public fun component4(): A4 = a4 8 | operator public fun component5(): A5 = a5 9 | operator public fun component6(): A6 = a6 10 | operator public fun component7(): A7 = a7 11 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Session.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import java.util.ArrayList 4 | 5 | interface Session { 6 | fun T.create() 7 | 8 | fun T.drop() 9 | 10 | // TODO: Refactor 11 | fun insert(columns: Array, *>>) 12 | 13 | // TODO: Refactor 14 | fun delete(table: T, op: Query): Int 15 | 16 | fun update(schema: AbstractSchema, columnValues: Array, *>>, op: Query): Int 17 | 18 | fun addAll(schema: AbstractSchema, column: AbstractColumn, *, *>, values: Collection, op: Query): Int 19 | fun incr(schema: KeyValueSchema, column: AbstractColumn<*, *, T>, value: T): T 20 | //internal fun incr(schema: AbstractSchema, column: AbstractColumn<*, *, T>, value: T, op: Query): T 21 | 22 | fun removeAll(schema: AbstractSchema, column: AbstractColumn, *, *>, values: Collection, op: Query): Int 23 | 24 | fun removeAll(schema: AbstractSchema, column: AbstractColumn, *, *>, removeOp: Query, op: Query): Int 25 | 26 | companion object { 27 | val threadLocale = ThreadLocal() 28 | 29 | fun current(): T { 30 | return threadLocale.get()!! as T 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/SetColumn.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | import kotlin.reflect.KClass 4 | 5 | open class SetColumn (name: String, valueClass: KClass) : AbstractColumn, S, C>(name, valueClass, ColumnType.CUSTOM_CLASS_SET) { 6 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/Sextuple.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class Sextuple(val a1: A1, val a2: A2, val a3: A3, val a4: A4, val a5: A5, val a6: A6) { 4 | operator public fun component1(): A1 = a1 5 | operator public fun component2(): A2 = a2 6 | operator public fun component3(): A3 = a3 7 | operator public fun component4(): A4 = a4 8 | operator public fun component5(): A5 = a5 9 | operator public fun component6(): A6 = a6 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/TableSchema.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | abstract class TableSchema(tableName: String, primaryKey: AbstractColumn, I>): AbstractTableSchema(tableName) { 4 | val pk = AbstractColumn>, TableSchema, I>(primaryKey.name, primaryKey.valueClass, ColumnType.PRIMARY_ID) 5 | } 6 | 7 | // Extension functions 8 | 9 | val > T.id: AbstractColumn, T, C> 10 | get () { 11 | return pk as AbstractColumn, T, C> 12 | } 13 | 14 | fun , P: Any> id(name: String, refSchema: R): AbstractColumn, S, P> = AbstractColumn(name, refSchema.id.valueClass, ColumnType.FOREIGN_ID) 15 | fun , P: Any> S.id(name: String, refSchema: R): AbstractColumn, S, P> = AbstractColumn(name, refSchema.id.valueClass, ColumnType.FOREIGN_ID) 16 | 17 | fun , R: TableSchema

, P: Any> listOfId(name: String, refSchema: R): IdListColumn = IdListColumn(name, refSchema) 18 | fun , R: TableSchema

, P: Any> S.listOfId(name: String, refSchema: R): IdListColumn = IdListColumn(name, refSchema) 19 | 20 | fun , R: TableSchema

, P: Any> setOfId(name: String, refSchema: R): IdSetColumn = IdSetColumn(name, refSchema) 21 | fun , R: TableSchema

, P: Any> S.setOfId(name: String, refSchema: R): IdSetColumn = IdSetColumn(name, refSchema) 22 | 23 | fun , R: TableSchema

, P: Any> nullableId(name: String, refSchema: R): NullableIdColumn = NullableIdColumn(name, refSchema.id.valueClass, ColumnType.FOREIGN_ID) 24 | fun , R: TableSchema

, P: Any> S.nullableId(name: String, refSchema: R): NullableIdColumn = NullableIdColumn(name, refSchema.id.valueClass, ColumnType.FOREIGN_ID) 25 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/TableSchemaOperations.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | interface TableSchemaOperations { 4 | fun , P: Any, V: Any> find(params: TableSchemaProjectionQueryParams): Iterator 5 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/TableSchemaProjectionQueryParams.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class TableSchemaProjectionQueryParams, P: Any, V>(val table: T, val projection: List>, val query: Query? = null, 4 | var skip: Int? = null, var take: Int? = null) { 5 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/TableSchemaProjectionQueryWrapper.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql 2 | 3 | class TableSchemaProjectionQueryWrapper, P: Any, V: Any>(val params: TableSchemaProjectionQueryParams): Iterable { 4 | override fun iterator(): Iterator { 5 | return Session.current().find(params) 6 | } 7 | 8 | fun skip(num: Int): TableSchemaProjectionQueryWrapper { 9 | params.skip = num 10 | return this 11 | } 12 | 13 | fun take(num: Int): TableSchemaProjectionQueryWrapper { 14 | params.take = num 15 | return this 16 | } 17 | 18 | companion object { 19 | val threadLocal = ThreadLocal, *, *>>() 20 | 21 | fun get(): TableSchemaProjectionQueryWrapper, *, *> { 22 | return threadLocal.get()!! as TableSchemaProjectionQueryWrapper, *, *> 23 | } 24 | 25 | fun set(value: TableSchemaProjectionQueryWrapper, *, *>) { 26 | threadLocal.set(value) 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/EqualQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.Expression 4 | import kotlinx.nosql.Query 5 | 6 | class EqualQuery(val expr1: Expression<*>, val expr2: Expression<*>): Query() { 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/GreateQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.Query 4 | import kotlinx.nosql.Expression 5 | 6 | class GreaterQuery(val expr1: Expression<*>, val expr2: Expression<*>): Query() { 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/GreaterEqualQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.Expression 4 | import kotlinx.nosql.Query 5 | 6 | class GreaterEqualQuery(val expr1: Expression<*>, val expr2: Expression<*>): Query() { 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/IsNotNullQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.AbstractColumn 4 | import kotlinx.nosql.Query 5 | 6 | class IsNotNullQuery(val column: AbstractColumn<*, *, *>): Query() { 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/IsNullQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.AbstractColumn 4 | import kotlinx.nosql.Query 5 | 6 | class IsNullQuery(val column: AbstractColumn<*, *, *>): Query() { 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/LessEqualQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.Expression 4 | import kotlinx.nosql.Query 5 | 6 | class LessEqualQuery(val expr1: Expression<*>, val expr2: Expression<*>): Query() { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/LessQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.Expression 4 | import kotlinx.nosql.Query 5 | 6 | class LessQuery(val expr1: Expression<*>, val expr2: Expression<*>): Query() { 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/MatchesQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.Expression 4 | import kotlinx.nosql.Query 5 | 6 | class MatchesQuery(val expr1: Expression<*>, val expr2: Expression<*>): Query() { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/MemberOfQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.Query 4 | import kotlinx.nosql.Expression 5 | 6 | class MemberOfQuery(val expr1: Expression<*>, val expr2: Expression<*>): Query() { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/NoQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.Query 4 | 5 | object NoQuery : Query() { 6 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/OrQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.Query 4 | 5 | class OrQuery(val expr1: Query, val expr2: Query): Query() { 6 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/query/TextQuery.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.query 2 | 3 | import kotlinx.nosql.Query 4 | 5 | class TextQuery(val search: String): Query() { 6 | } -------------------------------------------------------------------------------- /src/main/kotlin/kotlinx/nosql/util/SchemaUtils.kt: -------------------------------------------------------------------------------- 1 | package kotlinx.nosql.util 2 | 3 | import java.lang.reflect.Field 4 | import java.util.ArrayList 5 | import java.util.HashMap 6 | import kotlinx.nosql.AbstractColumn 7 | import kotlinx.nosql.AbstractSchema 8 | import org.joda.time.LocalDate 9 | import org.joda.time.LocalTime 10 | import org.joda.time.DateTime 11 | import kotlin.collections.listOf 12 | import kotlin.collections.setOf 13 | import kotlin.text.toLowerCase 14 | 15 | fun getAllFields(_type: Class, condition: (Field) -> Boolean = { f -> true }, 16 | fields: MutableList = ArrayList()): MutableList { 17 | for (field in _type.declaredFields!!) { 18 | if (condition(field)) fields.add(field) 19 | } 20 | if (_type.superclass != null) { 21 | getAllFields(_type.superclass!!, condition, fields) 22 | } 23 | return fields 24 | } 25 | 26 | fun getAllFieldsMap(_type: Class, condition: (Field) -> Boolean = { f -> true }, 27 | fields: MutableMap = HashMap()): MutableMap { 28 | for (field in _type.declaredFields!!) { 29 | if (condition(field)) fields.put(field.name!!.toLowerCase(), field) 30 | } 31 | if (_type.superclass != null) { 32 | getAllFieldsMap(_type.superclass, condition, fields) 33 | } 34 | return fields 35 | } 36 | 37 | val Field.isColumn: Boolean 38 | get() { 39 | return AbstractColumn::class.java.isAssignableFrom(this.type!!) 40 | } 41 | 42 | fun Field.asColumn(schema: Any): AbstractColumn<*, *, *> { 43 | this.isAccessible = true 44 | return this.get(schema) as AbstractColumn<*, *, *> 45 | } 46 | 47 | fun newInstance(clazz: Class): Any { 48 | val constructor = clazz.constructors!![0] 49 | val constructorParamTypes = constructor.parameterTypes!! 50 | val constructorParamValues = Array(constructor.parameterTypes!!.size, { index: Int -> 51 | when (constructorParamTypes[index].name) { 52 | "int" -> 0 53 | "java.lang.String" -> "" 54 | "org.joda.time.LocalDate" -> LocalDate() 55 | "org.joda.time.LocalTime" -> LocalTime() 56 | "org.joda.time.DateTime" -> DateTime() 57 | "double" -> 0.toDouble() 58 | "float" -> 0.toFloat() 59 | "long" -> 0.toLong() 60 | "short" -> 0.toShort() 61 | "byte" -> 0.toByte() 62 | "boolean" -> false 63 | "java.util.List" -> listOf() 64 | "java.util.Set" -> setOf() 65 | else -> newInstance(constructorParamTypes[index]) 66 | } 67 | }) 68 | return constructor.newInstance(*constructorParamValues)!! 69 | } 70 | --------------------------------------------------------------------------------