Add initial documentation

This commit is contained in:
Tobie Morgan Hitchcock 2016-02-26 22:28:02 +00:00
parent d74af9681e
commit 6f1f39226f
4 changed files with 398 additions and 0 deletions

110
docs/ENDPOINTS.md Normal file
View file

@ -0,0 +1,110 @@
# Endpoints
This document describes RESTful http endpoints which can be used to query and manipulate the database.
---
### SQL
*Endpoints*
- `POST` `https://api.surreal.io/sql` Execute SQL contained in HTTP body
---
### Tables
*Storage*
- `/surreal/{id}/{db}/{table}`
*Retrieve*
- `SCAN` `/surreal/{id}/{db}/{table}/` `/surreal/{id}/{db}/{table}/~`
*Endpoints*
- `GET` `https://api.surreal.io/{table}` SELECT * FROM {table}
- `POST` `https://api.surreal.io/{table}` INSERT INTO {table}
- `DEL` `https://api.surreal.io/{table}` DELETE FROM {table}
---
### Records
*Storage*
- `/surreal/{id}/{db}/{table}/{key}`
*Retrieve*
- `GET` `/surreal/{id}/{db}/{table}/{key}`
*Endpoints*
- `GET` `https://api.surreal.io/{table}/{key}` SELECT * FROM @{table}:{id}
- `PUT` `https://api.surreal.io/{table}/{key}` UPDATE @{table}:{id} CONTENT {}
- `POST` `https://api.surreal.io/{table}/{key}` CREATE @{table}:{id} CONTENT {}
- `PATCH` `https://api.surreal.io/{table}/{key}` MODIFY @{table}:{id} CONTENT {}
- `TRACE` `https://api.surreal.io/{table}/{key}` SELECT HISTORY FROM @{table}:{id}
- `DEL` `https://api.surreal.io/{table}/{key}` DELETE @{table}:{id}
---
### History
*Storage*
- `/surreal/{id}/{db}/{table}/•/{key}/{time}`
*Retrieve*
- `SCAN` `/surreal/{id}/{db}/{table}/•/{key}/` `/surreal/{id}/{db}/{table}/•/{key}/~`
*Endpoints*
- `GET` `https://api.surreal.io/{table}/{key}?time={time}` SELECT record as it looked at {time}
---
### Joins
*Storage*
- `/surreal/{id}/{db}/{table}/†/{key}/{type}/{foreignkey}`
*Retrieve*
- `SCAN` `/surreal/{id}/{db}/{table}/†/{key}/{type}/` `/surreal/{id}/{db}/{table}/†/{key}/{type}/~`
*Endpoints*
- `PUT` `https://api.surreal.io/{table}/{key}/join/{type}` CREATE (in|out) join of {type}
- `GET` `https://api.surreal.io/{table}/{key}/join/{type}` SELECT (in|out|inout) joins of {type}
- `GET` `https://api.surreal.io/{table}/{key}/join/{type}/{joinkey}` SELECT (in|out) join of {type} with id {joinkey}
- `DEL` `https://api.surreal.io/{table}/{key}/join/{type}/{joinkey}` DELETE (in|out) join of {type} with id {joinkey}
---
### Relations
*Storage*
- `/surreal/{id}/{db}/{table}/(«|»)/{key}/{type}/{foreignkey}`
*Retrieve*
- `SCAN` `/surreal/{id}/{db}/{table}/(«|»)/{key}/{type}/` `/surreal/{id}/{db}/{table}/(«|»)/{key}/{type}/~`
*Endpoints*
- `POST` `https://api.surreal.io/{table}/{key}/(in|out)/{type}/{vertexkey}` CREATE (in|out) relationship of {type} to {vertexkey}
- `GET` `https://api.surreal.io/{table}/{key}/(in|out|inout)/{type}` SELECT (in|out|inout) relationships of {type}
- `GET` `https://api.surreal.io/{table}/{key}/(in|out)/{type}/{edgekey}` SELECT (in|out) relationship of {type} with id {edgekey}
- `DEL` `https://api.surreal.io/{table}/{key}/(in|out)/{type}/{edgekey}` DELETE (in|out) relationship of {type} with id {edgekey}
---
### Events
*Storage*
- `/surreal/{id}/{db}/{table}/‡/{key}/{type}/{time}`
*Retrieve*
- `SCAN` `/surreal/{id}/{db}/{table}/‡/{key}/{type}/` `/surreal/{id}/{db}/{table}/‡/{key}/{type}/~`
*Endpoints*
- `GET` `https://api.surreal.io/{table}/{key}/events/{type}` SELECT events('login') ON @{table}:{id}
- `POST` `https://api.surreal.io/{table}/{key}/events/{type}` CREATE EVENT login ON @{table}:{id} WITH CONTENT {}
- `GET` `https://api.surreal.io/{table}/{key}/events/{type}/{time}` SELECT events('login') ON @{table}:{id} WHERE time={time}
- `POST` `https://api.surreal.io/{table}/{key}/events/{type}/{time}` CREATE EVENT login ON @{table}:{id} WITH CONTENT {} AT TIME {time}
- `DEL` `https://api.surreal.io/{table}/{key}/events/{type}/{time}` DELETE events('login') ON @{table}:{id} WHERE time={time}
---
### Search
- `GET` `https://api.surreal.io/search` Select all records in table

