mintdb-server 0.1.0-beta.2

MintDB is an open source document based database built in Rust.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
<p align="center">
    <img width="400" src="img/logo.svg" alt="mintDB Icon">
</p>
<h2 align="center">An Open Source Graph Database</h2>
<p align="center">
    <img src="https://img.shields.io/badge/version-0.1.0beta-10d99d">
    <img src="https://img.shields.io/badge/built_with-Rust-dca282.svg">
    <img src="https://img.shields.io/badge/license-MIT-critical">
    <a href="https://www.linkedin.com/in/eric-rodriguez-3a402811b/"><img src="https://img.shields.io/badge/linkedIn-connect-4777AF"></a>
</p>
*** For demonstrative purposes only

Introducing MintDB - a powerful, open-source embedded graph database built in Rust. With MintDB, you can easily manage and query your data using a simplified SQL-like JSON object and subscribe to real-time updates and events. The database supports relationships, offers both depth-first and breadth-first search capabilities, and comes with a built-in admin panel for visualizing and updating your data. The user interface is built with Vanilla Javascript, making it a lightweight and powerful solution. MintDB's simple API is perfect for modern web, mobile, and desktop applications, providing a secure and efficient way to manage your data.

<p align="center">
    <img width="400" src="img/db.png">
    <img width="400" src="img/pg.png">
</p>

