Giter VIP home page Giter VIP logo

exile's Introduction

Exile

A Realtime Database-As-A-Service with REST style resource location and Time Traveling Feature support.

See it live @ https://exile-web.gigalixirapp.com

Philosophy

An extremely simple to use NoSQL store which follows REST-like resource locators known as paths to locate records and define relations between data.

Getting Started

Development

Run Tests

mix tests

Run Dialyzer

mix dialyzer

Generate and View Docs

mix docs && open doc/index.html

Run App Locally

mix do deps.get, compile
(cd apps/exile_web/assets && npm install)
iex -S mix phx.server
open http://localhost:4000

๐ŸŽ‰ You will be presented with an interact REPL to play with the RT Database via JS API!

๐ŸŽ‰ You can also interact directly with the store using the Exile Elixir API Directly via the IEX session. See Docs: doc/Exile.html#content

Real Time Database ๐Ÿ–ฅ๏ธ โšก ๐Ÿ–ฅ๏ธ

  • Goto https://exile-web.gigalixirapp.com/ (or run locally)
  • Copy the URL (which contains the sandbox token) into another browser window
  • Click subscribe which will listen for changes on the "posts" domain path
  • Create posts in the other window
  • See the Magic โœจ as the changes are relayed to all subscribers

An example scenario:

Using Exile to create a blog completely in client JS, submit and edit posts and have them visible to all sessions, and have comments instantly appear in a live fashion in all sessions, WITHOUT ANY SERVER SIDE CODE ๐Ÿ˜

API

POST

Create Records

elixir

Exile.post("posts", {author: "holsee", title: "Hello World", body: "...", comments: []})
#=> {:ok, "614e1637-5af1-4bd4-8432-e5ccd3b5cd90"}

javascript

exile.post('posts', {author: 'holsee', title: 'Hello World', body: '...', comments: []})
//=>
{
  reference: 'posts',
  result: 'ok',
  value: '04c7fecd-9e3f-408d-8799-fef8d120d93c'
}
Nested

Create a nested Record

elixir: create a comment on a post

Exile.post("posts/#{post_id}/comments", %{author: "evadne", body: "nice!"})
#=>
{:ok, "cd3c2478-cc50-4010-b54c-7e6e2f534695"}

javascript: create a comment on a post

exile.post(`posts/${post_id}/comments`, {author: 'evadne', body: 'nice!'})
//=>
{
  reference: 'posts/04c7fecd-9e3f-408d-8799-fef8d120d93c/comments',
  result: 'ok',
  value: 'a7cc9516-59d0-4095-970d-25eeb7d0b5be'
}

GET

๐Ÿ”ฅ Using REST style locator paths you are able to dig into resources which have been dynamically created! ๐Ÿ”ฅ

elixir: get all posts

Exile.get('posts')
# =>
{:ok,
 [
   %{
     id: "88d903d4-4b7e-4735-926d-a54bce4b94cf",
     ts: 1569186483608933000,
     value: %{
       "author" => "holsee",
       "comments" => [
         %{
           id: "cd3c2478-cc50-4010-b54c-7e6e2f534695",
           ts: 1569186483608929000,
           value: %{"author" => "bran", "body" => "Lorem ipsum"}
         }
       ],
       "tags" => ["bill", "ted", "rufus"]
     }
   }
 ]}

elixir: get a specific comment

Exile.get("posts/#{post_id}/comments/#{comment_id}")
#=>
{:ok, %{"author" => "bran", "body" => "Lorem ipsum"}}

elixir: get a specific comment author

Exile.get("posts/#{post_id}/comments/#{comment_id}")
#=>
{:ok, "bran"}

javascript: get all posts

exile.get('posts')
//=>
{
  reference: 'posts',
  result: 'ok',
  value: [
    {
      id: '4874b3dd-6f67-48dd-8b3f-182ead6362a6',
      ts: 1569186089957471700,
      value: {
        author: 'holsee',
        body: '...',
        comments: [
          {
            id: '6748759c-896b-4e5b-93e9-3f49fa4d06cd',
            ts: 1569186089957465000,
            value: {
              author: 'evadne',
              body: 'nice!'
            }
          }
        ],
        title: 'Hello World'
      }
    }
  ]
}

javascript: get all comments on a post

exile.get('posts/${post_id}/comments')
//=>
{
  reference: 'posts/4874b3dd-6f67-48dd-8b3f-182ead6362a6/comments',
  result: 'ok',
  value: [
    {
      id: '6748759c-896b-4e5b-93e9-3f49fa4d06cd',
      ts: 1569186089957465000,
      value: {
        author: 'evadne',
        body: 'nice!'
      }
    }
  ]
}

PUT

Unlike POST operations which create new records, PUT allows you to update values at a locator path.

elixir: update post body

Exile.put("posts/#{post_id}/body", "new body!")
# => :ok

Exile.get("posts/#{post_id}/body")
# =>
{:ok, "new body!"}

DELETE

You can also delete values at the path:

elixir: delete all posts

Exile.delete("posts")
# =>
:ok

javascript: delete all posts

exile.delete('posts')

Subscribe to path (Realtime features ๐Ÿ–ฅ๏ธ โšก ๐Ÿ–ฅ๏ธ)

elixir: subscribe to posts, get update event

subscriber_address = self()
Exile.subscribe("posts", subscriber_address)
#=>
:ok

#when post is created or updated receive event:
flush()
#=>
{:exile_event,
 {:update, "posts/e5373a79-8b76-464f-b72a-8182a1ed6230/body",
  {"e5373a79-8b76-464f-b72a-8182a1ed6230", 1569187403304193274,
   %{
     "author" => "holsee",
     "body" => "new body!",
     "comments" => [
       %{
         id: "787b20f6-643f-454d-9a87-f9fd985b4458",
         ts: 1569186933359652898,
         value: %{"author" => "bran", "body" => "Lorem ipsum"}
       }
     ],
     "tags" => ["bill", "ted", "rufus"]
   }}}}

javascript: subscribe to posts, get new item event

exile.subscribe('posts')
#=>
{
  result: 'ok'
}

# when post is created receive event
#=>
{
  event_type: 'new',
  path: '37469d37-21f9-4ea5-b2a9-ebe136d8c3cc:posts',
  record: {
    id: 'd9f0db63-2f3d-422d-b9d7-bccc549d3e65',
    timestamp: 1569187287039046000,
    value: {
      comments: [],
      title: 'Hello World'
    }
  }
}

Time Traveling ๐Ÿ•“๐Ÿ•’๐Ÿ•‘

At a storage level records are immutable and every change results in a new version. By default the latest version is returned.

There is no public API support for this (ironically we ran out of time ๐Ÿฅ๐Ÿคฃ) but as we have the foundations in place as detailed, we envision an API like the following being completely possible:

get last 10 revisions of a post:

exile.get('posts/${post_id}', {last: 10})

get versions between timestamps:

exile.get('posts/${post_id}', {from: 1569186663, to: 1569187763})

exile's People

Contributors

bgottlob avatar evadne avatar holsee avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.