├── .editorconfig ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── shard.yml ├── spec ├── reql_spec.cr ├── reql_spec_generator.cr ├── rethinkdb_spec.cr ├── rql_test │ ├── connections │ │ └── server_info.yaml │ └── src │ │ ├── aggregation.yaml │ │ ├── arity.yaml │ │ ├── changefeeds │ │ ├── edge.yaml │ │ ├── geo.rb.yaml │ │ ├── idxcopy.yaml │ │ ├── include_states.yaml │ │ ├── point.yaml │ │ ├── sindex.yaml │ │ ├── squash.yaml │ │ └── table.yaml │ │ ├── control.yaml │ │ ├── datum │ │ ├── array.yaml │ │ ├── binary.yaml │ │ ├── bool.yaml │ │ ├── null.yaml │ │ ├── number.yaml │ │ ├── object.yaml │ │ ├── string.yaml │ │ ├── typeof.yaml │ │ └── uuid.yaml │ │ ├── default.yaml │ │ ├── geo │ │ ├── constructors.yaml │ │ ├── geojson.yaml │ │ ├── indexing.yaml │ │ ├── intersection_inclusion.yaml │ │ ├── operations.yaml │ │ └── primitives.yaml │ │ ├── joins.yaml │ │ ├── json.yaml │ │ ├── limits.yaml │ │ ├── match.yaml │ │ ├── math_logic │ │ ├── add.yaml │ │ ├── aliases.yaml │ │ ├── comparison.yaml │ │ ├── div.yaml │ │ ├── floor_ceil_round.yaml │ │ ├── logic.yaml │ │ ├── math.yaml │ │ ├── mod.yaml │ │ ├── mul.yaml │ │ └── sub.yaml │ │ ├── meta │ │ ├── composite.py.yaml │ │ ├── dbs.yaml │ │ └── table.yaml │ │ ├── mutation │ │ ├── atomic_get_set.yaml │ │ ├── delete.yaml │ │ ├── insert.yaml │ │ ├── replace.yaml │ │ ├── sync.yaml │ │ └── update.yaml │ │ ├── polymorphism.yaml │ │ ├── random.yaml │ │ ├── range.yaml │ │ ├── regression │ │ ├── 1001.yaml │ │ ├── 1005.yaml │ │ ├── 1023.yaml │ │ ├── 1081.yaml │ │ ├── 1132.yaml │ │ ├── 1133.yaml │ │ ├── 1155.yaml │ │ ├── 1179.yaml │ │ ├── 1468.yaml │ │ ├── 1789.yaml │ │ ├── 2052.yaml │ │ ├── 2399.rb.yaml │ │ ├── 2639.rb.yaml │ │ ├── 2696.yaml │ │ ├── 2697.yaml │ │ ├── 2709.yaml │ │ ├── 2710.yaml │ │ ├── 2766.yaml │ │ ├── 2767.yaml │ │ ├── 2774.yaml │ │ ├── 2838.py.yaml │ │ ├── 2930.yaml │ │ ├── 3057.yaml │ │ ├── 3059.yaml │ │ ├── 309.yaml │ │ ├── 3444.yaml │ │ ├── 3449.js.yaml │ │ ├── 354.yaml │ │ ├── 3637.yaml │ │ ├── 370.yaml │ │ ├── 3745.yaml │ │ ├── 3759.yaml │ │ ├── 4030.yaml │ │ ├── 4063.js.yaml │ │ ├── 4132.yaml │ │ ├── 4146.yaml │ │ ├── 4431.yaml │ │ ├── 4462.yaml │ │ ├── 4465.py.yaml │ │ ├── 4501.yaml │ │ ├── 453.yaml │ │ ├── 4582.yaml │ │ ├── 4591.yaml │ │ ├── 46.yaml │ │ ├── 469.yaml │ │ ├── 4729.yaml │ │ ├── 5092.js.yaml │ │ ├── 5130.js.yaml │ │ ├── 522.py.yaml │ │ ├── 5222.py.yaml │ │ ├── 5241.yaml │ │ ├── 5383.rb.yaml │ │ ├── 5438.yaml │ │ ├── 545.yaml │ │ ├── 546.yaml │ │ ├── 5481.py.yaml │ │ ├── 5535.rb.yaml │ │ ├── 5542.py.yaml │ │ ├── 568.yaml │ │ ├── 578.yaml │ │ ├── 579.yaml │ │ ├── 619.yaml │ │ ├── 665.yaml │ │ ├── 678.yaml │ │ ├── 718.yaml │ │ ├── 730.yaml │ │ ├── 757.yaml │ │ ├── 763.js.yaml │ │ ├── 767.yaml │ │ └── 831.yaml │ │ ├── selection.yaml │ │ ├── sindex │ │ ├── api.yaml │ │ ├── nullsinstrings.yaml │ │ ├── status.yaml │ │ ├── trunc_array.rb.yaml │ │ └── truncation.rb.yaml │ │ ├── timeout.yaml │ │ ├── times │ │ ├── api.yaml │ │ ├── constructors.yaml │ │ ├── index.yaml │ │ ├── portions.yaml │ │ ├── shim.yaml │ │ ├── time_arith.yaml │ │ └── timezones.yaml │ │ ├── transform │ │ ├── array.yaml │ │ ├── fold.yaml │ │ ├── map.yaml │ │ ├── object.yaml │ │ ├── table.yaml │ │ └── unordered_map.yaml │ │ └── transformation.yaml └── spec_helper.cr └── src ├── crystal-rethinkdb.cr ├── rethinkdb.cr └── rethinkdb ├── api-datum.cr ├── api-db.cr ├── api-global.cr ├── api-grouped.cr ├── api-row.cr ├── api-rows.cr ├── api-stream.cr ├── api-table.cr ├── api-term.cr ├── auth.cr ├── connection.cr ├── constants.cr ├── crypto.cr ├── cursor.cr ├── error.cr ├── message.cr ├── serialization.cr └── term.cr /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.cr] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | pull_request: 5 | schedule: 6 | - cron: "0 0 * * 1" # Midnight monday 7 | 8 | jobs: 9 | style: 10 | name: Style 11 | runs-on: ubuntu-latest 12 | container: crystallang/crystal:latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Format 16 | run: crystal tool format --check 17 | - name: Lint 18 | uses: crystal-ameba/github-action@v0.2.12 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | 22 | test: 23 | runs-on: ubuntu-latest 24 | name: "Test - crystal: ${{ matrix.crystal }}, MT: ${{ matrix.MT }}, stable: ${{ matrix.stable }}" 25 | continue-on-error: ${{ !matrix.stable }} 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | crystal: 30 | - 0.35.1 31 | - 0.36.1 32 | - 1.0.0 33 | - 1.1.1 34 | stable: [true] 35 | MT: [false] 36 | include: 37 | - crystal: 1.1.1 38 | MT: true 39 | stable: false 40 | - crystal: nightly 41 | MT: true 42 | stable: false 43 | - crystal: nightly 44 | MT: false 45 | stable: false 46 | services: 47 | rethink: 48 | image: rethinkdb:2.4 49 | ports: 50 | - 29015:29015 51 | - 28015:28015 52 | steps: 53 | - uses: actions/checkout@v2 54 | - uses: crystal-lang/install-crystal@v1 55 | with: 56 | crystal: ${{ matrix.crystal }} 57 | - name: Up open file limit 58 | run: ulimit -n 10000 59 | - run: shards install --ignore-crystal-version 60 | - name: Test 61 | if: ${{ !matrix.MT }} 62 | run: crystal spec --error-trace -v --no-color 63 | - name: Test Multithreading 64 | if: ${{ matrix.MT }} 65 | run: crystal spec --error-trace -v --no-color -Dpreview_mt 66 | 67 | publish: 68 | name: Publish Documentation 69 | if: contains('refs/tags', github.ref) 70 | runs-on: ubuntu-latest 71 | container: crystallang/crystal:latest 72 | steps: 73 | - uses: actions/checkout@v2 74 | - run: shards install --ignore-crystal-version 75 | - name: Run `crystal docs` 76 | run: https://github.com/kingsleyh/crystal-rethinkdb/tree/$(shards version) 77 | - name: Publish to GitHub Pages 78 | uses: crazy-max/ghaction-github-pages@v2 79 | with: 80 | target_branch: docs 81 | build_dir: docs 82 | commit_message: "Update docs for ${{ github.ref }}" 83 | env: 84 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 85 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /docs/ 2 | /lib/ 3 | /bin/ 4 | /.shards/ 5 | *.dwarf 6 | 7 | # Libraries don't need dependency lock 8 | # Dependencies will be locked in application that uses them 9 | /shard.lock 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Kingsley Hendrickse, Guilherme Bernal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /shard.yml: -------------------------------------------------------------------------------- 1 | name: rethinkdb 2 | version: 0.3.1 3 | crystal: ">= 0.35.1" 4 | license: MIT 5 | 6 | dependencies: 7 | retriable: 8 | github: sija/retriable.cr 9 | version: ~> 0.2 10 | 11 | authors: 12 | - Kingsley Hendrickse 13 | - Caspian Baska 14 | -------------------------------------------------------------------------------- /spec/reql_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | r.db("test").table_list.for_each do |name| 4 | r.db("test").table_drop(name) 5 | end.run(Fixtures::TestDB.conn) 6 | describe RethinkDB do 7 | {{ run("./reql_spec_generator", "spec/rql_test/src/aggregation.yaml") }} 8 | {{ run("./reql_spec_generator", "spec/rql_test/src/control.yaml") }} 9 | {{ run("./reql_spec_generator", "spec/rql_test/src/datum/array.yaml") }} 10 | {{ run("./reql_spec_generator", "spec/rql_test/src/datum/bool.yaml") }} 11 | {{ run("./reql_spec_generator", "spec/rql_test/src/datum/null.yaml") }} 12 | {{ run("./reql_spec_generator", "spec/rql_test/src/datum/number.yaml") }} 13 | {{ run("./reql_spec_generator", "spec/rql_test/src/datum/object.yaml") }} 14 | {{ run("./reql_spec_generator", "spec/rql_test/src/datum/string.yaml") }} 15 | {{ run("./reql_spec_generator", "spec/rql_test/src/datum/typeof.yaml") }} 16 | {{ run("./reql_spec_generator", "spec/rql_test/src/datum/uuid.yaml") }} 17 | {{ run("./reql_spec_generator", "spec/rql_test/src/default.yaml") }} 18 | {{ run("./reql_spec_generator", "spec/rql_test/src/math_logic/add.yaml") }} 19 | {{ run("./reql_spec_generator", "spec/rql_test/src/math_logic/aliases.yaml") }} 20 | {{ run("./reql_spec_generator", "spec/rql_test/src/math_logic/div.yaml") }} 21 | {{ run("./reql_spec_generator", "spec/rql_test/src/math_logic/floor_ceil_round.yaml") }} 22 | {{ run("./reql_spec_generator", "spec/rql_test/src/math_logic/logic.yaml") }} 23 | {{ run("./reql_spec_generator", "spec/rql_test/src/math_logic/math.yaml") }} 24 | {{ run("./reql_spec_generator", "spec/rql_test/src/math_logic/mod.yaml") }} 25 | {{ run("./reql_spec_generator", "spec/rql_test/src/math_logic/mul.yaml") }} 26 | {{ run("./reql_spec_generator", "spec/rql_test/src/math_logic/sub.yaml") }} 27 | {{ run("./reql_spec_generator", "spec/rql_test/src/mutation/update.yaml") }} 28 | {{ run("./reql_spec_generator", "spec/rql_test/src/range.yaml") }} 29 | {{ run("./reql_spec_generator", "spec/rql_test/src/selection.yaml") }} 30 | end 31 | -------------------------------------------------------------------------------- /spec/reql_spec_generator.cr: -------------------------------------------------------------------------------- 1 | require "yaml" 2 | 3 | def yaml_fixes(str) 4 | str = str.gsub("\\", "\\\\") 5 | str = str.gsub(/(\w+): (.+)\n/) do 6 | var = $1 7 | value = $2 8 | "#{var}: \"#{value.gsub("\"", "\\\"")}\"\n" 9 | end 10 | str 11 | end 12 | 13 | def quotes_fixes(str) 14 | str = str.gsub(/'([^']*)'/) { "\"#{$1.gsub("\"", "\\\"")}\"" } 15 | str 16 | end 17 | 18 | def language_fixes(str) 19 | lang_replaces = { 20 | "None" => "nil", 21 | "null" => "nil", 22 | "True" => "true", 23 | "False" => "false", 24 | } 25 | regex = /([^"'\w]|^)(#{lang_replaces.keys.join("|")})([^"'\w]|$)/ 26 | if !str.is_a?(String) 27 | str = str.raw.to_s 28 | end 29 | str = str.gsub(regex) do 30 | "#{$1}#{lang_replaces[$2]}#{$3}" 31 | end 32 | str = quotes_fixes(str) 33 | str = str.gsub("[]", "[] of Int32") 34 | str = str.gsub(/([^\)\s]\s*){}([^"])/) { "#{$1}{} of String => Int32#{$2}" } 35 | str = str.gsub(/^{}$/, "{} of String => Int32") 36 | str = str.gsub(/([^\\\d])\":/) { "#{$1}\" => " } 37 | str = str.gsub(/(\s|\{|,)(\d+):/) { "#{$1}#{$2} => " } 38 | str = str.gsub(/(\}):/) { "#{$1} => " } 39 | str = str.gsub(/(\W\s|\{|,|\()(\w+):/) { "#{$1}#{$2}: " } 40 | str = str.gsub("nil:", "nil =>") 41 | str = str.gsub("{{", "{ {") 42 | str = str.gsub("orderby", "order_by") 43 | str = str.gsub(/:(\w+) =>/) { "#{$1}:" } 44 | str 45 | end 46 | 47 | data = YAML.parse(yaml_fixes File.read(ARGV[0])) 48 | 49 | puts "describe #{data["desc"].inspect} do" 50 | if tables = data["table_variable_name"]? 51 | puts 52 | tables.as_s.split(", ").flat_map(&.split(' ')).each_with_index do |tablevar, i| 53 | random_name = "test_#{Time.utc.to_unix}_#{rand(10000)}_#{i + 1}" 54 | puts " r.db(\"test\").table_create(#{random_name.inspect}).run(Fixtures::TestDB.conn)" 55 | puts " #{tablevar} = r.db(\"test\").table(#{random_name.inspect})" 56 | end 57 | end 58 | data["tests"].as_a.each_with_index do |test, i| 59 | if d = test["def"]? 60 | if d.raw.is_a? Hash 61 | code = (d["rb"]? || d["cd"]).as_s 62 | code = d["js"].as_s if d["js"]? && d["js"].as_s =~ /\* 1000/ 63 | else 64 | code = d.as_s 65 | end 66 | puts " #{language_fixes code}" 67 | elsif test["ot"]? == nil && (test["rb"]? || test["cd"]?) 68 | assign = (language_fixes (test["rb"]? || test["cd"]).as_s).split("=") 69 | var = assign[0].strip 70 | value = assign[1].strip 71 | puts " #{var} = #{value}.run(Fixtures::TestDB.conn).as_i" 72 | else 73 | test["ot"]? 74 | subtests = test["rb"]? || test["cd"]? 75 | next unless subtests 76 | next if subtests == "" || subtests.raw.nil? 77 | if subtests.raw.is_a? Array 78 | subtests = subtests.as_a 79 | else 80 | subtests = [subtests.as_s] 81 | end 82 | 83 | output = test["ot"] 84 | unless output.raw.is_a? String 85 | if output["js"]? && output["js"].as_s =~ /reduction/ 86 | output = output["js"] 87 | else 88 | output = output["rb"]? || output["cd"] 89 | end 90 | end 91 | output = quotes_fixes output.as_s 92 | next if output =~ /ReqlCompileError/ && output =~ /argument/ 93 | next if output =~ /ReqlCompileError/ && output =~ /Object keys must be strings/ 94 | next if output =~ /ReqlQueryLogicError/ && output =~ /Expected function with \d+ argument/ 95 | next if output =~ /ReqlDriverCompileError/ 96 | 97 | runopts = test["runopts"]? || "{} of String => String" 98 | puts unless i == 0 99 | subtests.each_with_index do |subtest, j| 100 | next if output =~ /lambda/ || subtest =~ /lambda/ 101 | subtest = language_fixes subtest 102 | puts unless j == 0 103 | test_id = "##{i + 1}.#{j + 1}" 104 | puts " #{ARGV.includes?(test_id) ? "pending" : "it"} \"passes on test #{test_id}: #{subtest.gsub("\\", "\\\\").gsub("\"", "\\\"")}\" do" 105 | if output =~ /err\("(\w+)",\s?"(.+?)"[,)]/ 106 | puts " expect_raises(RethinkDB::#{$1}, \"#{$2.gsub("\\\\", "\\")}\") do" 107 | puts " (#{subtest}).run(Fixtures::TestDB.conn, #{runopts})" 108 | puts " end" 109 | elsif output =~ /err_regex\("(\w+)",\s?"(.+?)"[,)]/ 110 | puts " expect_raises(RethinkDB::#{$1}, /#{$2.gsub("\\\\", "\\")}/) do" 111 | puts " (#{subtest}).run(Fixtures::TestDB.conn, #{runopts})" 112 | puts " end" 113 | else 114 | puts " result = (#{subtest}).run(Fixtures::TestDB.conn, #{runopts})" 115 | puts " match_reql_output(result) { (#{language_fixes output}) }" 116 | end 117 | puts " end" 118 | end 119 | end 120 | end 121 | puts "end" 122 | -------------------------------------------------------------------------------- /spec/rethinkdb_spec.cr: -------------------------------------------------------------------------------- 1 | require "./spec_helper" 2 | 3 | describe RethinkDB do 4 | it "successfuly connects to the database" do 5 | connection = Fixtures::TestDB.conn 6 | connection.should be_a(RethinkDB::Connection) 7 | end 8 | 9 | it "raises unknown user error" do 10 | expect_raises(RethinkDB::ReqlError::ReqlDriverError::ReqlAuthError, "error_code: 17, error: Unknown user") do 11 | r.connect(host: Fixtures::TestDB.host, user: "owenfvoraewugbjbkv") 12 | end 13 | end 14 | 15 | it "raises unknown user error" do 16 | expect_raises(RethinkDB::ReqlError::ReqlDriverError::ReqlAuthError, "error_code: 12, error: Wrong password") do 17 | r.connect(host: Fixtures::TestDB.host, user: "admin", password: "incorrect") 18 | end 19 | end 20 | 21 | it "skip" do 22 | Generators.random_table_with_entries(20, ->(table : String) { 23 | r.table(table).skip(10).run(Fixtures::TestDB.conn).to_a.size.should eq(10) 24 | }) 25 | end 26 | 27 | it "r#json" do 28 | Generators.random_table do |table| 29 | r.table_create(table).run Fixtures::TestDB.conn 30 | 5.times do 31 | # Generate a random document 32 | document = { 33 | "id" => Generators.random_pk, 34 | "serial" => Generators.random_pk, 35 | "array" => Generators.random_array, 36 | "object" => Generators.random_hash, 37 | } 38 | 39 | # Insert the raw json, parsed on the DB 40 | response = r.json(document.to_json).do { |value| 41 | r.table(table).insert(value, return_changes: true) 42 | }.run Fixtures::TestDB.conn 43 | 44 | recursive_match(response["changes"][0]["new_val"], document) 45 | end 46 | 47 | r.table_drop(table).run Fixtures::TestDB.conn 48 | end 49 | end 50 | 51 | it "db#table_create(String, **options)" do 52 | 5.times do 53 | Generators.random_table do |table| 54 | Generators.random_pk do |pk| 55 | r.table_create(table).run Fixtures::TestDB.conn, {"primary_key" => pk} 56 | info = r.table(table).info.run Fixtures::TestDB.conn 57 | info["primary_key"].should eq pk 58 | info["name"].should eq table 59 | r.table_drop(table).run Fixtures::TestDB.conn 60 | end 61 | end 62 | end 63 | end 64 | 65 | it "table#info(String)" do 66 | 5.times do 67 | Generators.random_table do |table| 68 | r.table_create(table).run Fixtures::TestDB.conn 69 | info = r.table(table).info.run Fixtures::TestDB.conn 70 | info["type"].should eq "TABLE" 71 | info["primary_key"].should eq "id" 72 | info["name"].should eq table 73 | r.table_drop(table).run Fixtures::TestDB.conn 74 | end 75 | end 76 | end 77 | 78 | describe "listening to a feed" do 79 | it "table#changes" do 80 | table = Generators.random_table 81 | r.table_create(table).run Fixtures::TestDB.conn 82 | 83 | number_of_queries = 6 84 | result = [] of RethinkDB::QueryResult 85 | 86 | cursor = r.table(table).changes.run Fixtures::TestDB.conn 87 | spawn do 88 | cursor.each_with_index do |v, i| 89 | result << v 90 | break if i == number_of_queries - 1 91 | end 92 | end 93 | 94 | number_of_queries.times do 95 | r.table(table).insert({:id => Generators.random_pk}).run Fixtures::TestDB.conn 96 | end 97 | 98 | result.size.should eq number_of_queries 99 | result.each do |r| 100 | r.keys.should contain "new_val" 101 | r.keys.should contain "old_val" 102 | end 103 | 104 | r.table_drop(table).run Fixtures::TestDB.conn 105 | end 106 | 107 | it "document#changes" do 108 | table = Generators.random_table 109 | r.table_create(table).run Fixtures::TestDB.conn 110 | 111 | pk = Generators.random_pk 112 | results = [] of RethinkDB::QueryResult 113 | r.table(table).insert({id: pk, times: 0}) 114 | cursor = r.table(table).get(pk).changes.run Fixtures::TestDB.conn 115 | 116 | spawn do 117 | cursor.each do |v| 118 | old_times = v["old_val"]["times"].as_i 119 | new_times = v["new_val"]["times"].as_i 120 | new_times.should eq (old_times + 1) 121 | results << v 122 | end 123 | rescue e 124 | e.to_s.should contain "Changefeed aborted" 125 | end 126 | 127 | 6.times do |i| 128 | r.table(table).get(pk).update({times: i + 1}).run Fixtures::TestDB.conn 129 | end 130 | 131 | random_pk = Generators.random_pk 132 | r.table(table).insert({id: random_pk}).run Fixtures::TestDB.conn 133 | 134 | # Check that only documents in changefeed scope trigger events 135 | results.map do |v| 136 | id = v["new_value"]["id"].to_s 137 | (id != random_pk && pk == id).should be_true 138 | end 139 | 140 | r.table_drop(table).run Fixtures::TestDB.conn 141 | end 142 | end 143 | end 144 | -------------------------------------------------------------------------------- /spec/rql_test/connections/server_info.yaml: -------------------------------------------------------------------------------- 1 | desc: conn.server() tests 2 | tests: 3 | - cd: conn.server() 4 | ot: {"id": uuid(), "name": regex('.+'), "proxy": false} 5 | -------------------------------------------------------------------------------- /spec/rql_test/src/changefeeds/geo.rb.yaml: -------------------------------------------------------------------------------- 1 | desc: Geo indexed changefeed operations 2 | table_variable_name: tbl 3 | tests: 4 | - rb: tbl.index_create('L', {geo: true}) 5 | ot: partial({'created': 1}) 6 | 7 | - rb: tbl.index_wait().count 8 | ot: 1 9 | 10 | - def: obj11 = {id: "11", L: r.point(1,1)} 11 | - def: obj12 = {id: "12", L: r.point(1,2)} 12 | - def: obj21 = {id: "21", L: r.point(2,1)} 13 | - def: obj22 = {id: "22", L: r.point(2,2)} 14 | 15 | # A distance of 130,000 meters from 1,1 is enough to cover 1,2 and 2,1 (~110km 16 | # distance) but not 2,2 (~150km distance.) 17 | # 18 | # This is useful because the S2LatLngRect bounding box passed to the shards contains 19 | # 2,2 yet it should not be returned in the changefeed results. 20 | - rb: feed = tbl.get_intersecting(r.circle(r.point(1,1), 130000), {index: "L"}).get_field("id").changes(include_initial: true) 21 | 22 | - rb: tbl.insert([obj11, obj12, obj21, obj22]) 23 | ot: partial({'errors': 0, 'inserted': 4}) 24 | 25 | - rb: fetch(feed, 3) 26 | ot: bag([{"new_val" => "11", "old_val" => nil}, {"new_val" => "12", "old_val" => nil}, {"new_val" => "21", "old_val" => nil}]) 27 | 28 | -------------------------------------------------------------------------------- /spec/rql_test/src/changefeeds/idxcopy.yaml: -------------------------------------------------------------------------------- 1 | desc: Test duplicate indexes with squashing 2 | table_variable_name: tbl 3 | tests: 4 | - cd: tbl.index_create('a') 5 | ot: partial({'created':1}) 6 | - cd: tbl.index_wait('a') 7 | 8 | - py: feed = tbl.order_by(index='a').limit(10).changes(squash=2) 9 | rb: feed = tbl.orderby(index:'a').limit(10).changes(squash:2).limit(9) 10 | js: feed = tbl.orderBy({index:'a'}).limit(10).changes({squash:2}).limit(9) 11 | runopts: 12 | # limit the number of pre-fetched rows 13 | max_batch_rows: 1 14 | 15 | - py: tbl.insert(r.range(0, 12).map({'id':r.row, 'a':5})) 16 | rb: tbl.insert(r.range(0, 12).map{|row| {'id':row, 'a':5}}) 17 | js: tbl.insert(r.range(0, 12).map(function(row){ return {'id':row, 'a':5}; })) 18 | ot: partial({'inserted':12, 'errors':0}) 19 | 20 | - py: tbl.get_all(1, 8, 9, index='id').delete() 21 | rb: tbl.get_all(1, 8, 9, index:'id').delete() 22 | js: tbl.get_all(1, 8, 9, {index:'id'}).delete() 23 | ot: partial({'deleted':3, 'errors':0}) 24 | 25 | # should be replaced with a noreplyWait 26 | - cd: wait(2) 27 | 28 | - cd: fetch(feed) 29 | ot: bag([ 30 | {"new_val":{"a":5, "id":0}, "old_val":nil}, 31 | {"new_val":{"a":5, "id":2}, "old_val":nil}, 32 | {"new_val":{"a":5, "id":3}, "old_val":nil}, 33 | {"new_val":{"a":5, "id":4}, "old_val":nil}, 34 | {"new_val":{"a":5, "id":5}, "old_val":nil}, 35 | {"new_val":{"a":5, "id":6}, "old_val":nil}, 36 | {"new_val":{"a":5, "id":7}, "old_val":nil}, 37 | {"new_val":{"a":5, "id":10}, "old_val":nil}, 38 | {"new_val":{"a":5, "id":11}, "old_val":nil}]) 39 | -------------------------------------------------------------------------------- /spec/rql_test/src/changefeeds/include_states.yaml: -------------------------------------------------------------------------------- 1 | desc: Test `include_states` 2 | table_variable_name: tbl 3 | tests: 4 | - py: tbl.changes(squash=true, include_states=true).limit(1) 5 | rb: tbl.changes(squash:true, include_states:true).limit(1) 6 | js: tbl.changes({squash:true, includeStates:true}).limit(1) 7 | ot: [{'state':'ready'}] 8 | 9 | - py: tbl.get(0).changes(squash=true, include_states=true, include_initial=true).limit(3) 10 | rb: tbl.get(0).changes(squash:true, include_states:true, include_initial:true).limit(3) 11 | js: tbl.get(0).changes({squash:true, includeStates:true, includeInitial:true}).limit(3) 12 | ot: [{'state':'initializing'}, {'new_val':null}, {'state':'ready'}] 13 | 14 | - py: tbl.order_by(index='id').limit(10).changes(squash=true, include_states=true, include_initial=true).limit(2) 15 | rb: tbl.order_by(index:'id').limit(10).changes(squash:true, include_states:true, include_initial:true).limit(2) 16 | js: tbl.orderBy({index:'id'}).limit(10).changes({squash:true, includeStates:true, includeInitial:true}).limit(2) 17 | ot: [{'state':'initializing'}, {'state':'ready'}] 18 | 19 | - cd: tbl.insert({'id':1}) 20 | 21 | - py: tbl.order_by(index='id').limit(10).changes(squash=true, include_states=true, include_initial=true).limit(3) 22 | rb: tbl.order_by(index:'id').limit(10).changes(squash:true, include_states:true, include_initial:true).limit(3) 23 | js: tbl.orderBy({index:'id'}).limit(10).changes({squash:true, includeStates:true, includeInitial:true}).limit(3) 24 | ot: [{'state':'initializing'}, {'new_val':{'id':1}}, {'state':'ready'}] 25 | 26 | - py: tblchanges = tbl.changes(squash=true, include_states=true) 27 | rb: tblchanges = tbl.changes(squash:true, include_states:true) 28 | js: tblchanges = tbl.changes({squash:true, includeStates:true}) 29 | 30 | - cd: tbl.insert({'id':2}) 31 | 32 | - cd: fetch(tblchanges, 2) 33 | ot: [{'state':'ready'},{'new_val':{'id':2},'old_val':null}] 34 | 35 | - py: getchanges = tbl.get(2).changes(include_states=true, include_initial=true) 36 | rb: getchanges = tbl.get(2).changes(include_states:true, include_initial:true) 37 | js: getchanges = tbl.get(2).changes({includeStates:true, includeInitial:true}) 38 | 39 | - cd: tbl.get(2).update({'a':1}) 40 | 41 | - cd: fetch(getchanges, 4) 42 | ot: [{'state':'initializing'}, {'new_val':{'id':2}}, {'state':'ready'}, {'old_val':{'id':2},'new_val':{'id':2,'a':1}}] 43 | 44 | - py: limitchanges = tbl.order_by(index='id').limit(10).changes(include_states=true, include_initial=true) 45 | rb: limitchanges = tbl.order_by(index:'id').limit(10).changes(include_states:true, include_initial:true) 46 | js: limitchanges = tbl.orderBy({index:'id'}).limit(10).changes({includeStates:true, includeInitial:true}) 47 | 48 | - py: limitchangesdesc = tbl.order_by(index=r.desc('id')).limit(10).changes(include_states=true, include_initial=true) 49 | rb: limitchangesdesc = tbl.order_by(index:r.desc('id')).limit(10).changes(include_states:true, include_initial:true) 50 | js: limitchangesdesc = tbl.orderBy({index:r.desc('id')}).limit(10).changes({includeStates:true, includeInitial:true}) 51 | 52 | - cd: tbl.insert({'id':3}) 53 | 54 | - cd: fetch(limitchanges, 5) 55 | ot: [{'state':'initializing'}, {'new_val':{'id':1}}, {'new_val':{'a':1, 'id':2}}, {'state':'ready'}, {'old_val':null, 'new_val':{'id':3}}] 56 | 57 | - cd: fetch(limitchangesdesc, 5) 58 | ot: [{'state':'initializing'}, {'new_val':{'a':1, 'id':2}}, {'new_val':{'id':1}}, {'state':'ready'}, {'old_val':null, 'new_val':{'id':3}}] 59 | -------------------------------------------------------------------------------- /spec/rql_test/src/changefeeds/sindex.yaml: -------------------------------------------------------------------------------- 1 | desc: Test basic changefeed operations 2 | table_variable_name: tbl 3 | tests: 4 | 5 | # Fill in some data 6 | - rb: tbl.index_create('a') 7 | ot: partial({'created':1}) 8 | 9 | - rb: tbl.index_wait().count 10 | ot: 1 11 | 12 | - rb: tbl.insert([{id:1, a:8}, {id:2, a:7}]) 13 | ot: partial({'errors':0, 'inserted':2}) 14 | 15 | - rb: idmin = tbl.min(index:'id').changes(squash:false, include_initial:true).limit(2) 16 | - rb: idmax = tbl.max(index:'id').changes(squash:false, include_initial:true).limit(2) 17 | - rb: amin = tbl.min(index:'a').changes(squash:false, include_initial:true).limit(2) 18 | - rb: amax = tbl.max(index:'a').changes(squash:false, include_initial:true).limit(2) 19 | 20 | - rb: idmin2 = tbl.min(index:'id').changes(squash:true, include_initial:true).limit(2) 21 | - rb: idmax2 = tbl.max(index:'id').changes(squash:true, include_initial:true).limit(2) 22 | - rb: amin2 = tbl.min(index:'a').changes(squash:true, include_initial:true).limit(2) 23 | - rb: amax2 = tbl.max(index:'a').changes(squash:true, include_initial:true).limit(2) 24 | 25 | - rb: tbl.insert([{id:0, a:9}, {id:3, a:6}]) 26 | ot: partial({'errors':0, 'inserted':2}) 27 | 28 | - rb: idmin.to_a 29 | ot: ([{"new_val"=>{"a"=>8, "id"=>1}}, {"new_val"=>{"a"=>9, "id"=>0}, "old_val"=>{"a"=>8, "id"=>1}}]) 30 | 31 | - rb: idmax.to_a 32 | ot: ([{"new_val"=>{"a"=>7, "id"=>2}}, {"new_val"=>{"a"=>6, "id"=>3}, "old_val"=>{"a"=>7, "id"=>2}}]) 33 | 34 | - rb: amin.to_a 35 | ot: ([{"new_val"=>{"a"=>7, "id"=>2}}, {"new_val"=>{"a"=>6, "id"=>3}, "old_val"=>{"a"=>7, "id"=>2}}]) 36 | 37 | - rb: amax.to_a 38 | ot: ([{"new_val"=>{"a"=>8, "id"=>1}}, {"new_val"=>{"a"=>9, "id"=>0}, "old_val"=>{"a"=>8, "id"=>1}}]) 39 | 40 | - rb: idmin2.to_a 41 | ot: ([{"new_val"=>{"a"=>8, "id"=>1}}, {"new_val"=>{"a"=>9, "id"=>0}, "old_val"=>{"a"=>8, "id"=>1}}]) 42 | 43 | - rb: idmax2.to_a 44 | ot: ([{"new_val"=>{"a"=>7, "id"=>2}}, {"new_val"=>{"a"=>6, "id"=>3}, "old_val"=>{"a"=>7, "id"=>2}}]) 45 | 46 | - rb: amin2.to_a 47 | ot: ([{"new_val"=>{"a"=>7, "id"=>2}}, {"new_val"=>{"a"=>6, "id"=>3}, "old_val"=>{"a"=>7, "id"=>2}}]) 48 | 49 | - rb: amax2.to_a 50 | ot: ([{"new_val"=>{"a"=>8, "id"=>1}}, {"new_val"=>{"a"=>9, "id"=>0}, "old_val"=>{"a"=>8, "id"=>1}}]) 51 | -------------------------------------------------------------------------------- /spec/rql_test/src/changefeeds/squash.yaml: -------------------------------------------------------------------------------- 1 | desc: Test changefeed squashing 2 | table_variable_name: tbl 3 | tests: 4 | 5 | # Check type 6 | 7 | - py: tbl.changes(squash=true).type_of() 8 | rb: tbl.changes(squash:true).type_of() 9 | js: tbl.changes({squash:true}).typeOf() 10 | ot: ("STREAM") 11 | 12 | # comparison changes 13 | 14 | - cd: normal_changes = tbl.changes().limit(2) 15 | 16 | - py: false_squash_changes = tbl.changes(squash=False).limit(2) 17 | js: false_squash_changes = tbl.changes({squash:false}).limit(2) 18 | rb: false_squash_changes = tbl.changes(squash:false).limit(2) 19 | 20 | - py: long_squash_changes = tbl.changes(squash=0.5).limit(1) 21 | js: long_squash_changes = tbl.changes({squash:0.5}).limit(1) 22 | rb: long_squash_changes = tbl.changes(squash:0.5).limit(1) 23 | 24 | - py: squash_changes = tbl.changes(squash=true).limit(1) 25 | js: squash_changes = tbl.changes({squash:true}).limit(1) 26 | rb: squash_changes = tbl.changes(squash:true).limit(1) 27 | 28 | - cd: tbl.insert({'id':100})['inserted'] 29 | js: tbl.insert({'id':100})('inserted') 30 | ot: 1 31 | 32 | - cd: tbl.get(100).update({'a':1})['replaced'] 33 | js: tbl.get(100).update({'a':1})('replaced') 34 | ot: 1 35 | 36 | - cd: normal_changes 37 | ot: ([{'new_val':{'id':100}, 'old_val':null}, 38 | {'new_val':{'a':1, 'id':100}, 'old_val':{'id':100}}]) 39 | 40 | - cd: false_squash_changes 41 | ot: ([{'new_val':{'id':100}, 'old_val':null}, 42 | {'new_val':{'a':1, 'id':100}, 'old_val':{'id':100}}]) 43 | 44 | - cd: long_squash_changes 45 | ot: ([{'new_val':{'a':1, 'id':100}, 'old_val':null}]) 46 | 47 | - cd: squash_changes 48 | ot: 49 | js: ([{'new_val':{'a':1, 'id':100}, 'old_val':null}]) 50 | cd: ([{'new_val':{'id':100}, 'old_val':null}]) 51 | 52 | # Bad squash values 53 | 54 | - py: tbl.changes(squash=null) 55 | rb: tbl.changes(squash:null) 56 | js: tbl.changes({squash:null}) 57 | ot: err('ReqlQueryLogicError', 'Expected BOOL or NUMBER but found NULL.') 58 | 59 | - py: tbl.changes(squash=-10) 60 | rb: tbl.changes(squash:-10) 61 | js: tbl.changes({squash:-10}) 62 | ot: err('ReqlQueryLogicError', 'Expected BOOL or a positive NUMBER but found a negative NUMBER.') 63 | -------------------------------------------------------------------------------- /spec/rql_test/src/changefeeds/table.yaml: -------------------------------------------------------------------------------- 1 | desc: Test changefeeds on a table 2 | table_variable_name: tbl 3 | tests: 4 | 5 | # ==== regular tables 6 | 7 | # - start feeds 8 | 9 | - cd: all = tbl.changes() 10 | 11 | # - note: no initial values from table changefeeds 12 | 13 | # - inserts 14 | 15 | - cd: tbl.insert([{'id':1}, {'id':2}]) 16 | ot: partial({'errors':0, 'inserted':2}) 17 | - cd: fetch(all, 2) 18 | ot: bag([{'old_val':null, 'new_val':{'id':1}}, {'old_val':null, 'new_val':{'id':2}}]) 19 | 20 | # - updates 21 | 22 | - cd: tbl.get(1).update({'version':1}) 23 | ot: partial({'errors':0, 'replaced':1}) 24 | - cd: fetch(all, 1) 25 | ot: [{'old_val':{'id':1}, 'new_val':{'id':1, 'version':1}}] 26 | 27 | # - deletions 28 | 29 | - cd: tbl.get(1).delete() 30 | ot: partial({'errors':0, 'deleted':1}) 31 | - cd: fetch(all, 1) 32 | ot: [{'old_val':{'id':1, 'version':1}, 'new_val':null}] 33 | 34 | # - pluck on values 35 | 36 | - cd: pluck = tbl.changes().pluck({'new_val':['version']}) 37 | - cd: tbl.insert([{'id':5, 'version':5}]) 38 | ot: partial({'errors':0, 'inserted':1}) 39 | - cd: fetch(pluck, 1) 40 | ot: [{'new_val':{'version':5}}] 41 | 42 | # - order by 43 | 44 | - cd: tbl.changes().order_by('id') 45 | ot: err('ReqlQueryLogicError', "Cannot call a terminal (`reduce`, `count`, etc.) on an infinite stream (such as a changefeed).") 46 | # 47 | # ToDo: enable this when #4067 is done 48 | # 49 | # - js: orderedLimit = tbl.changes().limit(5).order_by(r.desc('id'))('new_val')('id') 50 | # cd: orderedLimit = tbl.changes().limit(5).order_by(r.desc('id'))['new_val']['id'] 51 | # - js: tbl.range(100, 105).map(function (row) { return {'id':row} }) 52 | # py: tbl.range(100, 105).map({'id':r.row}) 53 | # rb: tbl.range(100, 105).map{|row| {'id':row}} 54 | # - cd: fetch(orderedLimit) 55 | # ot: [104, 103, 102, 101, 100] 56 | 57 | # - changes overflow 58 | 59 | - cd: overflow = tbl.changes() 60 | runopts: 61 | changefeed_queue_size: 100 62 | # add enough entries to make sure we get the overflow error 63 | - js: tbl.insert(r.range(200).map(function(x) { return({}); })) 64 | py: tbl.insert(r.range(200).map(lambda x: {})) 65 | rb: tbl.insert(r.range(200).map{|x| {}}) 66 | - cd: fetch(overflow, 90) 67 | ot: partial([{'error': regex('Changefeed cache over array size limit, skipped \d+ elements.')}]) 68 | 69 | # ==== virtual tables 70 | 71 | - def: vtbl = r.db('rethinkdb').table('_debug_scratch') 72 | - cd: allVirtual = vtbl.changes() 73 | 74 | # - inserts 75 | 76 | - cd: vtbl.insert([{'id':1}, {'id':2}]) 77 | ot: partial({'errors':0, 'inserted':2}) 78 | - cd: fetch(allVirtual, 2) 79 | ot: bag([{'old_val':null, 'new_val':{'id':1}}, {'old_val':null, 'new_val':{'id':2}}]) 80 | 81 | # - updates 82 | 83 | - cd: vtbl.get(1).update({'version':1}) 84 | ot: partial({'errors':0, 'replaced':1}) 85 | - cd: fetch(allVirtual, 1) 86 | ot: [{'old_val':{'id':1}, 'new_val':{'id':1, 'version':1}}] 87 | 88 | # - deletions 89 | 90 | - cd: vtbl.get(1).delete() 91 | ot: partial({'errors':0, 'deleted':1}) 92 | - cd: fetch(allVirtual, 1) 93 | ot: [{'old_val':{'id':1, 'version':1}, 'new_val':null}] 94 | 95 | # - pluck on values 96 | 97 | - cd: vpluck = vtbl.changes().pluck({'new_val':['version']}) 98 | - cd: vtbl.insert([{'id':5, 'version':5}]) 99 | ot: partial({'errors':0, 'inserted':1}) 100 | - cd: fetch(vpluck, 1) 101 | ot: [{'new_val':{'version':5}}] 102 | -------------------------------------------------------------------------------- /spec/rql_test/src/datum/bool.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests of conversion to and from the RQL bool type 2 | tests: 3 | - py: r.expr(True) 4 | js: 5 | - r.expr(true) 6 | - r(true) 7 | rb: r true 8 | ot: true 9 | 10 | - py: r.expr(False) 11 | js: 12 | - r.expr(false) 13 | - r(false) 14 | rb: r false 15 | ot: false 16 | 17 | - cd: r.expr(False).type_of() 18 | ot: 'BOOL' 19 | 20 | # test coercions 21 | - cd: r.expr(True).coerce_to('string') 22 | ot: 'true' 23 | 24 | - cd: r.expr(True).coerce_to('bool') 25 | ot: True 26 | 27 | - cd: r.expr(False).coerce_to('bool') 28 | ot: False 29 | 30 | - cd: r.expr(null).coerce_to('bool') 31 | ot: False 32 | 33 | - cd: r.expr(0).coerce_to('bool') 34 | ot: True 35 | 36 | - cd: r.expr('false').coerce_to('bool') 37 | ot: True 38 | 39 | - cd: r.expr('foo').coerce_to('bool') 40 | ot: True 41 | 42 | - cd: r.expr([]).coerce_to('bool') 43 | ot: True 44 | 45 | - cd: r.expr({}).coerce_to('bool') 46 | ot: True 47 | 48 | -------------------------------------------------------------------------------- /spec/rql_test/src/datum/null.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests of conversion to and from the RQL null type 2 | tests: 3 | - cd: 4 | - r(null) 5 | - r.expr(null) 6 | py: r.expr(null) 7 | ot: (null) 8 | 9 | - cd: r.expr(null).type_of() 10 | rb: r(null).type_of() 11 | ot: 'NULL' 12 | 13 | # test coercions 14 | - cd: r.expr(null).coerce_to('string') 15 | ot: 'null' 16 | 17 | - cd: r.expr(null).coerce_to('null') 18 | ot: null 19 | -------------------------------------------------------------------------------- /spec/rql_test/src/datum/number.yaml: -------------------------------------------------------------------------------- 1 | # desc will be included in a comment to help identify test groups 2 | desc: Tests of conversion to and from the RQL number type 3 | tests: 4 | 5 | # Simple integers 6 | - cd: r.expr(1) 7 | js: 8 | - r(1) 9 | - r.expr(1) 10 | rb: 11 | - r 1 12 | - r(1) 13 | - r.expr(1) 14 | ot: 1 15 | - cd: r.expr(-1) 16 | js: 17 | - r(-1) 18 | - r.expr(-1) 19 | rb: 20 | - r -1 21 | - r(-1) 22 | - r.expr(-1) 23 | ot: -1 24 | - cd: r.expr(0) 25 | js: 26 | - r(0) 27 | - r.expr(0) 28 | rb: 29 | - r 0 30 | - r(0) 31 | - r.expr(0) 32 | ot: 0 33 | 34 | # Floats 35 | - cd: r.expr(1.0) 36 | js: 37 | - r(1.0) 38 | - r.expr(1.0) 39 | rb: 40 | - r 1.0 41 | - r(1.0) 42 | - r.expr(1.0) 43 | ot: 1.0 44 | - cd: r.expr(1.5) 45 | js: 46 | - r(1.5) 47 | - r.expr(1.5) 48 | rb: 49 | - r 1.5 50 | - r(1.5) 51 | - r.expr(1.5) 52 | ot: 1.5 53 | - cd: r.expr(-0.5) 54 | js: 55 | - r(-0.5) 56 | - r.expr(-0.5) 57 | rb: 58 | - r -0.5 59 | - r(-0.5) 60 | - r.expr(-0.5) 61 | ot: -0.5 62 | - cd: r.expr(67498.89278) 63 | js: 64 | - r(67498.89278) 65 | - r.expr(67498.89278) 66 | rb: 67 | - r 67498.89278 68 | - r(67498.89278) 69 | - r.expr(67498.89278) 70 | ot: 67498.89278 71 | 72 | # Big numbers 73 | - cd: r.expr(1234567890) 74 | js: 75 | - r(1234567890) 76 | - r.expr(1234567890) 77 | rb: 78 | - r 1234567890 79 | - r(1234567890) 80 | - r.expr(1234567890) 81 | ot: 1234567890 82 | 83 | - cd: r.expr(-73850380122423) 84 | js: 85 | - r.expr(-73850380122423) 86 | - r(-73850380122423) 87 | rb: 88 | - r -73850380122423 89 | - r.expr(-73850380122423) 90 | - r(-73850380122423) 91 | ot: -73850380122423 92 | 93 | # Test that numbers round-trip correctly 94 | - py: 95 | cd: r.expr(1234567890123456789012345678901234567890) 96 | ot: float(1234567890123456789012345678901234567890) 97 | js: 98 | cd: r.expr(1234567890123456789012345678901234567890) 99 | ot: 1234567890123456789012345678901234567890 100 | - cd: r.expr(123.4567890123456789012345678901234567890) 101 | ot: 123.4567890123456789012345678901234567890 102 | 103 | - cd: r.expr(1).type_of() 104 | ot: 'NUMBER' 105 | 106 | # test coercions 107 | - cd: r.expr(1).coerce_to('string') 108 | ot: '1' 109 | 110 | - cd: r.expr(1).coerce_to('number') 111 | ot: 1 112 | 113 | # The drivers now convert to an int (where relevant) if we think the result 114 | # looks like an int (result % 1.0 == 0.0) 115 | - py: r.expr(1.0) 116 | rb: r 1.0 117 | ot: int_cmp(1) 118 | 119 | - py: r.expr(45) 120 | rb: r 45 121 | ot: int_cmp(45) 122 | 123 | - py: r.expr(1.2) 124 | rb: r 1.2 125 | ot: float_cmp(1.2) 126 | -------------------------------------------------------------------------------- /spec/rql_test/src/datum/object.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests conversion to and from the RQL object type 2 | tests: 3 | - cd: 4 | - r({}) 5 | - r.expr({}) 6 | py: r.expr({}) 7 | ot: {} 8 | - cd: 9 | - r({a:1}) 10 | - r.expr({'a':1}) 11 | py: r.expr({'a':1}) 12 | ot: {'a':1} 13 | - cd: 14 | - r({a:1, b:'two', c:True}) 15 | - r.expr({'a':1, 'b':'two', 'c':True}) 16 | py: r.expr({'a':1, 'b':'two', 'c':True}) 17 | ot: {'a':1, 'b':'two', 'c':True} 18 | 19 | # Nested expressions 20 | - cd: r.expr({'a':r.expr(1)}) 21 | ot: {'a':1} 22 | 23 | - cd: r.expr({'a':{'b':[{'c':2}, 'a', 4]}}) 24 | ot: {'a':{'b':[{'c':2}, 'a', 4]}} 25 | 26 | - cd: r.expr({'a':1}).type_of() 27 | ot: 'OBJECT' 28 | 29 | # test coercions 30 | - cd: r.expr({'a':1}).coerce_to('string') 31 | ot: 32 | cd: '{"a":1}' 33 | 34 | - cd: r.expr({'a':1}).coerce_to('object') 35 | ot: {'a':1} 36 | 37 | - cd: r.expr({'a':1}).coerce_to('array') 38 | ot: [['a',1]] 39 | 40 | # Error cases 41 | - cd: r.expr({12:'a'}) 42 | # JavaScript auto-converts keys for us 43 | js: 44 | ot: err_regex("ReqlCompileError", "Object keys must be strings.*") 45 | 46 | - cd: r.expr({'a':{12:'b'}}) 47 | # JavaScript auto-converts keys for us 48 | js: 49 | ot: err_regex("ReqlCompileError", "Object keys must be strings.*") 50 | 51 | - js: r({'a':undefined}) 52 | ot: err("ReqlCompileError", "Object field 'a' may not be undefined") 53 | 54 | - js: r({'a':{'b':undefined}}) 55 | ot: err("ReqlCompileError", "Object field 'b' may not be undefined") 56 | 57 | - cd: r.expr({}, "foo") 58 | ot: 59 | cd: err("ReqlCompileError", "Second argument to `r.expr` must be a number.") 60 | js: err("ReqlCompileError", "Second argument to `r.expr` must be a number or undefined.") 61 | 62 | - js: r.expr({}, NaN) 63 | ot: err("ReqlCompileError", "Second argument to `r.expr` must be a number or undefined.") 64 | 65 | # r.object 66 | - cd: r.object() 67 | ot: {} 68 | 69 | - cd: r.object('a', 1, 'b', 2) 70 | ot: {'a':1,'b':2} 71 | 72 | - cd: r.object('c'+'d', 3) 73 | ot: {'cd':3} 74 | 75 | - cd: r.object('o','d','d') 76 | ot: err("ReqlQueryLogicError", "OBJECT expects an even number of arguments (but found 3).", []) 77 | 78 | - cd: r.object(1, 1) 79 | ot: err("ReqlQueryLogicError","Expected type STRING but found NUMBER.",[]) 80 | 81 | - cd: r.object('e', 4, 'e', 5) 82 | ot: err("ReqlQueryLogicError","Duplicate key \"e\" in object. (got 4 and 5 as values)",[]) 83 | 84 | - cd: r.object('g', r.db('test')) 85 | ot: err("ReqlQueryLogicError","Expected type DATUM but found DATABASE:",[]) 86 | -------------------------------------------------------------------------------- /spec/rql_test/src/datum/typeof.yaml: -------------------------------------------------------------------------------- 1 | desc: These tests test the type of command 2 | tests: 3 | 4 | # Method form 5 | - cd: r.expr(null).type_of() 6 | ot: 'NULL' 7 | 8 | # Prefix form 9 | - cd: r.type_of(null) 10 | ot: 'NULL' 11 | 12 | # Error cases 13 | - js: r(null).typeOf(1) 14 | ot: err('ReqlCompileError', 'Expected 1 argument but found 2.', [0]) 15 | -------------------------------------------------------------------------------- /spec/rql_test/src/datum/uuid.yaml: -------------------------------------------------------------------------------- 1 | desc: Test that UUIDs work 2 | tests: 3 | - cd: r.uuid() 4 | ot: uuid() 5 | - cd: r.expr(r.uuid()) 6 | ot: uuid() 7 | - cd: r.type_of(r.uuid()) 8 | ot: 'STRING' 9 | - cd: r.uuid().ne(r.uuid()) 10 | ot: true 11 | - cd: r.uuid('magic') 12 | ot: ('97dd10a5-4fc4-554f-86c5-0d2c2e3d5330') 13 | - cd: r.uuid('magic').eq(r.uuid('magic')) 14 | ot: true 15 | - cd: r.uuid('magic').ne(r.uuid('beans')) 16 | ot: true 17 | - py: r.expr([1,2,3,4,5,6,7,8,9,10]).map(lambda u:r.uuid()).distinct().count() 18 | js: r([1,2,3,4,5,6,7,8,9,10]).map(function(u) {return r.uuid();}).distinct().count() 19 | rb: r.expr([1,2,3,4,5,6,7,8,9,10]).map {|u| r.uuid()}.distinct().count() 20 | ot: 10 21 | -------------------------------------------------------------------------------- /spec/rql_test/src/geo/constructors.yaml: -------------------------------------------------------------------------------- 1 | desc: Test geo constructors 2 | tests: 3 | # Point 4 | - cd: r.point(0, 0) 5 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[0, 0], 'type':'Point'}) 6 | - cd: r.point(0, -90) 7 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[0, -90], 'type':'Point'}) 8 | - cd: r.point(0, 90) 9 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[0, 90], 'type':'Point'}) 10 | - cd: r.point(-180, 0) 11 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[-180, 0], 'type':'Point'}) 12 | - cd: r.point(180, 0) 13 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[180, 0], 'type':'Point'}) 14 | - cd: r.point(0, -91) 15 | ot: err('ReqlQueryLogicError', 'Latitude must be between -90 and 90. Got -91.', [0]) 16 | - cd: r.point(0, 91) 17 | ot: err('ReqlQueryLogicError', 'Latitude must be between -90 and 90. Got 91.', [0]) 18 | - cd: r.point(-181, 0) 19 | ot: err('ReqlQueryLogicError', 'Longitude must be between -180 and 180. Got -181.', [0]) 20 | - cd: r.point(181, 0) 21 | ot: err('ReqlQueryLogicError', 'Longitude must be between -180 and 180. Got 181.', [0]) 22 | 23 | # Line 24 | - cd: r.line() 25 | ot: err('ReqlCompileError', 'Expected 2 or more arguments but found 0.', [0]) 26 | - cd: r.line([0,0]) 27 | ot: err('ReqlCompileError', 'Expected 2 or more arguments but found 1.', [0]) 28 | - cd: r.line([0,0], [0,0]) 29 | ot: err('ReqlQueryLogicError', 'Invalid LineString. Are there antipodal or duplicate vertices?', [0]) 30 | - cd: r.line([0,0], [0,1]) 31 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[0,0], [0,1]], 'type':'LineString'}) 32 | - cd: r.line([0,0], [1]) 33 | ot: err('ReqlQueryLogicError', 'Expected point coordinate pair. Got 1 element array instead of a 2 element one.', [0]) 34 | - cd: r.line([0,0], [1,0,0]) 35 | ot: err('ReqlQueryLogicError', 'Expected point coordinate pair. Got 3 element array instead of a 2 element one.', [0]) 36 | - cd: r.line([0,0], [0,1], [0,0]) 37 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[0,0], [0,1], [0,0]], 'type':'LineString'}) 38 | - cd: r.line(r.point(0,0), r.point(0,1), r.point(0,0)) 39 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[0,0], [0,1], [0,0]], 'type':'LineString'}) 40 | - cd: r.line(r.point(0,0), r.point(1,0), r.line([0,0], [1,0])) 41 | ot: err('ReqlQueryLogicError', 'Expected geometry of type `Point` but found `LineString`.', [0]) 42 | 43 | # Polygon 44 | - cd: r.polygon() 45 | ot: err('ReqlCompileError', 'Expected 3 or more arguments but found 0.', [0]) 46 | - cd: r.polygon([0,0]) 47 | ot: err('ReqlCompileError', 'Expected 3 or more arguments but found 1.', [0]) 48 | - cd: r.polygon([0,0], [0,0]) 49 | ot: err('ReqlCompileError', 'Expected 3 or more arguments but found 2.', [0]) 50 | - cd: r.polygon([0,0], [0,0], [0,0], [0,0]) 51 | ot: err('ReqlQueryLogicError', 'Invalid LinearRing. Are there antipodal or duplicate vertices? Is it self-intersecting?', [0]) 52 | - cd: r.polygon([0,0], [0,1], [1,0]) 53 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[[0,0], [0,1], [1,0], [0,0]]], 'type':'Polygon'}) 54 | - cd: r.polygon([0,0], [0,1], [1,0], [0,0]) 55 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[[0,0], [0,1], [1,0], [0,0]]], 'type':'Polygon'}) 56 | - cd: r.polygon([0,0], [0,1], [1,0], [-1,0.5]) 57 | ot: err('ReqlQueryLogicError', 'Invalid LinearRing. Are there antipodal or duplicate vertices? Is it self-intersecting?', [0]) 58 | - cd: r.polygon([0,0], [0,1], [0]) 59 | ot: err('ReqlQueryLogicError', 'Expected point coordinate pair. Got 1 element array instead of a 2 element one.', [0]) 60 | - cd: r.polygon([0,0], [0,1], [0,1,0]) 61 | ot: err('ReqlQueryLogicError', 'Expected point coordinate pair. Got 3 element array instead of a 2 element one.', [0]) 62 | - cd: r.polygon(r.point(0,0), r.point(0,1), r.line([0,0], [0,1])) 63 | ot: err('ReqlQueryLogicError', 'Expected geometry of type `Point` but found `LineString`.', [0]) 64 | 65 | -------------------------------------------------------------------------------- /spec/rql_test/src/geo/geojson.yaml: -------------------------------------------------------------------------------- 1 | desc: Test geoJSON conversion 2 | tests: 3 | # Basic conversion 4 | - cd: r.geojson({'coordinates':[0, 0], 'type':'Point'}) 5 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[0, 0], 'type':'Point'}) 6 | - cd: r.geojson({'coordinates':[[0,0], [0,1]], 'type':'LineString'}) 7 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[0,0], [0,1]], 'type':'LineString'}) 8 | - cd: r.geojson({'coordinates':[[[0,0], [0,1], [1,0], [0,0]]], 'type':'Polygon'}) 9 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[[0,0], [0,1], [1,0], [0,0]]], 'type':'Polygon'}) 10 | 11 | # Wrong / missing fields 12 | - cd: r.geojson({'coordinates':[[], 0], 'type':'Point'}) 13 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found ARRAY.', [0]) 14 | - cd: r.geojson({'coordinates':true, 'type':'Point'}) 15 | ot: err('ReqlQueryLogicError', 'Expected type ARRAY but found BOOL.', [0]) 16 | - cd: r.geojson({'type':'Point'}) 17 | ot: err('ReqlNonExistenceError', 'No attribute `coordinates` in object:', [0]) 18 | - cd: r.geojson({'coordinates':[0, 0]}) 19 | ot: err('ReqlNonExistenceError', 'No attribute `type` in object:', [0]) 20 | - cd: r.geojson({'coordinates':[0, 0], 'type':'foo'}) 21 | ot: err('ReqlQueryLogicError', 'Unrecognized GeoJSON type `foo`.', [0]) 22 | - cd: r.geojson({'coordinates':[0, 0], 'type':'Point', 'foo':'wrong'}) 23 | ot: err('ReqlQueryLogicError', 'Unrecognized field `foo` found in geometry object.', [0]) 24 | 25 | # Unsupported features 26 | - cd: r.geojson({'coordinates':[0, 0], 'type':'Point', 'crs':null}) 27 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[0, 0], 'type':'Point', 'crs':null}) 28 | - js: r.geojson({'coordinates':[0, 0], 'type':'Point', 'crs':{'type':'name', 'properties':{'name':'test'}}}) 29 | ot: err('ReqlQueryLogicError', 'Non-default coordinate reference systems are not supported in GeoJSON objects. Make sure the `crs` field of the geometry is null or non-existent.', [0]) 30 | - cd: r.geojson({'coordinates':[0, 0], 'type':'MultiPoint'}) 31 | ot: err('ReqlQueryLogicError', 'GeoJSON type `MultiPoint` is not supported.', [0]) 32 | -------------------------------------------------------------------------------- /spec/rql_test/src/geo/primitives.yaml: -------------------------------------------------------------------------------- 1 | desc: Test geometric primitive constructors 2 | tests: 3 | # Circle 4 | - js: r.circle([0,0], 1, {num_vertices:3}) 5 | py: r.circle([0,0], 1, num_vertices=3) 6 | rb: r.circle([0,0], 1, :num_vertices=>3) 7 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[[0, -9.04369477050382e-06], [-7.779638566553426e-06, 4.5218473852518965e-06], [7.779638566553426e-06, 4.5218473852518965e-06], [0, -9.04369477050382e-06]]], 'type':'Polygon'}) 8 | 9 | - js: r.circle(r.point(0,0), 1, {num_vertices:3}) 10 | py: r.circle(r.point(0,0), 1, num_vertices=3) 11 | rb: r.circle(r.point(0,0), 1, :num_vertices=>3) 12 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[[0, -9.04369477050382e-06], [-7.779638566553426e-06, 4.5218473852518965e-06], [7.779638566553426e-06, 4.5218473852518965e-06], [0, -9.04369477050382e-06]]], 'type':'Polygon'}) 13 | 14 | - js: r.circle([0,0], 1, {num_vertices:3, fill:false}) 15 | py: r.circle([0,0], 1, num_vertices=3, fill=false) 16 | rb: r.circle([0,0], 1, :num_vertices=>3, :fill=>false) 17 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[0, -9.04369477050382e-06], [-7.779638566553426e-06, 4.5218473852518965e-06], [7.779638566553426e-06, 4.5218473852518965e-06], [0, -9.04369477050382e-06]], 'type':'LineString'}) 18 | 19 | - js: r.circle([0,0], 14000000, {num_vertices:3}) 20 | py: r.circle([0,0], 14000000, num_vertices=3) 21 | rb: r.circle([0,0], 14000000, :num_vertices=>3) 22 | ot: err('ReqlQueryLogicError', 'Radius must be smaller than a quarter of the circumference along the minor axis of the reference ellipsoid. Got 14000000m, but must be smaller than 9985163.1855612862855m.', [0]) 23 | 24 | - js: r.circle([0,0], 1, {num_vertices:3, geo_system:'WGS84'}) 25 | py: r.circle([0,0], 1, num_vertices=3, geo_system='WGS84') 26 | rb: r.circle([0,0], 1, :num_vertices=>3, :geo_system=>'WGS84') 27 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[[0, -9.04369477050382e-06], [-7.779638566553426e-06, 4.5218473852518965e-06], [7.779638566553426e-06, 4.5218473852518965e-06], [0, -9.04369477050382e-06]]], 'type':'Polygon'}) 28 | 29 | - js: r.circle([0,0], 2, {num_vertices:3, geo_system:'unit_'+'sphere'}) 30 | py: r.circle([0,0], 2, num_vertices=3, geo_system='unit_sphere') 31 | rb: r.circle([0,0], 2, :num_vertices=>3, :geo_system=>'unit_sphere') 32 | ot: err('ReqlQueryLogicError', 'Radius must be smaller than a quarter of the circumference along the minor axis of the reference ellipsoid. Got 2m, but must be smaller than 1.570796326794896558m.', [0]) 33 | 34 | - js: r.circle([0,0], 0.1, {num_vertices:3, geo_system:'unit_'+'sphere'}) 35 | py: r.circle([0,0], 0.1, num_vertices=3, geo_system='unit_sphere') 36 | rb: r.circle([0,0], 0.1, :num_vertices=>3, :geo_system=>'unit_sphere') 37 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[[0, -5.729577951308232], [-4.966092947444857, 2.861205754495701], [4.966092947444857, 2.861205754495701], [0, -5.729577951308232]]], 'type':'Polygon'}) 38 | testopts: 39 | precision: 0.0000000000001 40 | 41 | - js: r.circle([0,0], 1.0/1000.0, {num_vertices:3, unit:'km'}) 42 | py: r.circle([0,0], 1.0/1000.0, num_vertices=3, unit='km') 43 | rb: r.circle([0,0], 1.0/1000.0, :num_vertices=>3, :unit=>'km') 44 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[[0, -9.04369477050382e-06], [-7.779638566553426e-06, 4.5218473852518965e-06], [7.779638566553426e-06, 4.5218473852518965e-06], [0, -9.04369477050382e-06]]], 'type':'Polygon'}) 45 | 46 | - js: r.circle([0,0], 1.0/1609.344, {num_vertices:3, unit:'mi'}) 47 | py: r.circle([0,0], 1.0/1609.344, num_vertices=3, unit='mi') 48 | rb: r.circle([0,0], 1.0/1609.344, :num_vertices=>3, :unit=>'mi') 49 | ot: ({'$reql_type$':'GEOMETRY', 'coordinates':[[[0, -9.04369477050382e-06], [-7.779638566553426e-06, 4.5218473852518965e-06], [7.779638566553426e-06, 4.5218473852518965e-06], [0, -9.04369477050382e-06]]], 'type':'Polygon'}) 50 | 51 | -------------------------------------------------------------------------------- /spec/rql_test/src/json.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests RQL json parsing 2 | tests: 3 | 4 | - cd: r.json("[1,2,3]") 5 | ot: [1,2,3] 6 | 7 | - cd: r.json("1") 8 | ot: 1 9 | 10 | - cd: r.json("{}") 11 | ot: {} 12 | 13 | - cd: r.json('"foo"') 14 | ot: "foo" 15 | 16 | - cd: r.json("[1,2") 17 | ot: err("ReqlQueryLogicError", 'Failed to parse "[1,2" as JSON:' + ' Missing a comma or \']\' after an array element.', [0]) 18 | 19 | - cd: r.json("[1,2,3]").to_json_string() 20 | ot: '[1,2,3]' 21 | 22 | - js: r.json("[1,2,3]").toJSON() 23 | py: r.json("[1,2,3]").to_json() 24 | ot: '[1,2,3]' 25 | 26 | - cd: r.json("{\"foo\":4}").to_json_string() 27 | ot: '{"foo":4}' 28 | 29 | - js: r.json("{\"foo\":4}").toJSON() 30 | py: r.json("{\"foo\":4}").to_json() 31 | ot: '{"foo":4}' 32 | 33 | # stress test: data is from http://www.mockaroo.com/ 34 | - def: text = '[{"id":1,"first_name":"Harry","last_name":"Riley","email":"hriley0@usgs.gov","country":"Andorra","ip_address":"221.25.65.136"},{"id":2,"first_name":"Bonnie","last_name":"Anderson","email":"banderson1@list-manage.com","country":"Tuvalu","ip_address":"116.162.43.150"},{"id":3,"first_name":"Marie","last_name":"Schmidt","email":"mschmidt2@diigo.com","country":"Iraq","ip_address":"181.105.59.57"},{"id":4,"first_name":"Phillip","last_name":"Willis","email":"pwillis3@com.com","country":"Montenegro","ip_address":"24.223.139.156"}]' 35 | - def: sorted = '[{"country":"Andorra","email":"hriley0@usgs.gov","first_name":"Harry","id":1,"ip_address":"221.25.65.136","last_name":"Riley"},{"country":"Tuvalu","email":"banderson1@list-manage.com","first_name":"Bonnie","id":2,"ip_address":"116.162.43.150","last_name":"Anderson"},{"country":"Iraq","email":"mschmidt2@diigo.com","first_name":"Marie","id":3,"ip_address":"181.105.59.57","last_name":"Schmidt"},{"country":"Montenegro","email":"pwillis3@com.com","first_name":"Phillip","id":4,"ip_address":"24.223.139.156","last_name":"Willis"}]' 36 | 37 | - cd: r.json(text).to_json_string() 38 | ot: sorted 39 | 40 | - cd: r.expr(r.minval).to_json_string() 41 | ot: err('ReqlQueryLogicError', 'Cannot convert `r.minval` to JSON.') 42 | 43 | - cd: r.expr(r.maxval).to_json_string() 44 | ot: err('ReqlQueryLogicError', 'Cannot convert `r.maxval` to JSON.') 45 | 46 | - cd: r.expr(r.minval).coerce_to('string') 47 | ot: err('ReqlQueryLogicError', 'Cannot convert `r.minval` to JSON.') 48 | 49 | - cd: r.expr(r.maxval).coerce_to('string') 50 | ot: err('ReqlQueryLogicError', 'Cannot convert `r.maxval` to JSON.') 51 | 52 | - cd: r.time(2014,9,11, 'Z') 53 | runopts: 54 | time_format: 'raw' 55 | ot: {'timezone':'+00:00','$reql_type$':'TIME','epoch_time':1410393600} 56 | 57 | - cd: r.time(2014,9,11, 'Z').to_json_string() 58 | ot: '{"$reql_type$":"TIME","epoch_time":1410393600,"timezone":"+00:00"}' 59 | 60 | - cd: r.point(0,0) 61 | ot: {'$reql_type$':'GEOMETRY','coordinates':[0,0],'type':'Point'} 62 | 63 | - cd: r.point(0,0).to_json_string() 64 | ot: '{"$reql_type$":"GEOMETRY","coordinates":[0,0],"type":"Point"}' 65 | 66 | - def: 67 | rb: s = "\x66\x6f\x6f".force_encoding('BINARY') 68 | py: s = b'\x66\x6f\x6f' 69 | js: s = Buffer("\x66\x6f\x6f", 'binary') 70 | - cd: r.binary(s) 71 | ot: s 72 | 73 | - cd: r.expr("foo").coerce_to("binary").to_json_string() 74 | ot: '{"$reql_type$":"BINARY","data":"Zm9v"}' 75 | -------------------------------------------------------------------------------- /spec/rql_test/src/limits.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests array limit variations 2 | table_variable_name: tbl 3 | tests: 4 | 5 | # test simplistic array limits 6 | - cd: r.expr([1,1,1,1]).union([1, 1, 1, 1]) 7 | runopts: 8 | array_limit: 8 9 | ot: [1,1,1,1,1,1,1,1] 10 | - cd: r.expr([1,2,3,4]).union([5, 6, 7, 8]) 11 | runopts: 12 | array_limit: 4 13 | ot: err("ReqlResourceLimitError", "Array over size limit `4`.", [0]) 14 | 15 | # test array limits on query creation 16 | - cd: r.expr([1,2,3,4,5,6,7,8]) 17 | runopts: 18 | array_limit: 4 19 | ot: err("ReqlResourceLimitError", "Array over size limit `4`.", [0]) 20 | 21 | # test bizarre array limits 22 | - cd: r.expr([1,2,3,4,5,6,7,8]) 23 | runopts: 24 | array_limit: -1 25 | ot: err("ReqlQueryLogicError", "Illegal array size limit `-1`. (Must be >= 1.)", []) 26 | 27 | - cd: r.expr([1,2,3,4,5,6,7,8]) 28 | runopts: 29 | array_limit: 0 30 | ot: err("ReqlQueryLogicError", "Illegal array size limit `0`. (Must be >= 1.)", []) 31 | 32 | # make enormous > 100,000 element array 33 | - def: ten_l = r.expr([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 34 | - def: 35 | js: ten_f = function(l) { return ten_l } 36 | py: ten_f = lambda l:list(range(1,11)) 37 | - def: 38 | js: huge_l = r.expr(ten_l).concatMap(ten_f).concatMap(ten_f).concatMap(ten_f).concatMap(ten_f) 39 | py: huge_l = r.expr(ten_l).concat_map(ten_f).concat_map(ten_f).concat_map(ten_f).concat_map(ten_f) 40 | rb: huge_l = r.expr(ten_l).concat_map {|l| ten_l}.concat_map {|l| ten_l}.concat_map {|l| ten_l}.concat_map {|l| ten_l} 41 | - cd: huge_l.append(1).count() 42 | runopts: 43 | array_limit: 100001 44 | ot: 100001 45 | 46 | # attempt to insert enormous array 47 | - cd: tbl.insert({'id':0, 'array':huge_l.append(1)}) 48 | runopts: 49 | array_limit: 100001 50 | ot: partial({'errors':1, 'first_error':"Array too large for disk writes (limit 100,000 elements)."}) 51 | 52 | - cd: tbl.get(0) 53 | runopts: 54 | array_limit: 100001 55 | ot: (null) 56 | 57 | # attempt to read array that violates limit from disk 58 | - cd: tbl.insert({'id':1, 'array':ten_l}) 59 | ot: ({'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1}) 60 | - cd: tbl.get(1) 61 | runopts: 62 | array_limit: 4 63 | ot: ({'array':[1,2,3,4,5,6,7,8,9,10],'id':1}) 64 | 65 | 66 | # Test that the changefeed queue size actually causes changes to be sent early. 67 | - cd: tbl.delete().get_field('deleted') 68 | ot: 1 69 | 70 | - cd: c = tbl.changes({squash:1000000, changefeed_queue_size:10}) 71 | py: c = tbl.changes(squash=1000000, changefeed_queue_size=10) 72 | 73 | - cd: tbl.insert([{'id':0}, {'id':1}, {'id':2}, {'id':3}, {'id':4}, {'id':5}, {'id':6}]).get_field('inserted') 74 | ot: 7 75 | - py: fetch(c, 7) 76 | rb: fetch(c, 7) 77 | ot: bag([{'old_val':null, 'new_val':{'id':0}}, 78 | {'old_val':null, 'new_val':{'id':1}}, 79 | {'old_val':null, 'new_val':{'id':2}}, 80 | {'old_val':null, 'new_val':{'id':3}}, 81 | {'old_val':null, 'new_val':{'id':4}}, 82 | {'old_val':null, 'new_val':{'id':5}}, 83 | {'old_val':null, 'new_val':{'id':6}}]) 84 | 85 | - cd: tbl.insert([{'id':7}, {'id':8}, {'id':9}, {'id':10}, {'id':11}, {'id':12}, {'id':13}]).get_field('inserted') 86 | ot: 7 87 | - py: fetch(c, 7) 88 | rb: fetch(c, 7) 89 | ot: bag([{'old_val':null, 'new_val':{'id':7}}, 90 | {'old_val':null, 'new_val':{'id':8}}, 91 | {'old_val':null, 'new_val':{'id':9}}, 92 | {'old_val':null, 'new_val':{'id':10}}, 93 | {'old_val':null, 'new_val':{'id':11}}, 94 | {'old_val':null, 'new_val':{'id':12}}, 95 | {'old_val':null, 'new_val':{'id':13}}]) 96 | 97 | - cd: tbl.delete().get_field('deleted') 98 | ot: 14 99 | 100 | - cd: c2 = tbl.changes({squash:1000000}) 101 | py: c2 = tbl.changes(squash=1000000) 102 | runopts: 103 | changefeed_queue_size: 10 104 | 105 | 106 | - cd: tbl.insert([{'id':0}, {'id':1}, {'id':2}, {'id':3}, {'id':4}, {'id':5}, {'id':6}]).get_field('inserted') 107 | ot: 7 108 | - py: fetch(c2, 7) 109 | rb: fetch(c2, 7) 110 | ot: bag([{'old_val':null, 'new_val':{'id':0}}, 111 | {'old_val':null, 'new_val':{'id':1}}, 112 | {'old_val':null, 'new_val':{'id':2}}, 113 | {'old_val':null, 'new_val':{'id':3}}, 114 | {'old_val':null, 'new_val':{'id':4}}, 115 | {'old_val':null, 'new_val':{'id':5}}, 116 | {'old_val':null, 'new_val':{'id':6}}]) 117 | 118 | - cd: tbl.insert([{'id':7}, {'id':8}, {'id':9}, {'id':10}, {'id':11}, {'id':12}, {'id':13}]).get_field('inserted') 119 | ot: 7 120 | - py: fetch(c2, 7) 121 | rb: fetch(c2, 7) 122 | ot: bag([{'old_val':null, 'new_val':{'id':7}}, 123 | {'old_val':null, 'new_val':{'id':8}}, 124 | {'old_val':null, 'new_val':{'id':9}}, 125 | {'old_val':null, 'new_val':{'id':10}}, 126 | {'old_val':null, 'new_val':{'id':11}}, 127 | {'old_val':null, 'new_val':{'id':12}}, 128 | {'old_val':null, 'new_val':{'id':13}}]) 129 | -------------------------------------------------------------------------------- /spec/rql_test/src/match.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests for match 2 | table_variable_name: tbl 3 | tests: 4 | - cd: r.expr("abcdefg").match("a(b.e)|b(c.e)") 5 | ot: ({'str':'bcde','groups':[null,{'start':2,'str':'cde','end':5}],'start':1,'end':5}) 6 | - cd: r.expr("abcdefg").match("a(b.e)|B(c.e)") 7 | ot: (null) 8 | - cd: r.expr("abcdefg").match("(?i)a(b.e)|B(c.e)") 9 | ot: ({'str':'bcde','groups':[null,{'start':2,'str':'cde','end':5}],'start':1,'end':5}) 10 | 11 | - cd: r.expr(["aba", "aca", "ada", "aea"]).filter{|row| row.match("a(.)a")[:groups][0][:str].match("[cd]")} 12 | py: r.expr(["aba", "aca", "ada", "aea"]).filter(lambda row:row.match("a(.)a")['groups'][0]['str'].match("[cd]")) 13 | js: r.expr(["aba", "aca", "ada", "aea"]).filter(function(row){return row.match("a(.)a")('groups').nth(0)('str').match("[cd]")}) 14 | ot: (["aca", "ada"]) 15 | 16 | - cd: tbl.insert([{'id':0,'a':'abc'},{'id':1,'a':'ab'},{'id':2,'a':'bc'}]) 17 | ot: ({'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':3}) 18 | 19 | - cd: tbl.filter{|row| row['a'].match('b')}.orderby('id') 20 | py: tbl.filter(lambda row:row['a'].match('b')).order_by('id') 21 | js: tbl.filter(function(row){return row('a').match('b')}).order_by('id') 22 | ot: ([{'id':0,'a':'abc'},{'id':1,'a':'ab'},{'id':2,'a':'bc'}]) 23 | - cd: tbl.filter{|row| row['a'].match('ab')}.orderby('id') 24 | py: tbl.filter(lambda row:row['a'].match('ab')).order_by('id') 25 | js: tbl.filter(function(row){return row('a').match('ab')}).order_by('id') 26 | ot: ([{'id':0,'a':'abc'},{'id':1,'a':'ab'}]) 27 | - cd: tbl.filter{|row| row['a'].match('ab$')}.orderby('id') 28 | py: tbl.filter(lambda row:row['a'].match('ab$')).order_by('id') 29 | js: tbl.filter(function(row){return row('a').match('ab$')}).order_by('id') 30 | ot: ([{'id':1,'a':'ab'}]) 31 | - cd: tbl.filter{|row| row['a'].match('^b$')}.orderby('id') 32 | py: tbl.filter(lambda row:row['a'].match('^b$')).order_by('id') 33 | js: tbl.filter(function(row){return row('a').match('^b$')}).order_by('id') 34 | ot: ([]) 35 | 36 | - cd: r.expr("").match("ab\\9") 37 | ot: | 38 | err("ReqlQueryLogicError", "Error in regexp `ab\\9` (portion `\\9`): invalid escape sequence: \\9", []) 39 | -------------------------------------------------------------------------------- /spec/rql_test/src/math_logic/add.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests for basic usage of the add operation 2 | tests: 3 | - cd: r.add(1, 1) 4 | ot: 2 5 | 6 | - js: r(1).add(1) 7 | py: 8 | - r.expr(1) + 1 9 | - 1 + r.expr(1) 10 | - r.expr(1).add(1) 11 | rb: 12 | - r(1) + 1 13 | - r(1).add(1) 14 | ot: 2 15 | 16 | - py: r.expr(-1) + 1 17 | js: r(-1).add(1) 18 | rb: (r -1) + 1 19 | ot: 0 20 | 21 | - py: r.expr(1.75) + 8.5 22 | js: r(1.75).add(8.5) 23 | rb: (r 1.75) + 8.5 24 | ot: 10.25 25 | 26 | # Add is polymorphic on strings 27 | - py: r.expr('') + '' 28 | js: r('').add('') 29 | rb: (r '') + '' 30 | ot: '' 31 | 32 | - py: r.expr('abc') + 'def' 33 | js: r('abc').add('def') 34 | rb: (r 'abc') + 'def' 35 | ot: 'abcdef' 36 | 37 | # Add is polymorphic on arrays 38 | - cd: r.expr([1,2]) + [3] + [4,5] + [6,7,8] 39 | js: r([1,2]).add([3]).add([4,5]).add([6,7,8]) 40 | ot: [1,2,3,4,5,6,7,8] 41 | 42 | # All arithmetic operations (except mod) actually support arbitrary arguments 43 | # but this feature can't be accessed in Python because it's operators are binary 44 | - js: r(1).add(2,3,4,5) 45 | ot: 15 46 | 47 | - js: r('a').add('b', 'c', 'd') 48 | ot: 'abcd' 49 | 50 | # Type errors 51 | - cd: r(1).add('a') 52 | py: r.expr(1) + 'a' 53 | rb: r(1) + 'a' 54 | ot: err("ReqlQueryLogicError", "Expected type NUMBER but found STRING.", [1]) 55 | 56 | - cd: r('a').add(1) 57 | py: r.expr('a') + 1 58 | rb: r('a') + 1 59 | ot: err("ReqlQueryLogicError", "Expected type STRING but found NUMBER.", [1]) 60 | 61 | - cd: r([]).add(1) 62 | py: r.expr([]) + 1 63 | rb: r([]) + 1 64 | ot: err("ReqlQueryLogicError", "Expected type ARRAY but found NUMBER.", [1]) 65 | 66 | -------------------------------------------------------------------------------- /spec/rql_test/src/math_logic/aliases.yaml: -------------------------------------------------------------------------------- 1 | desc: Test named aliases for math and logic operators 2 | tests: 3 | 4 | - cd: 5 | - r.expr(0).add(1) 6 | - r.add(0, 1) 7 | - r.expr(2).sub(1) 8 | - r.sub(2, 1) 9 | - r.expr(2).div(2) 10 | - r.div(2, 2) 11 | - r.expr(1).mul(1) 12 | - r.mul(1, 1) 13 | - r.expr(1).mod(2) 14 | - r.mod(1, 2) 15 | ot: 1 16 | 17 | - cd: 18 | - r.expr(True).and(True) 19 | - r.expr(True).or(True) 20 | - r.and(True, True) 21 | - r.or(True, True) 22 | - r.expr(False).not() 23 | - r.not(False) 24 | py: 25 | - r.expr(True).and_(True) 26 | - r.expr(True).or_(True) 27 | - r.and_(True, True) 28 | - r.or_(True, True) 29 | - r.expr(False).not_() 30 | - r.not_(False) 31 | ot: True 32 | 33 | - cd: 34 | - r.expr(1).eq(1) 35 | - r.expr(1).ne(2) 36 | - r.expr(1).lt(2) 37 | - r.expr(1).gt(0) 38 | - r.expr(1).le(1) 39 | - r.expr(1).ge(1) 40 | - r.eq(1, 1) 41 | - r.ne(1, 2) 42 | - r.lt(1, 2) 43 | - r.gt(1, 0) 44 | - r.le(1, 1) 45 | - r.ge(1, 1) 46 | ot: True 47 | -------------------------------------------------------------------------------- /spec/rql_test/src/math_logic/div.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests for the basic usage of the division operation 2 | tests: 3 | 4 | - cd: r(4).div(2) 5 | py: 6 | - r.expr(4) / 2 7 | - 4 / r.expr(2) 8 | - r.expr(4).div(2) 9 | rb: 10 | - (r 4) / 2 11 | - r(4).div 2 12 | - 4 / r(2) 13 | ot: 2 14 | 15 | - py: r.expr(-1) / -2 16 | js: r(-1).div(-2) 17 | rb: (r -1) / -2 18 | ot: 0.5 19 | 20 | - py: r.expr(4.9) / 0.7 21 | js: r(4.9).div(0.7) 22 | rb: (r 4.9) / 0.7 23 | ot: 4.9 / 0.7 24 | 25 | - cd: r.expr(1).div(2,3,4,5) 26 | ot: 1.0/120 27 | 28 | # Divide by zero test 29 | - cd: 30 | - r(1).div(0) 31 | - r(2.0).div(0) 32 | - r(3).div(0.0) 33 | - r(4.0).div(0.0) 34 | - r(0).div(0) 35 | - r(0.0).div(0.0) 36 | py: 37 | - r.expr(1) / 0 38 | - r.expr(2.0) / 0 39 | - r.expr(3) / 0.0 40 | - r.expr(4.0) / 0.0 41 | - r.expr(0) / 0 42 | - r.expr(0.0) / 0.0 43 | ot: err('ReqlQueryLogicError', 'Cannot divide by zero.', [1]) 44 | 45 | # Type errors 46 | - py: r.expr('a') / 0.8 47 | cd: r('a').div(0.8) 48 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [0]) 49 | 50 | - py: r.expr(1) / 'a' 51 | cd: r(1).div('a') 52 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [1]) 53 | -------------------------------------------------------------------------------- /spec/rql_test/src/math_logic/floor_ceil_round.yaml: -------------------------------------------------------------------------------- 1 | desc: tests for `floor`, `ceil`, and `round`, tests inspired by the Python test suite 2 | tests: 3 | - cd: r.floor(1.0).type_of() 4 | ot: "NUMBER" 5 | - cd: r.floor(1.0) 6 | ot: 1.0 7 | - cd: r.expr(1.0).floor() 8 | ot: 1.0 9 | 10 | - cd: r.floor(0.5) 11 | ot: 0.0 12 | - cd: r.floor(1.0) 13 | ot: 1.0 14 | - cd: r.floor(1.5) 15 | ot: 1.0 16 | - cd: r.floor(-0.5) 17 | ot: -1.0 18 | - cd: r.floor(-1.0) 19 | ot: -1.0 20 | - cd: r.floor(-1.5) 21 | ot: -2.0 22 | 23 | - cd: r.expr('X').floor() 24 | ot: err("ReqlQueryLogicError", "Expected type NUMBER but found STRING.", []) 25 | 26 | 27 | - cd: r.ceil(1.0).type_of() 28 | ot: "NUMBER" 29 | - cd: r.ceil(1.0) 30 | ot: 1.0 31 | - cd: r.expr(1.0).ceil() 32 | ot: 1.0 33 | 34 | - cd: r.ceil(0.5) 35 | ot: 1.0 36 | - cd: r.ceil(1.0) 37 | ot: 1.0 38 | - cd: r.ceil(1.5) 39 | ot: 2.0 40 | - cd: r.ceil(-0.5) 41 | ot: 0.0 42 | - cd: r.ceil(-1.0) 43 | ot: -1.0 44 | - cd: r.ceil(-1.5) 45 | ot: -1.0 46 | 47 | - cd: r.expr('X').ceil() 48 | ot: err("ReqlQueryLogicError", "Expected type NUMBER but found STRING.", []) 49 | 50 | 51 | - cd: r.round(1.0).type_of() 52 | ot: "NUMBER" 53 | - cd: r.round(1.0) 54 | ot: 1.0 55 | - cd: r.expr(1.0).round() 56 | ot: 1.0 57 | 58 | - cd: r.round(0.5) 59 | ot: 1.0 60 | - cd: r.round(-0.5) 61 | ot: -1.0 62 | 63 | - cd: r.round(0.0) 64 | ot: 0.0 65 | - cd: r.round(1.0) 66 | ot: 1.0 67 | - cd: r.round(10.0) 68 | ot: 10.0 69 | - cd: r.round(1000000000.0) 70 | ot: 1000000000.0 71 | - cd: r.round(1e20) 72 | ot: 1e20 73 | 74 | - cd: r.round(-1.0) 75 | ot: -1.0 76 | - cd: r.round(-10.0) 77 | ot: -10.0 78 | - cd: r.round(-1000000000.0) 79 | ot: -1000000000.0 80 | - cd: r.round(-1e20) 81 | ot: -1e20 82 | 83 | - cd: r.round(0.1) 84 | ot: 0.0 85 | - cd: r.round(1.1) 86 | ot: 1.0 87 | - cd: r.round(10.1) 88 | ot: 10.0 89 | - cd: r.round(1000000000.1) 90 | ot: 1000000000.0 91 | 92 | - cd: r.round(-1.1) 93 | ot: -1.0 94 | - cd: r.round(-10.1) 95 | ot: -10.0 96 | - cd: r.round(-1000000000.1) 97 | ot: -1000000000.0 98 | 99 | - cd: r.round(0.9) 100 | ot: 1.0 101 | - cd: r.round(9.9) 102 | ot: 10.0 103 | - cd: r.round(999999999.9) 104 | ot: 1000000000.0 105 | 106 | - cd: r.round(-0.9) 107 | ot: -1.0 108 | - cd: r.round(-9.9) 109 | ot: -10.0 110 | - cd: r.round(-999999999.9) 111 | ot: -1000000000.0 112 | 113 | - cd: r.expr('X').round() 114 | ot: err("ReqlQueryLogicError", "Expected type NUMBER but found STRING.", []) 115 | -------------------------------------------------------------------------------- /spec/rql_test/src/math_logic/math.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests of nested arithmetic expressions 2 | tests: 3 | 4 | - py: (((4 + 2 * (r.expr(26) % 18)) / 5) - 3) 5 | js: r(4).add(r(2).mul(r(26).mod(18))).div(5).sub(3) 6 | rb: 7 | - ((((r 4) + (r 2) * ((r 26) % 18)) / 5) -3) 8 | - (((4 + 2 * ((r 26) % 18)) / 5) -3) 9 | ot: 1 10 | 11 | # Prescedence set by host langauge 12 | -------------------------------------------------------------------------------- /spec/rql_test/src/math_logic/mod.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests for the basic usage of the mod operation 2 | tests: 3 | 4 | - cd: r.expr(10).mod(3) 5 | py: 6 | - r.expr(10) % 3 7 | - 10 % r.expr(3) 8 | - r.expr(10).mod(3) 9 | rb: 10 | - (r 10) % 3 11 | - r(10).mod 3 12 | - 10 % (r 3) 13 | ot: 1 14 | 15 | - cd: r.expr(-10).mod(-3) 16 | py: r.expr(-10) % -3 17 | rb: (r -10) % -3 18 | ot: -1 19 | 20 | # Type errors 21 | - cd: r.expr(4).mod('a') 22 | py: r.expr(4) % 'a' 23 | rb: r(4) % 'a' 24 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [1]) 25 | 26 | - cd: r.expr('a').mod(1) 27 | py: r.expr('a') % 1 28 | rb: r('a') % 1 29 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [0]) 30 | 31 | - cd: r.expr('a').mod('b') 32 | py: r.expr('a') % 'b' 33 | rb: r('a') % 'b' 34 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [0]) 35 | -------------------------------------------------------------------------------- /spec/rql_test/src/math_logic/mul.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests for the basic usage of the multiplication operation 2 | tests: 3 | 4 | - cd: r.expr(1).mul(2) 5 | py: 6 | - r.expr(1) * 2 7 | - 1 * r.expr(2) 8 | - r.expr(1).mul(2) 9 | rb: 10 | - (r 1) * 2 11 | - r(1).mul(2) 12 | - 1 * (r 2) 13 | ot: 2 14 | 15 | - py: r.expr(-1) * -1 16 | js: r(-1).mul(-1) 17 | rb: (r -1) * -1 18 | ot: 1 19 | 20 | - cd: r.expr(1.5).mul(4.5) 21 | py: r.expr(1.5) * 4.5 22 | rb: (r 1.5) * 4.5 23 | ot: 6.75 24 | 25 | - py: r.expr([1,2,3]) * 3 26 | js: r([1,2,3]).mul(3) 27 | rb: (r [1,2,3]) * 3 28 | ot: [1,2,3,1,2,3,1,2,3] 29 | 30 | - cd: r.expr(1).mul(2,3,4,5) 31 | ot: 120 32 | 33 | - cd: r(2).mul([1,2,3], 2) 34 | py: # this form does not work in Python 35 | ot: [1,2,3,1,2,3,1,2,3,1,2,3] 36 | 37 | - cd: r([1,2,3]).mul(2, 2) 38 | py: # this form does not work in Python 39 | ot: [1,2,3,1,2,3,1,2,3,1,2,3] 40 | 41 | - cd: r(2).mul(2, [1,2,3]) 42 | py: # this form does not work in Python 43 | ot: [1,2,3,1,2,3,1,2,3,1,2,3] 44 | 45 | # Type errors 46 | - py: r.expr('a') * 0.8 47 | cd: r('a').mul(0.8) 48 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [0]) 49 | 50 | - py: r.expr(1) * 'a' 51 | cd: r(1).mul('a') 52 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [1]) 53 | 54 | - py: r.expr('b') * 'a' 55 | cd: r('b').mul('a') 56 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [0]) 57 | 58 | - py: r.expr([]) * 1.5 59 | cd: r([]).mul(1.5) 60 | ot: err('ReqlQueryLogicError', 'Number not an integer: 1.5', [0]) 61 | -------------------------------------------------------------------------------- /spec/rql_test/src/math_logic/sub.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests for basic usage of the subtraction operation 2 | tests: 3 | 4 | - cd: r.expr(1).sub(1) 5 | py: 6 | - r.expr(1) - 1 7 | - 1 - r.expr(1) 8 | - r.expr(1).sub(1) 9 | rb: 10 | - (r 1) - 1 11 | - 1 - (r 1) 12 | - r(1).sub(1) 13 | - r.expr(1).sub(1) 14 | ot: 0 15 | 16 | - cd: r.expr(-1).sub(1) 17 | py: r.expr(-1) - 1 18 | rb: (r -1) - 1 19 | ot: -2 20 | 21 | - cd: r.expr(1.75).sub(8.5) 22 | py: r.expr(1.75) - 8.5 23 | rb: (r 1.75) - 8.5 24 | ot: -6.75 25 | 26 | - cd: r.expr(1).sub(2,3,4,5) 27 | ot: -13 28 | 29 | # Type errors 30 | - cd: r.expr('a').sub(0.8) 31 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [0]) 32 | 33 | - cd: r.expr(1).sub('a') 34 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [1]) 35 | 36 | - cd: r.expr('b').sub('a') 37 | ot: err('ReqlQueryLogicError', 'Expected type NUMBER but found STRING.', [0]) 38 | -------------------------------------------------------------------------------- /spec/rql_test/src/meta/composite.py.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests meta operations in composite queries 2 | tests: 3 | 4 | - py: r.expr([1,2,3]).for_each(r.db_create('db_' + r.row.coerce_to('string'))) 5 | ot: ({'dbs_created':3,'config_changes':arrlen(3)}) 6 | 7 | - py: | 8 | r.db_list().set_difference(["rethinkdb", "test"]).for_each(lambda db_name: 9 | r.expr([1,2,3]).for_each(lambda i: 10 | r.db(db_name).table_create('tbl_' + i.coerce_to('string')))) 11 | ot: partial({'tables_created':9}) 12 | 13 | - py: r.db_list().set_difference(["rethinkdb", "test"]).for_each(r.db_drop(r.row)) 14 | ot: partial({'dbs_dropped':3,'tables_dropped':9}) 15 | -------------------------------------------------------------------------------- /spec/rql_test/src/meta/dbs.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests meta queries for databases 2 | tests: 3 | 4 | # We should always start out with a 'test' database and the special 'rethinkdb' 5 | # database 6 | - cd: r.db_list() 7 | ot: bag(['rethinkdb', 'test']) 8 | 9 | ## DB create 10 | 11 | - cd: r.db_create('a') 12 | ot: partial({'dbs_created':1}) 13 | - cd: r.db_create('b') 14 | ot: partial({'dbs_created':1}) 15 | 16 | ## DB list 17 | 18 | - cd: r.db_list() 19 | ot: bag(['rethinkdb', 'a', 'b', 'test']) 20 | 21 | ## DB config 22 | 23 | - cd: r.db('a').config() 24 | ot: {'name':'a','id':uuid()} 25 | 26 | ## DB drop 27 | 28 | - cd: r.db_drop('b') 29 | ot: partial({'dbs_dropped':1}) 30 | 31 | - cd: r.db_list() 32 | ot: bag(['rethinkdb', 'a', 'test']) 33 | 34 | - cd: r.db_drop('a') 35 | ot: partial({'dbs_dropped':1}) 36 | 37 | - cd: r.db_list() 38 | ot: bag(['rethinkdb', 'test']) 39 | 40 | ## DB errors 41 | - cd: r.db_create('bar') 42 | ot: partial({'dbs_created':1}) 43 | 44 | - cd: r.db_create('bar') 45 | ot: err('ReqlOpFailedError', 'Database `bar` already exists.', [0]) 46 | 47 | - cd: r.db_drop('bar') 48 | ot: partial({'dbs_dropped':1}) 49 | 50 | - cd: r.db_drop('bar') 51 | ot: err('ReqlOpFailedError', 'Database `bar` does not exist.', [0]) 52 | -------------------------------------------------------------------------------- /spec/rql_test/src/mutation/delete.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests deletes of selections 2 | table_variable_name: tbl 3 | tests: 4 | 5 | # Set up some data 6 | 7 | - py: tbl.insert([{'id':i} for i in xrange(100)]) 8 | js: | 9 | tbl.insert(function(){ 10 | var res = [] 11 | for (var i = 0; i < 100; i++) { 12 | res.push({id: i}); 13 | } 14 | return res; 15 | }()) 16 | rb: tbl.insert((1..100).map{ |i| {"id" => i} }) 17 | ot: ({'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':100}) 18 | 19 | - cd: tbl.count() 20 | ot: 100 21 | 22 | # Point delete 23 | 24 | - cd: tbl.get(12).delete() 25 | ot: ({'deleted':1,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':0}) 26 | 27 | # Attempt deletion with bad durability flag. 28 | 29 | - js: tbl.skip(50).delete({durability:'wrong'}) 30 | rb: tbl.skip(50).delete({ :durability => 'wrong' }) 31 | py: tbl.skip(50).delete(durability='wrong') 32 | ot: err('ReqlQueryLogicError', 'Durability option `wrong` unrecognized (options are "hard" and "soft").', [0]) 33 | 34 | # Delete selection of table, soft durability flag. 35 | 36 | - js: tbl.skip(50).delete({durability:'soft'}) 37 | rb: tbl.skip(50).delete({ :durability => 'soft' }) 38 | py: tbl.skip(50).delete(durability='soft') 39 | ot: ({'deleted':49,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':0}) 40 | 41 | # Delete whole table, hard durability flag. 42 | 43 | - js: tbl.delete({durability:'hard'}) 44 | rb: tbl.delete({ :durability => 'hard' }) 45 | py: tbl.delete(durability='hard') 46 | ot: ({'deleted':50,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':0}) 47 | 48 | # test deletion on a non-deletable object 49 | - cd: r.expr([1, 2]).delete() 50 | ot: err('ReqlQueryLogicError', 'Expected type SELECTION but found DATUM:', [0]) 51 | -------------------------------------------------------------------------------- /spec/rql_test/src/mutation/sync.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests syncing tables 2 | tests: 3 | 4 | # Set up our test tables 5 | - cd: r.db('test').table_create('test1') 6 | ot: partial({'tables_created':1}) 7 | - cd: r.db('test').table_create('test1soft') 8 | ot: partial({'tables_created':1}) 9 | - cd: r.db('test').table('test1soft').config().update({'durability':'soft'}) 10 | ot: {'skipped':0, 'deleted':0, 'unchanged':0, 'errors':0, 'replaced':1, 'inserted':0} 11 | - def: tbl = r.db('test').table('test1') 12 | - def: tbl_soft = r.db('test').table('test1soft') 13 | - cd: tbl.index_create('x') 14 | ot: partial({'created':1}) 15 | - cd: tbl.index_wait('x').pluck('index', 'ready') 16 | ot: [{'ready':True, 'index':'x'}] 17 | 18 | # This is the only way one can use sync legally at the moment 19 | - cd: tbl.sync() 20 | ot: {'synced':1} 21 | - cd: tbl_soft.sync() 22 | ot: {'synced':1} 23 | - cd: tbl.sync() 24 | ot: {'synced':1} 25 | runopts: 26 | durability: "soft" 27 | - cd: tbl.sync() 28 | ot: {'synced':1} 29 | runopts: 30 | durability: "hard" 31 | 32 | # This is of type table, but sync should still fail (because it makes little sense) 33 | - cd: tbl.between(1, 2).sync() 34 | ot: 35 | cd: err('ReqlQueryLogicError', 'Expected type TABLE but found TABLE_SLICE:', [1]) 36 | py: err('AttributeError', "'Between' object has no attribute 'sync'") 37 | 38 | # These are not even a table. Sync should fail with a different error message 39 | - cd: r.expr(1).sync() 40 | ot: 41 | cd: err("ReqlQueryLogicError", 'Expected type TABLE but found DATUM:', [1]) 42 | py: err('AttributeError', "'Datum' object has no attribute 'sync'") 43 | - js: tbl.order_by({index:'x'}).sync() 44 | rb: tbl.order_by({:index => 'soft'}).sync() 45 | ot: err("ReqlQueryLogicError", 'Expected type TABLE but found TABLE_SLICE:', [1]) 46 | 47 | # clean up 48 | - cd: r.db('test').table_drop('test1') 49 | ot: partial({'tables_dropped':1}) 50 | - cd: r.db('test').table_drop('test1soft') 51 | ot: partial({'tables_dropped':1}) 52 | 53 | -------------------------------------------------------------------------------- /spec/rql_test/src/polymorphism.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests that manipulation data in tables 2 | table_variable_name: tbl 3 | tests: 4 | 5 | - def: obj = r.expr({'id':0,'a':0}) 6 | 7 | - py: tbl.insert([{'id':i, 'a':i} for i in xrange(3)]) 8 | js: | 9 | tbl.insert(function(){ 10 | var res = [] 11 | for (var i = 0; i < 3; i++) { 12 | res.push({id:i, 'a':i}); 13 | } 14 | return res; 15 | }()) 16 | rb: tbl.insert((0..2).map{ |i| { :id => i, :a => i } }) 17 | ot: ({'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':3}) 18 | 19 | # Polymorphism 20 | - cd: 21 | - tbl.merge({'c':1}).nth(0) 22 | - obj.merge({'c':1}) 23 | ot: ({'id':0,'c':1,'a':0}) 24 | 25 | - cd: 26 | - tbl.without('a').nth(0) 27 | - obj.without('a') 28 | ot: ({'id':0}) 29 | 30 | - cd: 31 | - tbl.pluck('a').nth(0) 32 | - obj.pluck('a') 33 | ot: ({'a':0}) 34 | -------------------------------------------------------------------------------- /spec/rql_test/src/range.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests RQL range generation 2 | tests: 3 | - cd: r.range().type_of() 4 | ot: 'STREAM' 5 | 6 | - cd: r.range().limit(4) 7 | ot: [0, 1, 2, 3] 8 | 9 | - cd: r.range(4) 10 | ot: [0, 1, 2, 3] 11 | 12 | - cd: r.range(2, 5) 13 | ot: [2, 3, 4] 14 | 15 | - cd: r.range(0) 16 | ot: [] 17 | 18 | - cd: r.range(5, 2) 19 | ot: [] 20 | 21 | - cd: r.range(-5, -2) 22 | ot: [-5, -4, -3] 23 | 24 | - cd: r.range(-5, 2) 25 | ot: [-5, -4, -3, -2, -1, 0, 1] 26 | 27 | - cd: r.range(2, 5, 8) 28 | ot: err("ReqlCompileError", "Expected between 0 and 2 arguments but found 3.", []) 29 | 30 | - cd: r.range("foo") 31 | ot: err("ReqlQueryLogicError", "Expected type NUMBER but found STRING.", []) 32 | 33 | # Using 9007199254740994 instead of 9007199254740993 due to #2157 34 | - cd: r.range(9007199254740994) 35 | ot: err_regex("ReqlQueryLogicError", "Number not an integer \\(>2\\^53\\). 9007199254740994", []) 36 | 37 | - cd: r.range(-9007199254740994) 38 | ot: err_regex("ReqlQueryLogicError", "Number not an integer \\(<-2\\^53\\). -9007199254740994", []) 39 | 40 | - cd: r.range(0.5) 41 | ot: err_regex("ReqlQueryLogicError", "Number not an integer. 0\\.5", []) 42 | 43 | - cd: r.range().count() 44 | ot: err("ReqlQueryLogicError", "Cannot use an infinite stream with an aggregation function (`reduce`, `count`, etc.) or coerce it to an array.", []) 45 | 46 | - cd: r.range().coerce_to("ARRAY") 47 | ot: err("ReqlQueryLogicError", "Cannot use an infinite stream with an aggregation function (`reduce`, `count`, etc.) or coerce it to an array.", []) 48 | 49 | - cd: r.range().coerce_to("OBJECT") 50 | ot: err("ReqlQueryLogicError", "Cannot use an infinite stream with an aggregation function (`reduce`, `count`, etc.) or coerce it to an array.", []) 51 | 52 | - cd: r.range(4).count() 53 | ot: 4 54 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/1001.yaml: -------------------------------------------------------------------------------- 1 | desc: 1001 (null + between + sindexes) 2 | table_variable_name: tbl 3 | tests: 4 | - cd: tbl.insert({'a':null}) 5 | rb: tbl.insert({:a => null}) 6 | - cd: tbl.index_create('a') 7 | - cd: tbl.index_create('b') 8 | - cd: tbl.index_wait().pluck('index', 'ready') 9 | 10 | - cd: tbl.between(r.minval, r.maxval).count() 11 | ot: 1 12 | - py: tbl.between(r.minval, r.maxval, index='a').count() 13 | js: tbl.between(r.minval, r.maxval, {index:'a'}).count() 14 | rb: tbl.between(r.minval, r.maxval, :index => 'a').count() 15 | ot: 0 16 | - py: tbl.between(r.minval, r.maxval, index='b').count() 17 | js: tbl.between(r.minval, r.maxval, {index:'b'}).count() 18 | rb: tbl.between(r.minval, r.maxval, :index => 'b').count() 19 | ot: 0 20 | 21 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/1005.yaml: -------------------------------------------------------------------------------- 1 | desc: Regression test for issue #1005. 2 | tests: 3 | - py: r.expr(str(r.table_list())) 4 | ot: "r.table_list()" 5 | 6 | - py: r.expr(str(r.table_create('a'))) 7 | ot: "r.table_create('a')" 8 | 9 | - py: r.expr(str(r.table_drop('a'))) 10 | ot: "r.table_drop('a')" 11 | 12 | - py: r.expr(str(r.db('a').table_list())) 13 | ot: "r.db('a').table_list()" 14 | 15 | - py: r.expr(str(r.db('a').table_create('a'))) 16 | ot: "r.db('a').table_create('a')" 17 | 18 | - py: r.expr(str(r.db('a').table_drop('a'))) 19 | ot: "r.db('a').table_drop('a')" 20 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/1023.yaml: -------------------------------------------------------------------------------- 1 | desc: Tests key sorting of all usable types in primary indexes 2 | table_variable_name: tbl 3 | tests: 4 | 5 | 6 | # Test key sorting 7 | - def: 8 | py: binary_a = r.binary(b'') 9 | rb: binary_a = r.binary('') 10 | js: binary_a = Buffer('') 11 | 12 | - def: 13 | py: binary_b = r.binary(b'5aurhbviunr') 14 | rb: binary_b = r.binary('5aurhbviunr') 15 | js: binary_b = Buffer('5aurhbviunr') 16 | 17 | # Define a set of rows in order of increasing sindex keys 18 | - def: 19 | cd: trows = [{'num':0,'id':[0]}, 20 | {'num':1,'id':[1, 2, 3, 4, 0]}, 21 | {'num':2,'id':[1, 2, 3, 4, 4]}, 22 | {'num':3,'id':[1, 2, 3, 4, 4, 5]}, 23 | {'num':4,'id':[1, 2, 3, 4, 8, 1]}, 24 | {'num':5,'id':[1, 3, r.epoch_time(0)]}, 25 | {'num':6,'id':[1, 3, r.epoch_time(0), r.epoch_time(0)]}, 26 | {'num':7,'id':[1, 3, r.epoch_time(0), r.epoch_time(1)]}, 27 | {'num':8,'id':[1, 4, 3, 4, 8, 2]}, 28 | {'num':9,'id':False}, 29 | {'num':10,'id':True}, 30 | {'num':11,'id':-500}, 31 | {'num':12,'id':500}, 32 | {'num':13,'id':binary_a}, 33 | {'num':14,'id':binary_b}, 34 | {'num':15,'id':r.epoch_time(0)}, 35 | {'num':16,'id':''}, 36 | {'num':17,'id':' str'}] 37 | 38 | - def: 39 | cd: expected = r.range(tbl.count()).coerce_to('array') 40 | 41 | - cd: tbl.insert(trows)['inserted'] 42 | js: tbl.insert(trows)('inserted') 43 | ot: 18 44 | 45 | - rb: tbl.order_by({:index => 'id'}).map{|row| row['num']}.coerce_to('array').eq(expected) 46 | js: tbl.order_by({index:'id'}).map(r.row('num')).coerce_to('array').eq(expected) 47 | py: tbl.order_by(index='id').map(r.row['num']).coerce_to('array').eq(expected) 48 | ot: true 49 | 50 | # Test minval and maxval 51 | - rb: tbl.order_by(:index => 'id').between(r.minval, r.maxval).map{|x| x['num']}.coerce_to('array').eq(expected) 52 | js: tbl.order_by({index:'id'}).between(r.minval, r.maxval).map(r.row('num')).coerce_to('array').eq(expected) 53 | py: tbl.order_by(index='id').between(r.minval, r.maxval).map(r.row['num']).coerce_to('array').eq(expected) 54 | ot: true 55 | 56 | - py: tbl.order_by(index='id').between([1,2,3,4,4],[1,2,3,5]).map(r.row['num']).coerce_to('array') 57 | js: tbl.order_by({index:'id'}).between([1,2,3,4,4],[1,2,3,5]).map(r.row('num')).coerce_to('array') 58 | rb: tbl.order_by(:index => 'id').between([1,2,3,4,4],[1,2,3,5]).map{|x| x['num']}.coerce_to('array') 59 | ot: [2,3,4] 60 | 61 | - py: tbl.order_by(index='id').between([1,2,3,4,4,r.minval],[1,2,3,4,4,r.maxval]).map(r.row['num']).coerce_to('array') 62 | js: tbl.order_by({index:'id'}).between([1,2,3,4,4,r.minval],[1,2,3,4,4,r.maxval]).map(r.row('num')).coerce_to('array') 63 | rb: tbl.order_by(:index => 'id').between([1,2,3,4,4,r.minval],[1,2,3,4,4,r.maxval]).map{|x| x['num']}.coerce_to('array') 64 | ot: [3] 65 | 66 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/1081.yaml: -------------------------------------------------------------------------------- 1 | desc: 1081 union two streams 2 | tests: 3 | 4 | - rb: r.db('test').table_create('t1081') 5 | def: t = r.db('test').table('t1081') 6 | 7 | - rb: t.insert([{'id':0}, {'id':1}]) 8 | 9 | - rb: r([]).union([]).typeof 10 | ot: ("ARRAY") 11 | - rb: t.union(t).typeof 12 | ot: ("STREAM") 13 | - rb: t.union([]).typeof 14 | ot: ("STREAM") 15 | 16 | - rb: r.db('test').table_drop('t1081') 17 | 18 | - rb: r.table_create('1081') 19 | ot: partial({'tables_created':1}) 20 | 21 | - rb: r.table('1081').insert({:password => 0})[:inserted] 22 | ot: 1 23 | 24 | - rb: r.table('1081').index_create('password') 25 | ot: ({'created':1}) 26 | - rb: r.table('1081').index_wait('password').pluck('index', 'ready') 27 | ot: ([{'ready':True, 'index':'password'}]) 28 | 29 | - rb: r.table('1081').get_all(0, :index => 'password').typeof 30 | ot: ("SELECTION") 31 | - rb: r.table('1081').get_all(0, :index => 'password').without('id').typeof 32 | ot: ("STREAM") 33 | - rb: r.table('1081').get_all(0, 0, :index => 'password').typeof 34 | ot: ("SELECTION") 35 | - rb: r.table('1081').get_all(0, 0, :index => 'password').without('id').typeof 36 | ot: ("STREAM") 37 | 38 | - rb: r.table_drop('1081') 39 | ot: partial({'tables_dropped':1}) 40 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/1132.yaml: -------------------------------------------------------------------------------- 1 | desc: 1132 JSON duplicate key 2 | tests: 3 | - cd: r.json('{"a":1,"a":2}') 4 | ot: err("ReqlQueryLogicError", "Duplicate key \"a\" in JSON.", []) 5 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/1133.yaml: -------------------------------------------------------------------------------- 1 | desc: Regression tests for issue #1133, which concerns circular references in the drivers. 2 | 3 | tests: 4 | - def: a = {} 5 | - def: b = {'a':a} 6 | - def: a['b'] = b 7 | 8 | - cd: r.expr(a) 9 | ot: 10 | cd: err('ReqlDriverCompileError', 'Nesting depth limit exceeded.', []) 11 | rb: err('ReqlDriverCompileError', 'Maximum expression depth exceeded (you can override this with `r.expr(X, MAX_DEPTH)`).', []) 12 | 13 | - cd: r.expr({'a':{'a':{'a':{'a':{'a':{'a':{'a':{}}}}}}}}, 7) 14 | ot: 15 | cd: err('ReqlDriverCompileError', 'Nesting depth limit exceeded.', []) 16 | rb: err('ReqlDriverCompileError', 'Maximum expression depth exceeded (you can override this with `r.expr(X, MAX_DEPTH)`).', []) 17 | 18 | - cd: r.expr({'a':{'a':{'a':{'a':{'a':{'a':{'a':{}}}}}}}}, 10) 19 | ot: ({'a':{'a':{'a':{'a':{'a':{'a':{'a':{}}}}}}}}) 20 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/1155.yaml: -------------------------------------------------------------------------------- 1 | desc: 1155 -- Empty batched_replaces_t constructed 2 | table_variable_name: tbl 3 | tests: 4 | - rb: tbl.insert([{:id => '2'}, {:id => '4'}])['inserted'] 5 | ot: 2 6 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/1179.yaml: -------------------------------------------------------------------------------- 1 | desc: 1179 -- BRACKET term 2 | table_variable_name: tbl 3 | tests: 4 | - js: r.expr([1])(r.expr(0)) 5 | py: r.expr([1])[r.expr(0)] 6 | rb: r.expr([1])[r.expr(0)] 7 | ot: 1 8 | - js: r.expr({"foo":1})('foo') 9 | ot: 1 10 | - js: r.expr([1])(0) 11 | ot: 1 12 | - js: tbl.insert([{'id':42},{'id':4},{'id':89},{'id':6},{'id':43}]).pluck('inserted','first_error') 13 | ot: ({'inserted':5}) 14 | 15 | # test [] grouped data semantics 16 | - js: tbl.group('id')(0) 17 | ot: ([{"group":4,"reduction":{"id":4}},{"group":6,"reduction":{"id":6}},{"group":42,"reduction":{"id":42}},{"group":43,"reduction":{"id":43}},{"group":89,"reduction":{"id":89}}] ) 18 | - js: tbl.coerce_to('array').group('id')(0) 19 | ot: ([{"group":4,"reduction":{"id":4}},{"group":6,"reduction":{"id":6}},{"group":42,"reduction":{"id":42}},{"group":43,"reduction":{"id":43}},{"group":89,"reduction":{"id":89}}] ) 20 | 21 | # test nth grouped data semantics 22 | - js: tbl.group('id').nth(0) 23 | ot: ([{"group":4,"reduction":{"id":4}},{"group":6,"reduction":{"id":6}},{"group":42,"reduction":{"id":42}},{"group":43,"reduction":{"id":43}},{"group":89,"reduction":{"id":89}}] ) 24 | - js: tbl.coerce_to('array').group('id').nth(0) 25 | ot: ([{"group":4,"reduction":{"id":4}},{"group":6,"reduction":{"id":6}},{"group":42,"reduction":{"id":42}},{"group":43,"reduction":{"id":43}},{"group":89,"reduction":{"id":89}}] ) 26 | 27 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/1468.yaml: -------------------------------------------------------------------------------- 1 | desc: 1468 -- Empty batched_replaces_t constructed 2 | table_variable_name: tbl 3 | tests: 4 | - rb: tbl.insert([{}, {}, {}])['inserted'] 5 | ot: (3) 6 | - rb: tbl.replace(non_atomic:'true'){|row| r.js("{}")} 7 | ot: ({"unchanged"=>0,"skipped"=>0,"replaced"=>0,"inserted"=>0,"first_error"=>"Cannot convert javascript `undefined` to ql::datum_t.","errors"=>3,"deleted"=>0}) 8 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/1789.yaml: -------------------------------------------------------------------------------- 1 | desc: 1789 -- deleting a secondary index on a table that contains non-inline stored documents corrupts db 2 | table_variable_name: tbl 3 | tests: 4 | - rb: tbl.insert({:foo => 'a', :data => "AAAAAAAAAAAAAAAAAA 5 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 6 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 7 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 8 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}).pluck('inserted') 9 | ot: ({'inserted':1}) 10 | 11 | - rb: tbl.index_create('foo') 12 | ot: ({'created':1}) 13 | 14 | - rb: tbl.index_wait('foo').pluck('index', 'ready') 15 | ot: ([{'index':'foo', 'ready':true}]) 16 | 17 | - rb: tbl.index_drop('foo') 18 | ot: ({'dropped':1}) 19 | 20 | - rb: tbl.coerce_to('ARRAY').count() 21 | ot: (1) 22 | 23 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/2052.yaml: -------------------------------------------------------------------------------- 1 | desc: 2052 -- Verify that the server rejects bogus global options. 2 | tests: 3 | - cd: r.expr(1) 4 | runopts: 5 | array_limit: 16 6 | ot: 1 7 | - cd: r.expr(1) 8 | runopts: 9 | obviously_bogus: 16 10 | ot: err("ReqlCompileError", "Unrecognized global optional argument `obviously_bogus`.", []) 11 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/2399.rb.yaml: -------------------------------------------------------------------------------- 1 | desc: 2399 literal terms not removed under certain circumstances 2 | table_variable_name: t 3 | tests: 4 | - rb: t.insert({}) 5 | - rb: t.update({:a => {:b => r.literal({})}}) 6 | - rb: t.without('id').coerce_to("ARRAY") 7 | ot: [{'a':{'b':{}}}] 8 | - rb: t.delete() 9 | 10 | - rb: t.insert({}) 11 | - rb: t.update({:a => {:b => r.literal()}}) 12 | - rb: t.without('id').coerce_to("ARRAY") 13 | ot: [{'a': {}}] 14 | - rb: t.delete() 15 | 16 | - rb: t.insert({}) 17 | - rb: t.update({:a => {:b => {:c => {:d => r.literal({})}}}}) 18 | - rb: t.without('id').coerce_to("ARRAY") 19 | ot: [{'a':{'b':{'c':{'d':{}}}}}] 20 | - rb: t.delete() 21 | 22 | - rb: t.insert({}) 23 | - rb: t.update({:a => {:b => [[[{:c => r.literal({})}]]]}}) 24 | - rb: t.without('id').coerce_to("ARRAY") 25 | ot: [{'a':{'b':[[[{'c':{}}]]]}}] 26 | - rb: t.delete() 27 | 28 | - rb: t.insert({}) 29 | - rb: t.update({:a => {:b => [r.literal()]}}) 30 | - rb: t.without('id').coerce_to("ARRAY") 31 | ot: [{'a':{'b':[]}}] 32 | - rb: t.delete() 33 | 34 | - rb: t.insert({}) 35 | - rb: t.update({:a => {:b => {:a => 'A', :b => 'B', :c => 'C', :cc => r.literal(), :d => 'D'}}}) 36 | - rb: t.without('id').coerce_to("ARRAY") 37 | ot: [{'a':{'b':{'a':'A', 'b':'B', 'c':'C', 'd':'D'}}}] 38 | - rb: t.delete() 39 | 40 | - rb: t.insert({}) 41 | - rb: t.update({:a => {:b => {:a => 'A', :b => 'B', :c => 'C', :cc => r.literal('CC'), :d => 'D'}}}) 42 | - rb: t.without('id').coerce_to("ARRAY") 43 | ot: [{'a':{'b':{'a':'A', 'b':'B', 'c':'C', 'cc':'CC', 'd':'D'}}}] 44 | - rb: t.delete() 45 | 46 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/2639.rb.yaml: -------------------------------------------------------------------------------- 1 | desc: 2639 -- Coroutine stacks should not overflow during the query compilation phase. 2 | tests: 3 | - rb: r.expr({id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:{id:1}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, 1000) 4 | ot: partial({}) 5 | 6 | - rb: r.expr([[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],1000).and(nil) 7 | ot: nil 8 | 9 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/2696.yaml: -------------------------------------------------------------------------------- 1 | desc: Regression test for issue 2696, delete_at with end bounds. 2 | tests: 3 | - cd: r.expr([1,2,3,4]).delete_at(4,4) 4 | ot: [1,2,3,4] 5 | - cd: r.expr([]).delete_at(0,0) 6 | ot: [] 7 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/2697.yaml: -------------------------------------------------------------------------------- 1 | desc: 2697 -- Array insert and splice operations don't check array size limit. 2 | table_variable_name: tbl 3 | tests: 4 | # make enormous > 100,000 element array 5 | - def: ten_l = r.expr([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 6 | - js: tbl.insert({'id':1, 'a':r.expr(ten_l).concatMap(function(l) { return ten_l }).concatMap(function(l) { return ten_l }).concatMap(function(l) { return ten_l }).concatMap(function(l) { return ten_l })}).pluck('first_error', 'inserted') 7 | py: tbl.insert({'id':1, 'a':r.expr(ten_l).concat_map(lambda l:list(range(1,11))).concat_map(lambda l:list(range(1,11))).concat_map(lambda l:list(range(1,11))).concat_map(lambda l:list(range(1,11)))}).pluck('first_error', 'inserted') 8 | rb: tbl.insert({'id':1, 'a':r.expr(ten_l).concat_map {|l| ten_l}.concat_map {|l| ten_l}.concat_map {|l| ten_l}.concat_map {|l| ten_l}}).pluck('first_error', 'inserted') 9 | ot: ({'inserted':1}) 10 | - cd: tbl.get(1).replace({'id':1, 'a':r.row['a'].splice_at(0, [2])}).pluck('first_error') 11 | js: tbl.get(1).replace({'id':1, 'a':r.row('a').spliceAt(0, [2])}).pluck('first__error') 12 | rb: tbl.get(1).replace{|old| {:id => 1, :a => old['a'].splice_at(0, [2])}}.pluck('first_error') 13 | ot: ({'first_error':'Array over size limit `100000`.'}) 14 | - cd: tbl.get(1)['a'].count() 15 | js: tbl.get(1)('a').count() 16 | ot: 100000 17 | - cd: tbl.get(1).replace({'id':1, 'a':r.row['a'].insert_at(0, [2])}).pluck('first_error') 18 | js: tbl.get(1).replace({'id':1, 'a':r.row('a').insertAt(0, [2])}).pluck('first__error') 19 | rb: tbl.get(1).replace{|old| {:id => 1, :a => old['a'].insert_at(0, [2])}}.pluck('first_error') 20 | ot: ({'first_error':'Array over size limit `100000`.'}) 21 | - cd: tbl.get(1)['a'].count() 22 | js: tbl.get(1)('a').count() 23 | ot: 100000 24 | - js: r.expr([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).concatMap(function(l) { return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }).concatMap(function(l) { return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }).concatMap(function(l) { return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }).concatMap(function(l) { return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }).spliceAt(0, [1]).count() 25 | py: r.expr(ten_l).concat_map(lambda l:list(range(1,11))).concat_map(lambda l:list(range(1,11))).concat_map(lambda l:list(range(1,11))).concat_map(lambda l:list(range(1,11))).splice_at(0, [1]).count() 26 | rb: r.expr(ten_l).concat_map {|l| ten_l}.concat_map {|l| ten_l}.concat_map {|l| ten_l}.concat_map {|l| ten_l}.splice_at(0, [1]).count() 27 | ot: err("ReqlResourceLimitError", "Array over size limit `100000`.", []) 28 | - js: r.expr([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).concatMap(function(l) { return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }).concatMap(function(l) { return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }).concatMap(function(l) { return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }).concatMap(function(l) { return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }).insertAt(0, [1]).count() 29 | py: r.expr(ten_l).concat_map(lambda l:list(range(1,11))).concat_map(lambda l:list(range(1,11))).concat_map(lambda l:list(range(1,11))).concat_map(lambda l:list(range(1,11))).insert_at(0, [1]).count() 30 | rb: r.expr(ten_l).concat_map {|l| ten_l}.concat_map {|l| ten_l}.concat_map {|l| ten_l}.concat_map {|l| ten_l}.insert_at(0, [1]).count() 31 | ot: err("ReqlResourceLimitError", "Array over size limit `100000`.", []) 32 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/2709.yaml: -------------------------------------------------------------------------------- 1 | desc: 2709 -- Guarantee failed with [max_els >= min_els] 2 | table_variable_name: tbl 3 | tests: 4 | - py: tbl.insert([{'result':i} for i in range(1,1000)]).pluck('first_error', 'inserted') 5 | runopts: 6 | min_batch_rows: 10 7 | max_batch_rows: 13 8 | ot: ({'inserted':999}) 9 | 10 | - py: tbl.map(lambda thing:'key').count() 11 | runopts: 12 | min_batch_rows: 10 13 | max_batch_rows: 13 14 | ot: (999) 15 | 16 | - py: tbl.map(lambda thing:'key').count() 17 | runopts: 18 | min_batch_rows: 10 19 | max_batch_rows: 13 20 | ot: (999) 21 | 22 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/2710.yaml: -------------------------------------------------------------------------------- 1 | desc: Test pseudo literal strings in JSON. 2 | tests: 3 | - js: r.expr({"a":{"b":1, "c":2}}).merge(r.json('{"a":{"$reql_'+'type$":"LITERAL", "value":{"b":2}}}')) 4 | py: r.expr({"a":{"b":1, "c":2}}).merge(r.json('{"a":{"$reql_type$":"LITERAL", "value":{"b":2}}}')) 5 | rb: r.expr({:a => {:b => 1, :c => 2}}).merge(r.json('{"a":{"$reql_type$":"LITERAL", "value":{"b":2}}}')) 6 | ot: ({'a':{'b':2}}) 7 | -------------------------------------------------------------------------------- /spec/rql_test/src/regression/2766.yaml: -------------------------------------------------------------------------------- 1 | desc: Stop people treating ptypes as objects 2 | tests: 3 | - cd: r.now()['epoch_time'] 4 | js: r.now()('epoch_time') 5 | ot: err("ReqlQueryLogicError", "Cannot call `bracket` on objects of type `PTYPE