144
docs/QUERIES.md Normal file
View file

@ -0,0 +1,144 @@
# Queries
This document describes example SQL queries which can be used to query the database.
### CREATE
```sql
CREATE person SET age=28, name='Tobie'
```
```sql
CREATE @person:id /* Ensures record is blank */
CREATE @person:id SET age = 28, name = 'Tobie' /* ... and sets name+age */
CREATE @person:id SET age = 28, name = 'Tobie', tags = [] /* ... and sets `tags` to an empty set */
CREATE @person:id SET age = 28, name = 'Tobie', tags = ['old'] /* ... and sets `tags` to a set with 1 element */
```
### UPDATE
```sql
UPDATE person SET age=EMPTY
UPDATE person SET age=EMPTY WHERE age < 18
```
```sql
UPDATE @person:id /* Ensures record exists */
UPDATE @person:id SET age = 28, name = 'Tobie' /* ... and sets name+age */
UPDATE @person:id SET age = 28, name = 'Tobie', tags = NULL /* ... and sets `tags` to NULL */
UPDATE @person:id SET age = 28, name = 'Tobie', tags = [] /* ... and sets `tags` to an empty set */
UPDATE @person:id SET age = 28, name = 'Tobie', tags = ['old'] /* ... and sets `tags` to a set with 1 element */
UPDATE @person:id SET age = 28, name = 'Tobie', tags += ['new'], tags -= ['old'] /* ... and adds 'new' to `tags` and removes 'old' from `tags */
```
### MODIFY
```sql
MODIFY @person:id WITH {JSON}
```
### RELATE
```sql
RELATE friend FROM @person:one TO @person:two
```
### DELETE
```sql
DELETE person WHERE age < 18
```
```sql
DELETE @person:one, @person:two
```
### SELECT
```sql
SELECT FROM VIEW adults ON PERSON
```
```sql
SELECT * FROM person
SELECT *, both() FROM person
SELECT *, in(), out() FROM person
SELECT * FROM person WHERE account = 'abcum' ORDER BY (account, firstname, lastname)
SELECT mean(value) FROM cpu
SELECT mean(value)
SELECT mean(value) from cpu WHERE host = 'serverA' AND time > now() - 4h GROUP BY time(5m)
SELECT ALL FROM person WHERE tags ∋ "tag"
SELECT ALL FROM person WHERE tags.? = "tag"
SELECT ALL FROM person WHERE "tag" IN tags
SELECT ALL FROM person WHERE tags CONTAINS "tag"
SELECT ALL FROM person WHERE tags.? IN ["tag1", "tag2"]
SELECT ALL FROM person WHERE emails.?.value ~ "gmail.com" /* Any email address value matches 'gmail.com' */
SELECT ALL FROM person WHERE emails.*.value ~ "gmail.com" /* Every email address value matches 'gmail.com' */
SELECT ALL FROM person WHERE tags ∌ "tag"
SELECT ALL FROM person WHERE tags.* != "tag"
SELECT ALL FROM person WHERE "tag" NOT IN tags
SELECT ALL FROM person WHERE tags NOT CONTAINS "tag"
SELECT ALL FROM person WHERE tags.* NOT IN ["tag1", "tag2"]
SELECT ALL FROM person WHERE tags IN ["tag1", "tag2", "tag3"]
SELECT ALL FROM person WHERE "tag1" IN tags
SELECT *, :(friend|follow)/:person[age>=18,social=true] AS acquaintances FROM person WHERE acquaintances IN [@person:123]
SELECT *, :(friend|follow)/:person[age>=18,social=true] AS acquaintances FROM person WHERE acquaintances.firstname IN ['Tobie']
```
### VIEWS
```sql
DEFINE VIEW adults
MAP
`
if (meta.table == 'person') {
if (doc.firstname && doc.lastname) {
emit([doc.lastname, doc.firstname, meta.id], null)
}
if (doc:friend(person):name == 'Tobie') {
emit()
}
}
`
REDUCE
`
`
```
```sql
RESYNC VIEW adults
```
```sql
REMOVE VIEW adults
```
### INDEX
```sql
DEFINE INDEX name ON person COLUMNS lastname, firstname
DEFINE INDEX name ON person COLUMNS lastname, firstname, emails.0.value
DEFINE INDEX name ON person COLUMNS accounts, lastname, firstname, emails.0.value
```
```sql
RESYNC INDEX name ON person
```
```sql
REMOVE INDEX name ON person
```
### FIELD
```sql
DEFINE FIELD fullname ON person CODE `
let email = doc.emails ? _(doc.emails).pluck('value').first() : null;
return [doc.firstname, doc.middlename, doc.lastname, doc.username, email].filter(i => { return i }).join(' ');
`
```

22
docs/SECURITY.md Normal file
View file

@ -0,0 +1,22 @@
# Surreal
Surreal is a NoSQL Document and Graph database
---
### Authentication
- Accept connection on HTTP (RESTful)
- Check JWT token
- Get id from token *(account id)*
- Get db from token *(database name)*
- Check token against database `/surreal/{id}/{db}/!/tokens/{token}`
- `HTTP 403` if token does not exist
- Accept connection on HTTP (Websocket)
- Check JWT token
- Get id from token *(account id)*
- Get db from token *(database name)*
- Check token against database `/surreal/{id}/{db}/!/tokens/{token}`
- `HTTP 403` if token does not exist

122
docs/STORAGE.md Normal file
View file

@ -0,0 +1,122 @@
# Storage
Surreal can be used with any key-value storage which enables range scans. This document describes how the data is stored in the storage layer, so that it can be queried and manipulated quickly and efficiently.
**Base keys**
```bash
{$base} = "surreal" # This is the base key
```
The base key is used to separate the data used in SurrealDB from data used by other databases using the same key:value store.
```bash
{$auth} = "abcum" # This is the name of the auth account
```
The auth key is used to enable multi-tenancy of databases on SurrealDB. Each authenticated user is able to access databases underneath their own auth key only.
```bash
{$db} = "database" # This is the name of the database
```
The database key is used to separate data into multiple different databases under each multi-tenant installation.
**Unique ids**
Each view, table, and index is assigned a unique id, which is used instead of the name in each key:value pair. This allows for views, indexes, and tables to be deleted asynchronously, while at the same time a new one is created in its place with the same name.
**Data types**
Each data type is stored using a different symbol in the key:value pair.
```bash
¤ # Used to store view and index data
« # Used to store in edges
» # Used to store out edges
• # Used to store diffs to each record
‡ # Used to store time-series data
```
---
### Table
```bash
/{$base}/{$auth}/{$db}/!/tables/{$table} "{$tableid}"
# e.g.
/{$base}/{$auth}/{$db}/!/tables/people "1bd7ajq8"
```
### Field
```bash
/{$base}/{$auth}/{$db}/{$tableid}/!/field/{$field} "{CODE}"
# e.g.
/{$base}/{$auth}/{$db}/1bd7ajq8/!/field/fullname "return doc.fname + doc.lname"
```
### Items
```bash
/{$base}/{$auth}/{$db}/{$tableid}/{$id} ""
# e.g
/{$base}/{$auth}/{$db}/{$tableid}/UUID `{"name":"Tobie","age":18}`
```
*TRAIL*
```bash
/{$base}/{$auth}/{$db}/{$tableid}/•/{$id}/{$time} ""
# e.g
/{$base}/{$auth}/{$db}/{$tableid}/•/UUID/2016-01-29T22:42:56.478173947Z ""
```
*EVENT*
```bash
/{$base}/{$auth}/{$db}/{$tableid}/‡/{$id}/{$type}/{$time} ""
# e.g
/{$base}/{$auth}/{$db}/{$tableid}/‡/UUID/login/2016-01-29T22:42:56.478173947Z ""
```
*EDGES*
```bash
/{$base}/{$auth}/{$db}/{$tableid}/»/{$id}/{$type}/{$edgeid} ""
/{$base}/{$auth}/{$db}/{$typeid}/{$id} ""
/{$base}/{$auth}/{$db}/{$tableid}/«/{$id}/{$type}/{$edgeid} ""
# e.g
/{$base}/{$auth}/{$db}/{$tableid}/»/1537/follow/9563 ""
/{$base}/{$auth}/{$db}/{$typeid}/9563 `{"in":"1537","out":"5295"}`
/{$base}/{$auth}/{$db}/{$tableid}/«/5295/follow/9563 ""
```
### Views
```bash
/{$base}/{$auth}/{$db}/!/views/{$view} "{$viewid}"
# e.g.
/{$base}/{$auth}/{$db}/!/views/test "9jh1ebj4"
/{$base}/{$auth}/{$db}/!/views/test/map "emit()"
/{$base}/{$auth}/{$db}/!/views/test/red "return count()"
```
```bash
/{$base}/{$auth}/{$db}/¤/{$viewid}/COLUMNS "{$id}"
# e.g
/{$base}/{$auth}/{$db}/¤/{$viewid}/[lastname,firstname] "@person:1342"
```
### Index
```bash
/{$base}/{$auth}/{$db}/{$tableid}/!/index/{$index} "{$indexid}"
/{$base}/{$auth}/{$db}/{$tableid}/!/index/{$index}/col "COLUMNS"
# e.g
/{$base}/{$auth}/{$db}/{$tableid}/!/index/names "5gbq3hm5"
/{$base}/{$auth}/{$db}/1bd7ajq8/!/index/names/col "lastname|firstname|emails.0.value"
```
```bash
/{$base}/{$auth}/{$db}/{$tableid}/¤/{$indexid}/COLUMNS "{$id}"
# e.g
/{$base}/{$auth}/{$db}/{$tableid}/¤/{$indexid}/[lastname,firstname] "@person:1342"
```