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.
- checksums.yaml +7 -0
- data/.env.example +4 -0
- data/.gitignore +3 -0
- data/.rspec +1 -0
- data/.rubocop.yml +15 -0
- data/.ruby-version +1 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +100 -0
- data/LICENSE +9 -0
- data/README.md +1042 -0
- data/components/errors.rb +22 -0
- data/components/http.rb +55 -0
- data/controllers/api.rb +48 -0
- data/controllers/client.rb +43 -0
- data/controllers/documentation/formatter.rb +37 -0
- data/controllers/documentation/generator.rb +390 -0
- data/controllers/dsl/querying.rb +39 -0
- data/controllers/dsl/schema.rb +37 -0
- data/controllers/dsl/transacting.rb +62 -0
- data/controllers/dsl.rb +48 -0
- data/datomic-flare.gemspec +39 -0
- data/docs/CURL.md +781 -0
- data/docs/README.md +360 -0
- data/docs/api.md +395 -0
- data/docs/dsl.md +257 -0
- data/docs/templates/.rubocop.yml +15 -0
- data/docs/templates/README.md +319 -0
- data/docs/templates/api.md +267 -0
- data/docs/templates/dsl.md +206 -0
- data/helpers/h.rb +17 -0
- data/logic/dangerous_override.rb +108 -0
- data/logic/querying.rb +34 -0
- data/logic/schema.rb +91 -0
- data/logic/transacting.rb +53 -0
- data/logic/types.rb +141 -0
- data/ports/cli.rb +26 -0
- data/ports/dsl/datomic-flare/errors.rb +5 -0
- data/ports/dsl/datomic-flare.rb +20 -0
- data/static/gem.rb +15 -0
- metadata +146 -0
@@ -0,0 +1,319 @@
|
|
1
|
+
# Datomic Flare for Ruby
|
2
|
+
|
3
|
+
A Ruby gem for interacting with [Datomic](https://www.datomic.com) through [Datomic Flare](https://github.com/gbaptista/datomic-flare).
|
4
|
+
|
5
|
+

|
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
|
+
```ruby
|
12
|
+
gem '{{ gem.name }}', '~> {{ gem.version }}'
|
13
|
+
```
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
require '{{ gem.name }}'
|
17
|
+
|
18
|
+
client = Flare.new(credentials: { address: 'http://localhost:3042' })
|
19
|
+
```
|
20
|
+
|
21
|
+
```ruby:runnable
|
22
|
+
client.dsl.transact_schema!(
|
23
|
+
{
|
24
|
+
book: {
|
25
|
+
title: { type: :string, doc: 'The title of the book.' },
|
26
|
+
genre: { type: :string, doc: 'The genre of the book.' },
|
27
|
+
}
|
28
|
+
}
|
29
|
+
)
|
30
|
+
|
31
|
+
client.dsl.assert_into!(
|
32
|
+
:book,
|
33
|
+
{ title: 'The Tell-Tale Heart',
|
34
|
+
genre: 'Horror' }
|
35
|
+
)
|
36
|
+
|
37
|
+
client.dsl.query(
|
38
|
+
datalog: <<~EDN
|
39
|
+
[:find ?e ?title ?genre
|
40
|
+
:where [?e :book/title ?title]
|
41
|
+
[?e :book/genre ?genre]]
|
42
|
+
EDN
|
43
|
+
)
|
44
|
+
```
|
45
|
+
|
46
|
+
```ruby:placeholder
|
47
|
+
```
|
48
|
+
|
49
|
+
{{ index }}
|
50
|
+
|
51
|
+
## Flare
|
52
|
+
|
53
|
+
### Creating a Client
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
require '{{ gem.name }}'
|
57
|
+
|
58
|
+
client = Flare.new(credentials: { address: 'http://localhost:3042' })
|
59
|
+
```
|
60
|
+
|
61
|
+
### Meta
|
62
|
+
|
63
|
+
```ruby:runnable
|
64
|
+
client.meta
|
65
|
+
```
|
66
|
+
|
67
|
+
```ruby:placeholder
|
68
|
+
```
|
69
|
+
|
70
|
+
{{ dsl }}
|
71
|
+
|
72
|
+
{{ api }}
|
73
|
+
|
74
|
+
## Development
|
75
|
+
|
76
|
+
```bash
|
77
|
+
bundle
|
78
|
+
rubocop -A
|
79
|
+
```
|
80
|
+
|
81
|
+
### Publish to RubyGems
|
82
|
+
|
83
|
+
```bash
|
84
|
+
gem build {{ gem.name }}.gemspec
|
85
|
+
|
86
|
+
gem signin
|
87
|
+
|
88
|
+
gem push {{ gem.name }}-{{ gem.version }}.gem
|
89
|
+
```
|
90
|
+
|
91
|
+
### Setup for Tests and Documentation
|
92
|
+
|
93
|
+
Tests run against real Datomic databases, and documentation (README) is generated by interacting with real Datomic databases.
|
94
|
+
|
95
|
+
To accomplish that, we need to have [Datomic](https://github.com/gbaptista/datomic-pro-docker) and [Flare](https://github.com/gbaptista/datomic-flare) running.
|
96
|
+
|
97
|
+
**TL;DR:**
|
98
|
+
|
99
|
+
```bash
|
100
|
+
git clone https://github.com/gbaptista/datomic-pro-docker.git
|
101
|
+
|
102
|
+
cd datomic-pro-docker
|
103
|
+
|
104
|
+
cp compose/flare-dev.yml docker-compose.yml
|
105
|
+
|
106
|
+
docker compose up -d datomic-storage
|
107
|
+
|
108
|
+
docker compose run datomic-tools psql \
|
109
|
+
-f bin/sql/postgres-table.sql \
|
110
|
+
-h datomic-storage \
|
111
|
+
-U datomic-user \
|
112
|
+
-d my-datomic-storage
|
113
|
+
|
114
|
+
docker compose up -d datomic-transactor
|
115
|
+
|
116
|
+
docker compose run datomic-tools clojure -M -e "$(cat <<'CLOJURE'
|
117
|
+
(require '[datomic.api :as d])
|
118
|
+
|
119
|
+
(d/create-database "datomic:sql://my-datomic-database?jdbc:postgresql://datomic-storage:5432/my-datomic-storage?user=datomic-user&password=unsafe")
|
120
|
+
|
121
|
+
(d/create-database "datomic:sql://my-datomic-database-test?jdbc:postgresql://datomic-storage:5432/my-datomic-storage?user=datomic-user&password=unsafe")
|
122
|
+
|
123
|
+
(d/create-database "datomic:sql://my-datomic-database-test-green?jdbc:postgresql://datomic-storage:5432/my-datomic-storage?user=datomic-user&password=unsafe")
|
124
|
+
|
125
|
+
(System/exit 0)
|
126
|
+
CLOJURE
|
127
|
+
)"
|
128
|
+
|
129
|
+
docker compose up -d datomic-peer-server
|
130
|
+
|
131
|
+
docker compose up -d datomic-flare-peer datomic-flare-client
|
132
|
+
```
|
133
|
+
|
134
|
+
```bash
|
135
|
+
curl -s http://localhost:3042/meta \
|
136
|
+
-X GET \
|
137
|
+
-H "Content-Type: application/json" \
|
138
|
+
| jq
|
139
|
+
```
|
140
|
+
|
141
|
+
```json
|
142
|
+
{
|
143
|
+
"data": {
|
144
|
+
"mode": "peer"
|
145
|
+
}
|
146
|
+
}
|
147
|
+
```
|
148
|
+
|
149
|
+
```bash
|
150
|
+
curl -s http://localhost:3043/meta \
|
151
|
+
-X GET \
|
152
|
+
-H "Content-Type: application/json" \
|
153
|
+
| jq
|
154
|
+
```
|
155
|
+
|
156
|
+
```json
|
157
|
+
{
|
158
|
+
"data": {
|
159
|
+
"mode": "client"
|
160
|
+
}
|
161
|
+
}
|
162
|
+
```
|
163
|
+
|
164
|
+
You are ready to run tests and generate documentation.
|
165
|
+
|
166
|
+
**Detailed instructions:**
|
167
|
+
|
168
|
+
Clone the [datomic-pro-docker](https://github.com/gbaptista/datomic-pro-docker) repository and copy the Docker Compose template:
|
169
|
+
|
170
|
+
```bash
|
171
|
+
git clone https://github.com/gbaptista/datomic-pro-docker.git
|
172
|
+
|
173
|
+
cd datomic-pro-docker
|
174
|
+
|
175
|
+
cp compose/flare-dev.yml docker-compose.yml
|
176
|
+
```
|
177
|
+
|
178
|
+
Start PostgreSQL as Datomic's storage service:
|
179
|
+
|
180
|
+
```bash
|
181
|
+
docker compose up -d datomic-storage
|
182
|
+
|
183
|
+
docker compose logs -f datomic-storage
|
184
|
+
```
|
185
|
+
|
186
|
+
Create the table for Datomic databases:
|
187
|
+
|
188
|
+
```bash
|
189
|
+
docker compose run datomic-tools psql \
|
190
|
+
-f bin/sql/postgres-table.sql \
|
191
|
+
-h datomic-storage \
|
192
|
+
-U datomic-user \
|
193
|
+
-d my-datomic-storage
|
194
|
+
```
|
195
|
+
|
196
|
+
You will be prompted for a password, which is `unsafe`.
|
197
|
+
|
198
|
+
Start the Datomic Transactor:
|
199
|
+
|
200
|
+
```bash
|
201
|
+
docker compose up -d datomic-transactor
|
202
|
+
|
203
|
+
docker compose logs -f datomic-transactor
|
204
|
+
```
|
205
|
+
|
206
|
+
Create the following databases:
|
207
|
+
|
208
|
+
- `my-datomic-database`
|
209
|
+
- `my-datomic-database-test`
|
210
|
+
- `my-datomic-database-test-green`
|
211
|
+
|
212
|
+
```bash
|
213
|
+
docker compose run datomic-tools clojure -M -e "$(cat <<'CLOJURE'
|
214
|
+
(require '[datomic.api :as d])
|
215
|
+
|
216
|
+
(d/create-database "datomic:sql://my-datomic-database?jdbc:postgresql://datomic-storage:5432/my-datomic-storage?user=datomic-user&password=unsafe")
|
217
|
+
|
218
|
+
(d/create-database "datomic:sql://my-datomic-database-test?jdbc:postgresql://datomic-storage:5432/my-datomic-storage?user=datomic-user&password=unsafe")
|
219
|
+
|
220
|
+
(d/create-database "datomic:sql://my-datomic-database-test-green?jdbc:postgresql://datomic-storage:5432/my-datomic-storage?user=datomic-user&password=unsafe")
|
221
|
+
|
222
|
+
(System/exit 0)
|
223
|
+
CLOJURE
|
224
|
+
)"
|
225
|
+
```
|
226
|
+
|
227
|
+
Start the Peer Server:
|
228
|
+
|
229
|
+
```bash
|
230
|
+
docker compose up -d datomic-peer-server
|
231
|
+
|
232
|
+
docker compose logs -f datomic-peer-server
|
233
|
+
```
|
234
|
+
|
235
|
+
Start 2 instances of Flare, one in Peer Mode and another in Client Mode:
|
236
|
+
|
237
|
+
```bash
|
238
|
+
docker compose up -d datomic-flare-peer datomic-flare-client
|
239
|
+
|
240
|
+
docker compose logs -f datomic-flare-peer
|
241
|
+
docker compose logs -f datomic-flare-client
|
242
|
+
```
|
243
|
+
|
244
|
+
You should be able to request both:
|
245
|
+
|
246
|
+
Datomic Flare in Peer Mode:
|
247
|
+
```bash
|
248
|
+
curl -s http://localhost:3042/meta \
|
249
|
+
-X GET \
|
250
|
+
-H "Content-Type: application/json" \
|
251
|
+
| jq
|
252
|
+
```
|
253
|
+
|
254
|
+
```json
|
255
|
+
{
|
256
|
+
"data": {
|
257
|
+
"mode": "peer"
|
258
|
+
}
|
259
|
+
}
|
260
|
+
```
|
261
|
+
|
262
|
+
Datomic Flare in Client Mode:
|
263
|
+
```bash
|
264
|
+
curl -s http://localhost:3043/meta \
|
265
|
+
-X GET \
|
266
|
+
-H "Content-Type: application/json" \
|
267
|
+
| jq
|
268
|
+
```
|
269
|
+
|
270
|
+
```json
|
271
|
+
{
|
272
|
+
"data": {
|
273
|
+
"mode": "client"
|
274
|
+
}
|
275
|
+
}
|
276
|
+
```
|
277
|
+
|
278
|
+
You are ready to run tests and generate documentation.
|
279
|
+
|
280
|
+
### Running Tests
|
281
|
+
|
282
|
+
Tests run against real Datomic databases, so complete the [Setup for Tests and Documentation](#setup-for-tests-and-documentation) first.
|
283
|
+
|
284
|
+
```bash
|
285
|
+
cp .env.example .env
|
286
|
+
|
287
|
+
bundle exec rspec
|
288
|
+
```
|
289
|
+
|
290
|
+
### Updating the README
|
291
|
+
|
292
|
+
Documentation (README) is generated by interacting with real Datomic databases, so complete the [Setup for Tests and Documentation](#setup-for-tests-and-documentation) first.
|
293
|
+
|
294
|
+
Update the `docs/templates/*.md` files, and then:
|
295
|
+
|
296
|
+
```sh
|
297
|
+
cp .env.example .env
|
298
|
+
|
299
|
+
bundle exec ruby ports/cli.rb docs:generate
|
300
|
+
```
|
301
|
+
|
302
|
+
Trick for automatically updating the `README.md` when `docs/templates/*.md` files change:
|
303
|
+
|
304
|
+
```sh
|
305
|
+
sudo pacman -S inotify-tools # Arch / Manjaro
|
306
|
+
sudo apt-get install inotify-tools # Debian / Ubuntu / Raspberry Pi OS
|
307
|
+
sudo dnf install inotify-tools # Fedora / CentOS / RHEL
|
308
|
+
|
309
|
+
while inotifywait -e modify docs/templates/*; \
|
310
|
+
do bundle exec ruby ports/cli.rb docs:generate; \
|
311
|
+
done
|
312
|
+
```
|
313
|
+
|
314
|
+
Trick for Markdown Live Preview:
|
315
|
+
```sh
|
316
|
+
pip install -U markdown_live_preview
|
317
|
+
|
318
|
+
mlp README.md -p 8042 --no-follow
|
319
|
+
```
|
@@ -0,0 +1,267 @@
|
|
1
|
+
## Flare API
|
2
|
+
|
3
|
+
It provides methods that mirror [Datomic's APIs](https://docs.datomic.com/clojure/index.html). Most interactions use EDN, closely following [Datomic’s documentation](https://docs.datomic.com).
|
4
|
+
|
5
|
+
This approach should be familiar to those who know Datomic concepts and APIs.
|
6
|
+
|
7
|
+
Learn more about Clojure and Datomic:
|
8
|
+
|
9
|
+
- [Clojure Rationale](https://clojure.org/about/rationale)
|
10
|
+
- [Datomic Introduction](https://docs.datomic.com/datomic-overview.html)
|
11
|
+
|
12
|
+
### Creating a Database
|
13
|
+
|
14
|
+
```ruby:runnable
|
15
|
+
client.api.create_database!({ name: 'fireball' })['data']
|
16
|
+
```
|
17
|
+
|
18
|
+
```ruby:placeholder
|
19
|
+
```
|
20
|
+
|
21
|
+
### Deleting a Database
|
22
|
+
|
23
|
+
```ruby:runnable
|
24
|
+
client.api.delete_database!({ name: 'fireball' })['data']
|
25
|
+
```
|
26
|
+
|
27
|
+
```ruby:placeholder
|
28
|
+
```
|
29
|
+
|
30
|
+
### Listing Databases
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
# Flare on Peer Mode
|
34
|
+
client.api.get_database_names['data']
|
35
|
+
|
36
|
+
# Flare on Client Mode
|
37
|
+
client.api.list_databases['data']
|
38
|
+
```
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
['my-datomic-database']
|
42
|
+
```
|
43
|
+
|
44
|
+
### Transacting Schema
|
45
|
+
|
46
|
+
```ruby:runnable
|
47
|
+
client.api.transact!(
|
48
|
+
{ data: <<~EDN
|
49
|
+
[{:db/ident :book/title
|
50
|
+
:db/valueType :db.type/string
|
51
|
+
:db/cardinality :db.cardinality/one
|
52
|
+
:db/doc "The title of the book."}
|
53
|
+
|
54
|
+
{:db/ident :book/genre
|
55
|
+
:db/valueType :db.type/string
|
56
|
+
:db/cardinality :db.cardinality/one
|
57
|
+
:db/doc "The genre of the book."}
|
58
|
+
|
59
|
+
{:db/ident :book/published_at_year
|
60
|
+
:db/valueType :db.type/long
|
61
|
+
:db/cardinality :db.cardinality/one
|
62
|
+
:db/doc "The year the book was first published."}]
|
63
|
+
EDN
|
64
|
+
}
|
65
|
+
)['data']
|
66
|
+
```
|
67
|
+
|
68
|
+
```ruby:placeholder
|
69
|
+
```
|
70
|
+
|
71
|
+
### Checking Schema
|
72
|
+
|
73
|
+
```ruby:runnable
|
74
|
+
client.api.q(
|
75
|
+
{ inputs: [{ database: { latest: true } }],
|
76
|
+
query: <<~EDN
|
77
|
+
[:find
|
78
|
+
?e ?ident ?value_type ?cardinality ?doc
|
79
|
+
?unique ?index ?no_history
|
80
|
+
:in $
|
81
|
+
:where
|
82
|
+
[?e :db/ident ?ident]
|
83
|
+
|
84
|
+
[?e :db/valueType ?value_type_id]
|
85
|
+
[?value_type_id :db/ident ?value_type]
|
86
|
+
|
87
|
+
[?e :db/cardinality ?cardinality_id]
|
88
|
+
[?cardinality_id :db/ident ?cardinality]
|
89
|
+
|
90
|
+
[(get-else $ ?e :db/doc "") ?doc]
|
91
|
+
|
92
|
+
[(get-else $ ?e :db/unique -1) ?unique_id]
|
93
|
+
[(get-else $ ?unique_id :db/ident false) ?unique]
|
94
|
+
|
95
|
+
[(get-else $ ?e :db/index false) ?index]
|
96
|
+
[(get-else $ ?e :db/noHistory false) ?no_history]]
|
97
|
+
EDN
|
98
|
+
}
|
99
|
+
)['data'].filter do |datom|
|
100
|
+
!%w[
|
101
|
+
db
|
102
|
+
db.alter db.attr db.bootstrap db.cardinality db.entity db.excise
|
103
|
+
db.fn db.install db.lang db.part db.sys db.type db.unique
|
104
|
+
fressian
|
105
|
+
].include?(datom[1].split('/').first)
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
```ruby:placeholder
|
110
|
+
```
|
111
|
+
|
112
|
+
### Asserting Facts
|
113
|
+
|
114
|
+
```ruby:runnable
|
115
|
+
client.api.transact!(
|
116
|
+
{ data: <<~EDN
|
117
|
+
[{:db/id -1
|
118
|
+
:book/title "Pride and Prejudice"
|
119
|
+
:book/genre "Romance"
|
120
|
+
:book/published_at_year 1813}]
|
121
|
+
EDN
|
122
|
+
}
|
123
|
+
)['data']
|
124
|
+
```
|
125
|
+
|
126
|
+
```ruby:placeholder
|
127
|
+
```
|
128
|
+
|
129
|
+
```ruby:runnable
|
130
|
+
client.api.transact!(
|
131
|
+
{ data: <<~EDN
|
132
|
+
[{:db/id -1
|
133
|
+
:book/title "Near to the Wild Heart"
|
134
|
+
:book/genre "Novel"
|
135
|
+
:book/published_at_year 1943}
|
136
|
+
{:db/id -2
|
137
|
+
:book/title "A Study in Scarlet"
|
138
|
+
:book/genre "Detective"
|
139
|
+
:book/published_at_year 1887}
|
140
|
+
{:db/id -3
|
141
|
+
:book/title "The Tell-Tale Heart"
|
142
|
+
:book/genre "Horror"
|
143
|
+
:book/published_at_year 1843}]
|
144
|
+
EDN
|
145
|
+
}
|
146
|
+
)['data']
|
147
|
+
```
|
148
|
+
|
149
|
+
```ruby:state
|
150
|
+
state[:wild_heart_entity_id] = result['tempids']['-1']
|
151
|
+
state[:scarlet_entity_id] = result['tempids']['-2']
|
152
|
+
```
|
153
|
+
|
154
|
+
```ruby:placeholder
|
155
|
+
```
|
156
|
+
|
157
|
+
### Reading Data by Entity
|
158
|
+
|
159
|
+
```ruby:runnable/render
|
160
|
+
client.api.entity(
|
161
|
+
{ database: { latest: true },
|
162
|
+
id: {{ state.wild_heart_entity_id }} }
|
163
|
+
)['data']
|
164
|
+
```
|
165
|
+
|
166
|
+
```ruby:placeholder
|
167
|
+
```
|
168
|
+
|
169
|
+
### Reading Data by Querying
|
170
|
+
|
171
|
+
```ruby:runnable
|
172
|
+
client.api.q(
|
173
|
+
{ inputs: [{ database: { latest: true } }],
|
174
|
+
query: <<~EDN
|
175
|
+
[:find ?e ?title ?genre ?year
|
176
|
+
:where [?e :book/title ?title]
|
177
|
+
[?e :book/genre ?genre]
|
178
|
+
[?e :book/published_at_year ?year]]
|
179
|
+
EDN
|
180
|
+
}
|
181
|
+
)['data']
|
182
|
+
```
|
183
|
+
|
184
|
+
```ruby:placeholder
|
185
|
+
```
|
186
|
+
|
187
|
+
```ruby:runnable
|
188
|
+
client.api.q(
|
189
|
+
{ inputs: [
|
190
|
+
{ database: { latest: true } },
|
191
|
+
'The Tell-Tale Heart'
|
192
|
+
],
|
193
|
+
query: <<~EDN
|
194
|
+
[:find ?e ?title ?genre ?year
|
195
|
+
:in $ ?title
|
196
|
+
:where [?e :book/title ?title]
|
197
|
+
[?e :book/genre ?genre]
|
198
|
+
[?e :book/published_at_year ?year]]
|
199
|
+
EDN
|
200
|
+
}
|
201
|
+
)['data']
|
202
|
+
```
|
203
|
+
|
204
|
+
```ruby:state
|
205
|
+
state[:tale_heart_entity_id] = result[0][0]
|
206
|
+
```
|
207
|
+
|
208
|
+
```ruby:placeholder
|
209
|
+
```
|
210
|
+
|
211
|
+
### Accumulating Facts
|
212
|
+
|
213
|
+
```ruby:runnable/render
|
214
|
+
client.api.transact!(
|
215
|
+
{ data: <<~EDN
|
216
|
+
[{:db/id {{ state.tale_heart_entity_id }} :book/genre "Gothic"}]
|
217
|
+
EDN
|
218
|
+
}
|
219
|
+
)['data']
|
220
|
+
```
|
221
|
+
|
222
|
+
```ruby:placeholder
|
223
|
+
```
|
224
|
+
|
225
|
+
### Retracting Facts
|
226
|
+
|
227
|
+
Retract the value of an attribute:
|
228
|
+
|
229
|
+
```ruby:runnable/render
|
230
|
+
client.api.transact!(
|
231
|
+
{ data: <<~EDN
|
232
|
+
[[:db/retract {{ state.tale_heart_entity_id }} :book/genre "Gothic"]]
|
233
|
+
EDN
|
234
|
+
}
|
235
|
+
)['data']
|
236
|
+
```
|
237
|
+
|
238
|
+
```ruby:placeholder
|
239
|
+
```
|
240
|
+
|
241
|
+
Retract an attribute:
|
242
|
+
|
243
|
+
```ruby:runnable/render
|
244
|
+
client.api.transact!(
|
245
|
+
{ data: <<~EDN
|
246
|
+
[[:db/retract {{ state.wild_heart_entity_id }} :book/genre]]
|
247
|
+
EDN
|
248
|
+
}
|
249
|
+
)['data']
|
250
|
+
```
|
251
|
+
|
252
|
+
```ruby:placeholder
|
253
|
+
```
|
254
|
+
|
255
|
+
Retract an entity:
|
256
|
+
|
257
|
+
```ruby:runnable/render
|
258
|
+
client.api.transact!(
|
259
|
+
{ data: <<~EDN
|
260
|
+
[[:db/retractEntity {{ state.scarlet_entity_id }}]]
|
261
|
+
EDN
|
262
|
+
}
|
263
|
+
)['data']
|
264
|
+
```
|
265
|
+
|
266
|
+
```ruby:placeholder
|
267
|
+
```
|