# Features 
- A user-friendly admin dashboard for managing your data
- A SQL and Websocket playground for testing queries and subscriptions
- Support for ACID transactions to ensure data integrity
- User authentication for secure access to your data
- A SQL API endpoint for querying your data
- A Websocket message publishing endpoint for real-time updates
- Real-time Websocket subscriptions for monitoring table, document, and key mutations
- [TypeScript SDK](https://www.npmjs.com/package/mintdb-js)

### Dependencies
```toml
[dependencies]
futures = "0.3.25"
mintdb = { path = "lib"}
once_cell = "1.16.0"
serde = { version = "1.0.148", features = ["derive", "rc"] }
serde_json = "1.0.89"
tokio = { version = "1.22.0", features = ["macros", "sync", "rt-multi-thread", "signal"]}
tokio-stream = "0.1.11"
uuid = { version = "1.2.2", features = ["serde", "v4"]}
warp = "0.3.3"
thiserror = "1.0.37"
```
# Get Started

# SQL API
Send a POST request to http://127.0.0.1:8000/sql with the following format
```json
{
    "stmt": "String",
    "tb": "String",
    "doc": "String",
    "data": Map<String, JSONValue>,
    "topic": "String",
    "user_id": Option<number>,
    "message": "String",
}
```
### SELECT

Get One

Read a user
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "SELECT",
    "tb": "person",
    "doc": "person:1",
    "data": {},
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
Get All

Read all users
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "SELECT",
    "tb": "person",
    "doc": "*",
    "data": {},
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```

### CREATE
Create a user

Returns an error if the person already exists
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "CREATE",
    "tb": "person",
    "doc": "person:4",
    "data": {
        "name": "Ricky",
        "email": "ricky@gmail.com",
        "city": "Miami",
    },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### MERGE
Merge data to a user document. 

This will create a new table or document if they do not exist.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "MERGE",
    "tb": "person",
    "doc": "person:4",
    "data": {
        "phone": "305 578 5899"
    },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### DELETE
Delete a document
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "DELETE",
    "tb": "person",
    "doc": "person:4",
    "data": {},
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### FIND
Find data by passing a Map of values to match. 

Returns a vector of documents that match any of the parameters.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "FIND",
    "tb": "person",
    "doc": "",
    "data": { "phone": "305 578 5899" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### MATCH
Find data by passing a Map of values to match. 

Returns a vector of documents that match all the parameters.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "MATCH",
    "tb": "person",
    "doc": "",
    "data": { "state": "FL", "name": "Lucy" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```

### COMPARE
Find data by passing a Map of:
```json
{
    "lhs": <String>, // The key of the document to compare.
    "op" <Operator>, // The operation to compare ("==", "!=" "<=" "<" ">=" ">" "contains" "icontains")
    "rhs": <String | Number> // The value to compare. Contains and icontains must use String
}
```

Returns a vector of documents that match the parameters.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "MATCH",
    "tb": "car",
    "doc": "",
    "data": { "lhs": "make", "op": "==", "rhs": "Suzuki" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```

Returns a vector of documents where the key is not the rhs.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "MATCH",
    "tb": "car",
    "doc": "",
    "data": { "lhs": "make", "op": "!=", "rhs": "Suzuki" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```

Returns a vector of documents where the key is greater than or equal to the rhs.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "MATCH",
    "tb": "car",
    "doc": "",
    "data": { "lhs": "year", "op": ">=", "rhs": 2000 },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```

Returns a vector of documents where the key is greater than the rhs.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "MATCH",
    "tb": "car",
    "doc": "",
    "data": { "lhs": "year", "op": ">", "rhs": 2000 },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```

Returns a vector of documents where the key is less than or equal to the rhs.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "MATCH",
    "tb": "car",
    "doc": "",
    "data": { "lhs": "year", "op": "<=", "rhs": 2000 },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```

Returns a vector of documents where the key is less than the rhs.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "MATCH",
    "tb": "car",
    "doc": "",
    "data": { "lhs": "year", "op": "<", "rhs": 2000 },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```

Returns a vector of documents where the key is a string and contains the value. Case sensitive.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "MATCH",
    "tb": "car",
    "doc": "",
    "data": { "lhs": "model", "op": "contains", "rhs": "AMG" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```

Returns a vector of documents where the key is a string and contains the value. Case insensitive.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "MATCH",
    "tb": "car",
    "doc": "",
    "data": { "lhs": "model", "op": "icontains", "rhs": "amg" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### INFO
Get the keys of all tables in the Database
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "INFO",
    "tb": "",
    "doc": "",
    "data": {},
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### ADD
Add a table if it does not exist
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "ADD",
    "tb": "car",
    "doc": "",
    "data": {},
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### PUSH
Pushes a value to an array specified by the key. 

If the key exists and is not an array, an error will be returned. If the key does not exist, a new array is created and the key value pair is inserted into the document.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "PUSH",
    "tb": "car",
    "doc": "car:1",
    "data": { "key":"parts", "value":"engine" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### PUT
Puts a value into a specified key. 

If the key exists, the value will be overwritten. If the key does not exist, the key value pair is inserted into the document.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "PUT",
    "tb": "car",
    "doc": "car:1",
    "data": { "key":"owner", "value":"person:1" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### REL
Relates two documents with a specified relationship. 

The relationship is added as an array in the key "rel:<rel>" and can be used for BFS and DFS
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "REL",
    "tb": "person",
    "doc": "person:1",
    "data": { "rel_tb":"person", "rel_doc":"person:2", "rel":"like" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### BFS
Performs a BFS search for the target document with the specified relationship. 

The response returns either the first node containing the target, or an error message if not found.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "BFS",
    "tb": "person",
    "doc": "person:1",
    "data": { "target":"person:2", "rel":"like" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```
### DFS
Performs a DFS search for the target document with the specified relationship. 

The response returns either the first node containing the target, or an error message if not found.
```
curl -X POST 'http://127.0.0.1:8000/sql' -H 'Content-Type: application/json' -d '{
    "stmt": "DFS",
    "tb": "person",
    "doc": "person:1",
    "data": { "target":"person:2", "rel":"like" },
    "topic": "",
    "user_id": 1,
    "message": ""    
}' 
```

# User Authentication

Send a POST request to http://127.0.0.1:8000/auth with the following format
```json
{
    "event": "String",
    "username": "String",
    "password": "String",
}
```
### SignIn
Returns a JSON Web Token
```
curl -X POST 'http://127.0.0.1:8000/auth' -H 'Content-Type: application/json' -d '{
    "event": "signin",
    "username": "Lucy@gmail.com",
    "password": "abc123"
}' 
```
### SignUp
Returns a JSON Web Token
```
curl -X POST 'http://127.0.0.1:8000/auth' -H 'Content-Type: application/json' -d '{
    "event": "signup",
    "username": "Lucy@gmail.com",
    "password": "abc123"
}' 
```
### SignOut
```
curl -X POST 'http://127.0.0.1:8000/auth' -H 'Content-Type: application/json' -H 'Authorization: Bearer <JWT>' -d '{
    "event": "signout",
    "username": "",
    "password": ""
}' 
```
# Websocket Connection

Send a POST request to http://127.0.0.1:8000/register with the JSON payload { "user_id": i32 }
```
curl -X POST 'http://127.0.0.1:8000/register' -H 'Content-Type: application/json' -d '{ "user_id": 1 }' 
```

The response will be the websocket connection URL for the client
```JSON
{
  "url": "ws://127.0.0.1:8000/ws/4cc7c8ba4c144788a0e9bf9ee6840489"
}
```

Connect to the websocket url and add subscription topics from websocket client as JSON payload { "topics": Vec< String > }
```JSON
{ "topics": ["dogs", "sports"] }
```
Send a message to a topic channel via POST request to http://127.0.0.1:8000/publish with JSON payload { "user_id": i32, "message": String, topic: String }
```
{"user_id": "4cc7c8ba4c144788a0e9bf9ee6840489", "topic": "sports", "message": "Hello, world!"}
```
## Subscriptions
You may subscribe to mutations made within a table, document, or key. Given the table "person", document "person:1", and key "phone", the following subscriptions will receive the updated document on changes. Send the JSON object as a message to the websocket.

Subscribe to all mutations in table
```JSON
{ "topics": ["person"] }
```

Subscribe to all mutations in document person:1
```JSON
{ "topics": ["person:1"] }
```

Subscribe to all mutations of the key "phone" made to the person:1 document
```JSON
{ "topics": ["person:1:phone"] }
```
### Unregister a client
Send a DELETE request to http://127.0.0.1:8000/register/{user_id}
```
curl -X DELETE 'http://127.0.0.1:8000/register/{user_id}' 
```

### Endpoints
- Admin Console: GET / manage the database from a web UI
- SQL API: POST /sql
- Auth API: POST /auth
- Publish API: POST /publish Post to publish messages to subscribers
- Health API: POST /health Post to check server status
- Register: POST /register Responds with a websocket endpoint to connect to
- WebSocket Server ws://127.0.0.1:8000/ws/{id}