package

github.com/kingsleyh/crystal-rethinkdb

0.3.1 / published Sep 15, 2021 / repository

driver for rethinkdb / rebirthdb

Crystal RethinkDB

This is a RethinkDB Driver for the Crystal Language.

CI Crystal Version

Installation

Add this to your application's shard.yml:

dependencies:
  rethinkdb:
    github: kingsleyh/crystal-rethinkdb

Usage

This library is meant to be compatible with RethinkDB's Ruby API. Thus, all official documentation should be valid here. If you find something that behaves differently, please open an issue.

require "rethinkdb"
include RethinkDB::Shortcuts

# Let’s connect and create a table:

conn = r.connect(host: "localhost")
r.db("test").table_create("tv_shows").run(conn)

# Now, let’s insert some JSON documents into the table:

r.table("tv_shows").insert([
  {name: "Star Trek TNG", episodes: 178},
  {name: "Battlestar Galactica", episodes: 75}
]).run(conn)

# We’ve just inserted two rows into the tv_shows table. Let’s verify the number of rows inserted:

pp r.table("tv_shows").count().run(conn)

# Finally, let’s do a slightly more sophisticated query. Let’s find all shows with more than 100 episodes.

p r.table("tv_shows").filter {|show| show["episodes"] > 100 }.run(conn).to_a

# As a result, we of course get the best science fiction show in existence.

Connecting as a user

If you made a user called bob with password secret in the rethinkdb system table users e.g.:

r.db('rethinkdb').table('users').insert({id: 'bob', password: 'secret'})
require "rethinkdb"
include RethinkDB::Shortcuts

conn = r.connect(host: "localhost", db: "my_database", user: "bob", password: "secret")

Read more about users and permissions here: https://rethinkdb.com/docs/permissions-and-accounts/

Useful Queries

Here are some more complex queries - mostly as a reminder to myself on how to do various more complicated things:

Something to note is that depending on the query you write you could get back one of these 3 things:

  • RethinkDB::QueryResult
  • RethinkDB:Cursor
  • RethinkDB::Array(RethinkDB::QueryResult)
Inserting
r.table("users").insert({
                      name: name, email: email, password: password,
                      activeChannel: {} of String => String,
                      channels: [] of String, groups: [] of String,
                      isOnline: false
                      }
                    ).run(@connection)
r.table("messages").insert({channelId: channelId, userId: userId, content: content, date: r.now.to_iso8601}).run(@connection)
Finding All
r.table("users").map{|u|
         {id: u["id"], name: u["name"], isOnline: u["isOnline"]}
      }.run(@connection) }
r.table("users").filter{|u| r.expr(u["groups"]).contains(groupId) }.map{|u|
         {id: u["id"], name: u["name"], isOnline: u["isOnline"]}
      }.run(@connection)
r.table("groups").map{|g|
         {id: g["id"], name: g["name"], landingChannel: r.table("channels").filter({isLanding: true, groupId: g["id"]})[0]["id"]}
      }.run(@connection)
r.table("users").filter({id: userId}).map{|user|
                        {
                         channels: r.table("channels").filter{|ch| ch["groupId"] == groupId}.coerce_to("array"),
                         activeChannel: r.branch(user["activeChannel"].has_fields("channelId"),
                                          {groupId: user["activeChannel"]["groupId"], channelId: user["activeChannel"]["channelId"], name: r.table("channels").get(user["activeChannel"]["channelId"])["name"]},
                                          {groupId: "", channelId: "", name: ""}),
                         groupId: r.table("groups").get(groupId)["id"],
                         name: r.table("groups").get(groupId)["name"]
                         }
                       }.run(@connection)
Finding One
r.table("users").get(userId).run(@connection)
  r.table("users").filter({id: userId}).map{|user|
                        {
                        channels: r.table("channels").filter{|ch| r.expr(user["channels"]).contains(ch["id"])}.filter{|ch| ch["groupId"] == groupId}.coerce_to("array"),
                        groups: r.table("groups").filter{|g| r.expr(user["groups"]).contains(g["id"])}.map{|g| {id: g["id"], name: g["name"], landingChannel: r.table("channels").filter({isLanding: true, groupId: g["id"]})[0]["id"]}}.coerce_to("array"),
                        messages: r.table("messages").filter{|m| m["channelId"] == channelId }.map{|m| {messageId: m["id"], userId: m["userId"], name: r.table("users").get(m["userId"])["name"], content: m["content"], date: m["date"]} }.coerce_to("array"),
                        channel: r.table("channels").get(channelId),
                        group: r.table("groups").get(groupId),
                        userIsOnline: user["isOnline"]
                        }
                      }.run(@connection).to_a.first
Updates
r.table("users").get(userId).update({isOnline: isOnline}).run(@connection)
r.table("users").get(userId).update{|u|
        {channels: u.get_field("channels").set_insert(channelId),
         groups: u.get_field("groups").set_insert(groupId),
         activeChannel: {groupId: groupId, channelId: channelId}
        }
      }.run(@connection) }
r.table("users").get(userId).update{|u| {groups: u.get_field("groups").set_insert(groupId)}}.run(@connection)
Creating a database
def recreate_database
  puts "dropping database: #{@env.database.name}"

  begin
    r.db_drop(@env.database.name).run( @connection)
  rescue ex
    puts ex.message
  end

  puts "creating database: #{@env.database.name}"
  r.db_create(@env.database.name).run(@connection)

  # add tables
  puts "adding tables: users, groups, channels, messages"
  r.db(@env.database.name).table_create("users").run(@connection)
  r.db(@env.database.name).table_create("groups").run(@connection)
  r.db(@env.database.name).table_create("channels").run(@connection)
  r.db(@env.database.name).table_create("messages").run(@connection)

  puts "done"
end

Contributing

  1. Fork it (https://github.com/kingsleyh/crystal-rethinkdb/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

  • kingsleyh Kingsley Hendrickse - creator, maintainer
  • caspiano Caspian Baska - contributor, maintainer
  • fenicks Christian Kakesa - contributor

Thanks

API

  • Array(T)

    An Array is an ordered, integer-indexed collection of objects of type T.

  • Bool

    Bool has only two possible values: true and false.

  • Float

    Float is the base type of all floating point numbers.

  • Hash(K, V)

    A Hash represents a collection of key-value mappings, similar to a dictionary.

  • Int

    Int is the base type of all integer types.

  • NamedTuple(**T)

    A named tuple is a fixed-size, immutable, stack-allocated mapping of a fixed set of keys to values.

  • Nil

    The Nil type has only one possible value: nil.

  • Number

    The top-level number type.

  • ReqlType
  • RethinkDB
  • String

    A String represents an immutable sequence of UTF-8 characters.

  • Symbol

    A symbol is a constant that is identified by a name without you having to give it a numeric value.

  • Time

    Time represents a date-time instant in incremental time observed in a specific time zone.

  • Tuple(*T)

    A tuple is a fixed-size, immutable, stack-allocated sequence of values of possibly different types.

  • UUID

    Represents a UUID (Universally Unique IDentifier).