datomic-flare 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/docs/CURL.md ADDED
@@ -0,0 +1,781 @@
1
+ # Datomic Flare
2
+
3
+ A web server that offers an HTTP/JSON API for interacting with [Datomic](https://www.datomic.com) databases.
4
+
5
+ ![The image features a logo with curved lines forming a tesseract, suggesting distortion and movement like space-time.](https://media.githubusercontent.com/media/gbaptista/assets/refs/heads/main/datomic-flare/datomic-flare-canvas.png)
6
+
7
+ _This is not an official Datomic project or documentation and it is not affiliated with Datomic in any way._
8
+
9
+ ## TL;DR and Quick Start
10
+
11
+ Ensure you have [Java](https://clojure.org/guides/install_clojure#java) and [Clojure](https://clojure.org/guides/install_clojure) installed.
12
+
13
+ ```bash
14
+ cp .env.example .env
15
+
16
+ ```
17
+
18
+ ```bash
19
+ clj -M:run
20
+
21
+ ```
22
+
23
+ ```text
24
+ [main] INFO flare.components.server - Starting server on http://0.0.0.0:3042 as peer
25
+
26
+ ```
27
+
28
+ Ensure you have [curl](https://github.com/curl/curl), [bb](https://github.com/babashka/babashka), and [jq](https://github.com/jqlang/jq) installed.
29
+
30
+ Transact a Schema:
31
+
32
+
33
+ ```bash
34
+ echo '
35
+ [{:db/ident :book/title
36
+ :db/valueType :db.type/string
37
+ :db/cardinality :db.cardinality/one
38
+ :db/doc "The title of the book."}
39
+
40
+ {:db/ident :book/genre
41
+ :db/valueType :db.type/string
42
+ :db/cardinality :db.cardinality/one
43
+ :db/doc "The genre of the book."}]
44
+ ' \
45
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
46
+ | curl -s http://localhost:3042/datomic/transact \
47
+ -X POST \
48
+ -H "Content-Type: application/json" \
49
+ --data-binary @- <<JSON \
50
+ | jq
51
+ {
52
+ "data": $(cat)
53
+ }
54
+ JSON
55
+ ```
56
+
57
+ Assert Facts:
58
+
59
+
60
+ ```bash
61
+ echo '
62
+ [{:db/id -1
63
+ :book/title "The Tell-Tale Heart"
64
+ :book/genre "Horror"}]
65
+ ' \
66
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
67
+ | curl -s http://localhost:3042/datomic/transact \
68
+ -X POST \
69
+ -H "Content-Type: application/json" \
70
+ --data-binary @- <<JSON \
71
+ | jq
72
+ {
73
+ "data": $(cat)
74
+ }
75
+ JSON
76
+ ```
77
+
78
+ Read the Data by Querying:
79
+
80
+
81
+ ```bash
82
+ echo '
83
+ [:find ?e ?title ?genre
84
+ :where [?e :book/title ?title]
85
+ [?e :book/genre ?genre]]
86
+ ' \
87
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
88
+ | curl -s http://localhost:3042/datomic/q \
89
+ -X GET \
90
+ -H "Content-Type: application/json" \
91
+ --data-binary @- <<JSON \
92
+ | jq
93
+ {
94
+ "inputs": [
95
+ {
96
+ "database": {
97
+ "latest": true
98
+ }
99
+ }
100
+ ],
101
+ "query": $(cat)
102
+ }
103
+ JSON
104
+ ```
105
+
106
+ ```json
107
+ {
108
+ "data": [
109
+ [
110
+ 4611681620380877802,
111
+ "The Tell-Tale Heart",
112
+ "Horror"
113
+ ]
114
+ ]
115
+ }
116
+ ```
117
+
118
+
119
+ - [TL;DR and Quick Start](#tldr-and-quick-start)
120
+ - [Running](#running)
121
+ - [Quick Start](#quick-start)
122
+ - [CURL](#curl)
123
+ - [Ruby](#ruby)
124
+ - [JavaScript](#javascript)
125
+ - [Python](#python)
126
+ - [Usage](#usage)
127
+ - [Meta](#meta)
128
+ - [Creating a Database](#creating-a-database)
129
+ - [Deleting a Database](#deleting-a-database)
130
+ - [Listing Databases](#listing-databases)
131
+ - [Transacting Schema](#transacting-schema)
132
+ - [Asserting Facts](#asserting-facts)
133
+ - [Reading Data by Entity](#reading-data-by-entity)
134
+ - [Reading Data by Querying](#reading-data-by-querying)
135
+ - [Accumulating Facts](#accumulating-facts)
136
+ - [Retracting Facts](#retracting-facts)
137
+ - [About](#about)
138
+ - [Characteristics](#characteristics)
139
+ - [Trade-offs](#trade-offs)
140
+ - [Development](#development)
141
+
142
+ ## Running
143
+
144
+ The server can operate in _Client Mode_, using `com.datomic/client-pro` to connect to a Datomic Peer Server, or in _Peer Mode_, embedding `com.datomic/peer` to establish a _Peer_ directly within the server.
145
+
146
+ Copy the `.env.example` file and fill it with the appropriate information.
147
+
148
+ ```bash
149
+ cp .env.example .env
150
+
151
+ ```
152
+
153
+ If you want _Client Mode_:
154
+ ```bash
155
+ FLARE_PORT=3042
156
+ FLARE_BIND=0.0.0.0
157
+
158
+ FLARE_MODE=client
159
+
160
+ FLARE_CLIENT_ENDPOINT=localhost:8998
161
+ FLARE_CLIENT_SECRET=unsafe-secret
162
+ FLARE_CLIENT_ACCESS_KEY=unsafe-key
163
+ FLARE_CLIENT_DATABASE_NAME=my-datomic-database
164
+
165
+ ```
166
+
167
+ If you want _Peer Mode_:
168
+ ```bash
169
+ FLARE_PORT=3042
170
+ FLARE_BIND=0.0.0.0
171
+
172
+ FLARE_MODE=peer
173
+
174
+ FLARE_PEER_CONNECTION_URI="datomic:sql://my-datomic-database?jdbc:postgresql://localhost:5432/my-datomic-storage?user=datomic-user&password=unsafe"
175
+
176
+ ```
177
+
178
+ Ensure you have [Java](https://clojure.org/guides/install_clojure#java) and [Clojure](https://clojure.org/guides/install_clojure) installed.
179
+
180
+ Run the server:
181
+
182
+ ```bash
183
+ clj -M:run
184
+
185
+ ```
186
+
187
+ ```text
188
+ [main] INFO flare.components.server - Starting server on http://0.0.0.0:3042 as peer
189
+
190
+ ```
191
+
192
+ You should be able to start firing requests to the server:
193
+
194
+
195
+ ```bash
196
+ curl -s http://localhost:3042/meta \
197
+ -X GET \
198
+ -H "Content-Type: application/json" \
199
+ | jq
200
+ ```
201
+
202
+ ```json
203
+ {
204
+ "data": {
205
+ "datomic-flare": "1.0.0",
206
+ "org.clojure/clojure": "1.12.0",
207
+ "com.datomic/peer": "1.0.7187",
208
+ "com.datomic/client-pro": "1.0.81"
209
+ }
210
+ }
211
+ ```
212
+
213
+ ## Quick Start
214
+
215
+ ### CURL
216
+ TODO
217
+
218
+ ### Ruby
219
+ TODO
220
+
221
+ ### JavaScript
222
+ TODO
223
+
224
+ ### Python
225
+ TODO
226
+
227
+ ## Usage
228
+
229
+ Ensure you have [curl](https://github.com/curl/curl), [bb](https://github.com/babashka/babashka), and [jq](https://github.com/jqlang/jq) installed.
230
+
231
+ ### Meta
232
+
233
+
234
+ ```bash
235
+ curl -s http://localhost:3042/meta \
236
+ -X GET \
237
+ -H "Content-Type: application/json" \
238
+ | jq
239
+ ```
240
+
241
+ ```json
242
+ {
243
+ "data": {
244
+ "datomic-flare": "1.0.0",
245
+ "org.clojure/clojure": "1.12.0",
246
+ "com.datomic/peer": "1.0.7187",
247
+ "com.datomic/client-pro": "1.0.81"
248
+ }
249
+ }
250
+ ```
251
+
252
+ ### Creating a Database
253
+
254
+
255
+ ```bash
256
+ curl -s http://localhost:3042/datomic/create-database \
257
+ -X POST \
258
+ -H "Content-Type: application/json" \
259
+ -d '
260
+ {
261
+ "name": "moonlight"
262
+ }
263
+ ' \
264
+ | jq
265
+ ```
266
+
267
+ ```json
268
+ {
269
+ "data": true
270
+ }
271
+ ```
272
+
273
+ ### Deleting a Database
274
+
275
+
276
+ ```bash
277
+ curl -s http://localhost:3042/datomic/delete-database \
278
+ -X DELETE \
279
+ -H "Content-Type: application/json" \
280
+ -d '
281
+ {
282
+ "name": "moonlight"
283
+ }
284
+ ' \
285
+ | jq
286
+ ```
287
+
288
+ ```json
289
+ {
290
+ "data": true
291
+ }
292
+ ```
293
+
294
+ ### Listing Databases
295
+
296
+ Flare on Peer Mode:
297
+ ```bash
298
+ curl -s http://localhost:3042/datomic/get-database-names \
299
+ -X GET \
300
+ -H "Content-Type: application/json" \
301
+ | jq
302
+
303
+ ```
304
+
305
+ Flare on Client Mode
306
+ ```bash
307
+ curl -s http://localhost:3042/datomic/list-databases \
308
+ -X GET \
309
+ -H "Content-Type: application/json" \
310
+ | jq
311
+
312
+ ```
313
+
314
+ ```json
315
+ {
316
+ "data": [
317
+ "my-datomic-database"
318
+ ]
319
+ }
320
+
321
+ ```
322
+
323
+ ### Transacting Schema
324
+
325
+
326
+ ```bash
327
+ echo '
328
+ [{:db/ident :book/title
329
+ :db/valueType :db.type/string
330
+ :db/cardinality :db.cardinality/one
331
+ :db/doc "The title of the book."}
332
+
333
+ {:db/ident :book/genre
334
+ :db/valueType :db.type/string
335
+ :db/cardinality :db.cardinality/one
336
+ :db/doc "The genre of the book."}
337
+
338
+ {:db/ident :book/published_at_year
339
+ :db/valueType :db.type/long
340
+ :db/cardinality :db.cardinality/one
341
+ :db/doc "The year the book was first published."}]
342
+ ' \
343
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
344
+ | curl -s http://localhost:3042/datomic/transact \
345
+ -X POST \
346
+ -H "Content-Type: application/json" \
347
+ --data-binary @- <<JSON \
348
+ | jq
349
+ {
350
+ "data": $(cat)
351
+ }
352
+ JSON
353
+ ```
354
+
355
+ ```json
356
+ {
357
+ "data": {
358
+ "db-before": "datomic.db.Db@1cf55f93",
359
+ "db-after": "datomic.db.Db@1bdd0be0",
360
+ "tx-data": [
361
+ [1003, 50, "Sun Sep 22 08:58:31 BRT 2024", 1003, true],
362
+ [74, 10, "published_at_year", 1003, true],
363
+ [74, 40, 22, 1003, true],
364
+ [74, 41, 35, 1003, true],
365
+ [74, 62, "The year the book was first published.", 1003, true],
366
+ [0, 13, 74, 1003, true]
367
+ ],
368
+ "tempids": {
369
+ "-9223300668110593560": 72,
370
+ "-9223300668110593559": 73,
371
+ "-9223300668110593558": 74
372
+ }
373
+ }
374
+ }
375
+ ```
376
+
377
+ ### Asserting Facts
378
+
379
+
380
+ ```bash
381
+ echo '
382
+ [{:db/id -1
383
+ :book/title "Pride and Prejudice"
384
+ :book/genre "Romance"
385
+ :book/published_at_year 1813}]
386
+ ' \
387
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
388
+ | curl -s http://localhost:3042/datomic/transact \
389
+ -X POST \
390
+ -H "Content-Type: application/json" \
391
+ --data-binary @- <<JSON \
392
+ | jq
393
+ {
394
+ "data": $(cat)
395
+ }
396
+ JSON
397
+ ```
398
+
399
+ ```json
400
+ {
401
+ "data": {
402
+ "db-before": "datomic.db.Db@39bb3c53",
403
+ "db-after": "datomic.db.Db@d8d15290",
404
+ "tx-data": [
405
+ [1004, 50, "Sun Sep 22 08:58:31 BRT 2024", 1004, true],
406
+ [1005, 72, "Pride and Prejudice", 1004, true],
407
+ [1005, 73, "Romance", 1004, true],
408
+ [1005, 74, 1813, 1004, true]
409
+ ],
410
+ "tempids": {
411
+ "-1": 4611681620380877805
412
+ }
413
+ }
414
+ }
415
+ ```
416
+
417
+
418
+
419
+ ```bash
420
+ echo '
421
+ [{:db/id -1
422
+ :book/title "Near to the Wild Heart"
423
+ :book/genre "Novel"
424
+ :book/published_at_year 1943}
425
+ {:db/id -2
426
+ :book/title "A Study in Scarlet"
427
+ :book/genre "Detective"
428
+ :book/published_at_year 1887}
429
+ {:db/id -3
430
+ :book/title "The Tell-Tale Heart"
431
+ :book/genre "Horror"
432
+ :book/published_at_year 1843}]
433
+ ' \
434
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
435
+ | curl -s http://localhost:3042/datomic/transact \
436
+ -X POST \
437
+ -H "Content-Type: application/json" \
438
+ --data-binary @- <<JSON \
439
+ | jq
440
+ {
441
+ "data": $(cat)
442
+ }
443
+ JSON
444
+ ```
445
+
446
+ ```json
447
+ {
448
+ "data": {
449
+ "db-before": "datomic.db.Db@d8d15290",
450
+ "db-after": "datomic.db.Db@19234447",
451
+ "tx-data": [
452
+ [1006, 50, "Sun Sep 22 08:58:31 BRT 2024", 1006, true],
453
+ [1007, 72, "Near to the Wild Heart", 1006, true],
454
+ [1007, 73, "Novel", 1006, true],
455
+ [1007, 74, 1943, 1006, true],
456
+ [1008, 72, "A Study in Scarlet", 1006, true],
457
+ [1008, 73, "Detective", 1006, true],
458
+ [1008, 74, 1887, 1006, true],
459
+ [1009, 72, "The Tell-Tale Heart", 1006, true],
460
+ [1009, 73, "Horror", 1006, true],
461
+ [1009, 74, 1843, 1006, true]
462
+ ],
463
+ "tempids": {
464
+ "-1": 4611681620380877807,
465
+ "-2": 4611681620380877808,
466
+ "-3": 4611681620380877809
467
+ }
468
+ }
469
+ }
470
+ ```
471
+
472
+ ### Reading Data by Entity
473
+
474
+
475
+ ```bash
476
+ curl -s http://localhost:3042/datomic/entity \
477
+ -X GET \
478
+ -H "Content-Type: application/json" \
479
+ -d '
480
+ {
481
+ "database": {
482
+ "latest": true
483
+ },
484
+ "id": 4611681620380877807
485
+ }
486
+ ' \
487
+ | jq
488
+ ```
489
+
490
+ ```json
491
+ {
492
+ "data": {
493
+ ":book/title": "Near to the Wild Heart",
494
+ ":book/genre": "Novel",
495
+ ":book/published_at_year": 1943,
496
+ ":db/id": 4611681620380877807
497
+ }
498
+ }
499
+ ```
500
+
501
+ ### Reading Data by Querying
502
+
503
+
504
+ ```bash
505
+ echo '
506
+ [:find ?e ?title ?genre ?year
507
+ :where [?e :book/title ?title]
508
+ [?e :book/genre ?genre]
509
+ [?e :book/published_at_year ?year]]
510
+ ' \
511
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
512
+ | curl -s http://localhost:3042/datomic/q \
513
+ -X GET \
514
+ -H "Content-Type: application/json" \
515
+ --data-binary @- <<JSON \
516
+ | jq
517
+ {
518
+ "inputs": [
519
+ {
520
+ "database": {
521
+ "latest": true
522
+ }
523
+ }
524
+ ],
525
+ "query": $(cat)
526
+ }
527
+ JSON
528
+ ```
529
+
530
+ ```json
531
+ {
532
+ "data": [
533
+ [
534
+ 4611681620380877808,
535
+ "A Study in Scarlet",
536
+ "Detective",
537
+ 1887
538
+ ],
539
+ [
540
+ 4611681620380877807,
541
+ "Near to the Wild Heart",
542
+ "Novel",
543
+ 1943
544
+ ],
545
+ [
546
+ 4611681620380877809,
547
+ "The Tell-Tale Heart",
548
+ "Horror",
549
+ 1843
550
+ ],
551
+ [
552
+ 4611681620380877805,
553
+ "Pride and Prejudice",
554
+ "Romance",
555
+ 1813
556
+ ]
557
+ ]
558
+ }
559
+ ```
560
+
561
+
562
+ ```bash
563
+ echo '
564
+ [:find ?e ?title ?genre ?year
565
+ :in $ ?title
566
+ :where [?e :book/title ?title]
567
+ [?e :book/genre ?genre]
568
+ [?e :book/published_at_year ?year]]
569
+ ' \
570
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
571
+ | curl -s http://localhost:3042/datomic/q \
572
+ -X GET \
573
+ -H "Content-Type: application/json" \
574
+ --data-binary @- <<JSON \
575
+ | jq
576
+ {
577
+ "inputs": [
578
+ {
579
+ "database": {
580
+ "latest": true
581
+ }
582
+ },
583
+ "The Tell-Tale Heart"
584
+ ],
585
+ "query": $(cat)
586
+ }
587
+ JSON
588
+ ```
589
+
590
+ ```json
591
+ {
592
+ "data": [
593
+ [
594
+ 4611681620380877809,
595
+ "The Tell-Tale Heart",
596
+ "Horror",
597
+ 1843
598
+ ]
599
+ ]
600
+ }
601
+ ```
602
+
603
+ ### Accumulating Facts
604
+
605
+
606
+ ```bash
607
+ echo '
608
+ [{:db/id 4611681620380877806 :book/genre "Gothic"}]
609
+ ' \
610
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
611
+ | curl -s http://localhost:3042/datomic/transact \
612
+ -X POST \
613
+ -H "Content-Type: application/json" \
614
+ --data-binary @- <<JSON \
615
+ | jq
616
+ {
617
+ "data": $(cat)
618
+ }
619
+ JSON
620
+ ```
621
+
622
+ ```json
623
+ {
624
+ "data": {
625
+ "db-before": "datomic.db.Db@19234447",
626
+ "db-after": "datomic.db.Db@6f78a7c",
627
+ "tx-data": [
628
+ [1010, 50, "Sun Sep 22 08:58:31 BRT 2024", 1010, true],
629
+ [1006, 73, "Gothic", 1010, true]
630
+ ],
631
+ "tempids": {
632
+ }
633
+ }
634
+ }
635
+ ```
636
+
637
+ ### Retracting Facts
638
+
639
+ Retract the value of an attribute:
640
+
641
+
642
+ ```bash
643
+ echo '
644
+ [[:db/retract 4611681620380877806 :book/genre "Gothic"]]
645
+ ' \
646
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
647
+ | curl -s http://localhost:3042/datomic/transact \
648
+ -X POST \
649
+ -H "Content-Type: application/json" \
650
+ --data-binary @- <<JSON \
651
+ | jq
652
+ {
653
+ "data": $(cat)
654
+ }
655
+ JSON
656
+ ```
657
+
658
+ ```json
659
+ {
660
+ "data": {
661
+ "db-before": "datomic.db.Db@6f78a7c",
662
+ "db-after": "datomic.db.Db@89bedc15",
663
+ "tx-data": [
664
+ [1011, 50, "Sun Sep 22 08:58:31 BRT 2024", 1011, true],
665
+ [1006, 73, "Gothic", 1011, false]
666
+ ],
667
+ "tempids": {
668
+ }
669
+ }
670
+ }
671
+ ```
672
+
673
+ Retract an attribute:
674
+
675
+
676
+ ```bash
677
+ echo '
678
+ [[:db/retract 4611681620380877804 :book/genre]]
679
+ ' \
680
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
681
+ | curl -s http://localhost:3042/datomic/transact \
682
+ -X POST \
683
+ -H "Content-Type: application/json" \
684
+ --data-binary @- <<JSON \
685
+ | jq
686
+ {
687
+ "data": $(cat)
688
+ }
689
+ JSON
690
+ ```
691
+
692
+ ```json
693
+ {
694
+ "data": {
695
+ "db-before": "datomic.db.Db@89bedc15",
696
+ "db-after": "datomic.db.Db@4fa1fea2",
697
+ "tx-data": [
698
+ [1012, 50, "Sun Sep 22 08:58:31 BRT 2024", 1012, true]
699
+ ],
700
+ "tempids": {
701
+ }
702
+ }
703
+ }
704
+ ```
705
+
706
+ Retract an entity:
707
+
708
+
709
+ ```bash
710
+ echo '
711
+ [[:db/retractEntity 4611681620380877805]]
712
+ ' \
713
+ | bb -e '(pr-str (edn/read-string (slurp *in*)))' \
714
+ | curl -s http://localhost:3042/datomic/transact \
715
+ -X POST \
716
+ -H "Content-Type: application/json" \
717
+ --data-binary @- <<JSON \
718
+ | jq
719
+ {
720
+ "data": $(cat)
721
+ }
722
+ JSON
723
+ ```
724
+
725
+ ```json
726
+ {
727
+ "data": {
728
+ "db-before": "datomic.db.Db@4fa1fea2",
729
+ "db-after": "datomic.db.Db@74650f2d",
730
+ "tx-data": [
731
+ [1013, 50, "Sun Sep 22 08:58:31 BRT 2024", 1013, true],
732
+ [1005, 72, "Pride and Prejudice", 1013, false],
733
+ [1005, 73, "Romance", 1013, false],
734
+ [1005, 74, 1813, 1013, false]
735
+ ],
736
+ "tempids": {
737
+ }
738
+ }
739
+ }
740
+ ```
741
+
742
+ ## About
743
+
744
+ ### Characteristics
745
+
746
+ - Languages that play well with HTTP and JSON can interact with Datomic right away.
747
+
748
+ - Plug and play into any of the many flavors of Datomic's flexible infrastructure architecture.
749
+
750
+ - Minimal and transparent layer, not a DSL or framework, just straightforward access to Datomic.
751
+
752
+ - Despite JSON, both queries and transactions are done in EDN, enabling, e.g., powerful Datalog queries.
753
+
754
+ ### Trade-offs
755
+
756
+ - Languages have different data types, so EDN -> JSON -> [Your Language] and vice-versa: something will be lost in translation and expressiveness.
757
+
758
+ - An extra layer in the architecture adds a new hop to requests, potentially increasing latency.
759
+
760
+ - Being one step away from Clojure reduces our power to leverage its types, data structures, immutability, and other desired properties.
761
+
762
+ - Some tricks that would be easy to do in Clojure + Datomic become more cumbersome: transaction functions, advanced Datalog datasources, lazy loading, etc.
763
+
764
+ ## Development
765
+
766
+ ```bash
767
+ clj -M:repl
768
+
769
+ ```
770
+
771
+ ```bash
772
+ clj -M:format
773
+ clj -M:lint
774
+
775
+ ```
776
+
777
+ ```bash
778
+ cljfmt fix deps.edn src/
779
+ clj-kondo --lint deps.edn src/
780
+
781
+ ```