dexiecable 0.2.0 → 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 +4 -4
- data/README.md +26 -24
- data/lib/dexiecable/active_record_ext.rb +23 -36
- data/lib/dexiecable/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b462191000153b424593099689d503a34152404f08cd33911f8db01a61d154cf
|
|
4
|
+
data.tar.gz: 3fd86cd2c4b9cb4a73b43fc0fee7e686a91a9c4d1a1e390cc544d87f0dddbdc0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 933c9999fa8d60d04fb3571a094568f1fe78ace8f3a13de6e48dd18d71471e647a1b33c6eb49e2ec6123321933967a8479a1fb6c10906412b5a518302b141f66
|
|
7
|
+
data.tar.gz: 13751b561bb8f7d57d05ba7639b474c15d3077262a3ec488a8f217f1d5c20be4235757172eac5fa1b5e558af50b5c97d6d253d5a04544c60c80a768f44ab3049
|
data/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# DexieCable
|
|
2
2
|
|
|
3
3
|
> [!NOTE]
|
|
4
|
-
> DexieCable is NOT a local-first solution, because it lacks the capability to automatically sync updates back to the server
|
|
4
|
+
> The current version of DexieCable is NOT a local-first solution, because it lacks the capability to automatically sync updates back to the server. For now, think of it more as an alternative to turbo streams that works well with component frameworks.
|
|
5
|
+
>
|
|
6
|
+
> Full synchronization utilizing event streams will arrive in DexieCable 2.0.
|
|
5
7
|
|
|
6
|
-
DexieCable augments ActionCable channels with a query DSL that mirrors the Dexie.js API, letting you push database mutations from the server to the client in real time. It also gives you a [`
|
|
8
|
+
DexieCable augments ActionCable channels with a query DSL that mirrors the Dexie.js API, letting you push database mutations from the server to the client in real time. It also gives you a [`streams_via`](#streams_via--automatic-model-syncing) ActiveRecord macro for automatic change syncing.
|
|
7
9
|
|
|
8
10
|
You can run any Dexie table update directly inside a channel:
|
|
9
11
|
|
|
@@ -30,11 +32,11 @@ class NotificationsController < ApplicationController
|
|
|
30
32
|
end
|
|
31
33
|
```
|
|
32
34
|
|
|
33
|
-
An even more convenient way is to use the `
|
|
35
|
+
An even more convenient way is to use the `streams_via` macro (more info [below](#streams_via--automatic-model-syncing))
|
|
34
36
|
|
|
35
37
|
```ruby
|
|
36
38
|
class Notification < ApplicationRecord
|
|
37
|
-
|
|
39
|
+
streams_via UserChannel, to: :user
|
|
38
40
|
end
|
|
39
41
|
```
|
|
40
42
|
|
|
@@ -48,7 +50,7 @@ Add to your `Gemfile`:
|
|
|
48
50
|
gem "dexiecable"
|
|
49
51
|
```
|
|
50
52
|
|
|
51
|
-
Then `bundle install`. The Railtie automatically extends `ActiveRecord::Base` with `
|
|
53
|
+
Then `bundle install`. The Railtie automatically extends `ActiveRecord::Base` with `streams_via`.
|
|
52
54
|
|
|
53
55
|
### npm package
|
|
54
56
|
|
|
@@ -131,25 +133,25 @@ UserChannel[current_user]
|
|
|
131
133
|
|
|
132
134
|
The full query chain is serialized as JSON and sent over ActionCable. The JS client replays every method call against the local Dexie database in order.
|
|
133
135
|
|
|
134
|
-
### `
|
|
136
|
+
### `streams_via` — automatic model streaming
|
|
135
137
|
|
|
136
|
-
Add to any ActiveRecord model. Just provide the channel class and the broadcast target.
|
|
138
|
+
Add to any ActiveRecord model. Just provide the channel class and, optionally, the broadcast target.
|
|
137
139
|
|
|
138
140
|
```ruby
|
|
139
141
|
class Message < ApplicationRecord
|
|
140
142
|
# Calls send(:receiver), then broadcasts: UserChannel.broadcast_to(receiver, ...)
|
|
141
|
-
|
|
143
|
+
streams_via UserChannel, to: :receiver
|
|
142
144
|
|
|
143
|
-
# String used directly:
|
|
144
|
-
|
|
145
|
+
# String used directly: RoomChannel.broadcast_to("public", ...)
|
|
146
|
+
streams_via RoomChannel, to: "public"
|
|
145
147
|
|
|
146
148
|
# Procs are also supported. If an array is returned, multiple broadcasts are made
|
|
147
149
|
# conversation.users.each { |u| UserChannel.broadcast_to(u, ...) }
|
|
148
|
-
|
|
150
|
+
streams_via UserChannel, to: -> { conversation.users }
|
|
149
151
|
end
|
|
150
152
|
```
|
|
151
153
|
|
|
152
|
-
Internally, `
|
|
154
|
+
Internally, `streams_via` sets up the following ActiveRecord callbacks:
|
|
153
155
|
|
|
154
156
|
| Event | Action |
|
|
155
157
|
|---|---|
|
|
@@ -161,23 +163,23 @@ Internally, `streams_to_dexie` sets up the following ActiveRecord callbacks:
|
|
|
161
163
|
|
|
162
164
|
| Option | Default | Description |
|
|
163
165
|
|---|---|---|
|
|
164
|
-
|
|
|
165
|
-
| `to:` |
|
|
166
|
+
| *(first argument)* | *(required)* | A DexieCable channel class |
|
|
167
|
+
| `to:` | the record itself | The stream target passed to `broadcast_to`. Symbol → calls `send`. String → used as-is. Proc → evaluated in record context. Returns a single recipient or collection. |
|
|
166
168
|
| `table:` | model's `table_name` | Override the Dexie table name. A Proc is evaluated in the record's context. |
|
|
167
169
|
| `only:` | `[:create, :update, :destroy]` | Limit which events trigger a sync |
|
|
168
170
|
| `with:` | `:as_json_for_dexie` | Method name (Symbol) or Proc for serializing records |
|
|
169
171
|
| `if:` | *(none)* | Symbol (method name) or Proc — only sync when it returns truthy |
|
|
170
172
|
| `unless:` | *(none)* | Symbol (method name) or Proc — skip sync when it returns truthy |
|
|
171
173
|
|
|
172
|
-
You can combine multiple `
|
|
174
|
+
You can combine multiple `streams_via` declarations, each with different conditions:
|
|
173
175
|
|
|
174
176
|
```ruby
|
|
175
177
|
class Message < ApplicationRecord
|
|
176
|
-
|
|
177
|
-
|
|
178
|
+
streams_via UserChannel, to: -> { sender },
|
|
179
|
+
if: :published?
|
|
178
180
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
+
streams_via AdminChannel,
|
|
182
|
+
unless: -> { draft? }
|
|
181
183
|
end
|
|
182
184
|
```
|
|
183
185
|
|
|
@@ -188,23 +190,23 @@ Override `as_json_for_dexie` in your model, or use the `with` option to specify
|
|
|
188
190
|
```ruby
|
|
189
191
|
class Message < ApplicationRecord
|
|
190
192
|
# Using the default as_json_for_dexie override:
|
|
191
|
-
|
|
193
|
+
streams_via UserChannel, to: :sender
|
|
192
194
|
|
|
193
195
|
def as_json_for_dexie
|
|
194
196
|
super.merge(room_name: room.name)
|
|
195
197
|
end
|
|
196
198
|
|
|
197
199
|
# Or use a custom serializer method:
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
streams_via AdminChannel, to: :admin,
|
|
201
|
+
with: :admin_payload
|
|
200
202
|
|
|
201
203
|
def admin_payload
|
|
202
204
|
attributes.slice("id", "body", "flagged")
|
|
203
205
|
end
|
|
204
206
|
|
|
205
207
|
# Or a Proc:
|
|
206
|
-
|
|
207
|
-
|
|
208
|
+
streams_via PublicChannel,
|
|
209
|
+
with: -> { { id: id, summary: body.truncate(100) } }
|
|
208
210
|
end
|
|
209
211
|
```
|
|
210
212
|
|
|
@@ -9,22 +9,21 @@ module DexieCable
|
|
|
9
9
|
# DexieCable channel.
|
|
10
10
|
#
|
|
11
11
|
# class Message < ApplicationRecord
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
12
|
+
# streams_via UserChannel, to: :sender
|
|
13
|
+
# streams_via UserChannel, to: "global_feed"
|
|
14
|
+
# streams_via UserChannel, to: -> { conversation.users }
|
|
15
|
+
# streams_via PublicChannel
|
|
16
16
|
# end
|
|
17
17
|
#
|
|
18
|
-
# @param via [Class] A DexieCable channel class
|
|
19
|
-
#
|
|
20
|
-
# +via[to]+ to produce scoped
|
|
21
|
-
#
|
|
22
|
-
# unscoped channel.
|
|
18
|
+
# @param via [Class] A DexieCable channel class, passed as the
|
|
19
|
+
# first positional argument. Each recipient is
|
|
20
|
+
# mapped through +via[to]+ to produce scoped
|
|
21
|
+
# channels.
|
|
23
22
|
# @param to [Proc, Symbol, String] A Proc evaluated in record
|
|
24
23
|
# context, a Symbol to call via +send+, or a String
|
|
25
24
|
# used directly as the stream name for +broadcast_to+.
|
|
26
25
|
# Must return a single recipient or collection of
|
|
27
|
-
# recipients.
|
|
26
|
+
# recipients. Defaults to the record itself.
|
|
28
27
|
# @param table [String, Symbol, Proc] Override the Dexie table name
|
|
29
28
|
# (defaults to the model's table_name). A Proc is
|
|
30
29
|
# evaluated in the record's context.
|
|
@@ -36,7 +35,7 @@ module DexieCable
|
|
|
36
35
|
# returns truthy (evaluated in the record's context).
|
|
37
36
|
# @param unless [Symbol, Proc] Skip sync if the given method or proc
|
|
38
37
|
# returns truthy (evaluated in the record's context).
|
|
39
|
-
def
|
|
38
|
+
def streams_via(via, to: nil, table: nil, only: nil, with: nil, **options)
|
|
40
39
|
events = Array(only || %i[create update destroy])
|
|
41
40
|
conditions = options.slice(:if, :unless)
|
|
42
41
|
serializer = with || :as_json_for_dexie
|
|
@@ -48,7 +47,7 @@ module DexieCable
|
|
|
48
47
|
before_destroy :dexie_sync_before_destroy
|
|
49
48
|
|
|
50
49
|
after_commit on: :destroy, **conditions do
|
|
51
|
-
|
|
50
|
+
resolve_channels(via, to).each do |channel|
|
|
52
51
|
next unless channel
|
|
53
52
|
channel.table(resolve_table(table)).delete(dexie_destroy_id)
|
|
54
53
|
end
|
|
@@ -57,19 +56,19 @@ module DexieCable
|
|
|
57
56
|
|
|
58
57
|
if events.include?(:create)
|
|
59
58
|
after_commit on: :create, **conditions do
|
|
60
|
-
|
|
59
|
+
resolve_channels(via, to).each do |channel|
|
|
61
60
|
next unless channel
|
|
62
|
-
channel.table(resolve_table(table)).add(
|
|
61
|
+
channel.table(resolve_table(table)).add(resolve(serializer))
|
|
63
62
|
end
|
|
64
63
|
end
|
|
65
64
|
end
|
|
66
65
|
|
|
67
66
|
if events.include?(:update)
|
|
68
67
|
after_commit on: :update, **conditions do
|
|
69
|
-
|
|
68
|
+
resolve_channels(via, to).each do |channel|
|
|
70
69
|
next unless channel
|
|
71
70
|
|
|
72
|
-
changes =
|
|
71
|
+
changes = resolve(serializer).slice(*saved_changes.keys)
|
|
73
72
|
channel.table(resolve_table(table)).update(id, changes)
|
|
74
73
|
end
|
|
75
74
|
end
|
|
@@ -79,20 +78,16 @@ module DexieCable
|
|
|
79
78
|
|
|
80
79
|
private
|
|
81
80
|
|
|
82
|
-
def
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
Array(recipients).map { |r| via[r] }
|
|
86
|
-
else
|
|
87
|
-
via
|
|
88
|
-
end
|
|
81
|
+
def resolve_channels(via, to = nil)
|
|
82
|
+
recipients = to ? resolve(to) : self
|
|
83
|
+
Array(recipients).map { |r| via[r] }
|
|
89
84
|
end
|
|
90
85
|
|
|
91
|
-
def
|
|
92
|
-
case
|
|
93
|
-
when Proc then instance_exec(&
|
|
94
|
-
when Symbol then send(
|
|
95
|
-
else
|
|
86
|
+
def resolve(val)
|
|
87
|
+
case val
|
|
88
|
+
when Proc then instance_exec(&val)
|
|
89
|
+
when Symbol then send(val)
|
|
90
|
+
else val
|
|
96
91
|
end
|
|
97
92
|
end
|
|
98
93
|
|
|
@@ -104,14 +99,6 @@ module DexieCable
|
|
|
104
99
|
end
|
|
105
100
|
end
|
|
106
101
|
|
|
107
|
-
def serialize_record(serializer)
|
|
108
|
-
case serializer
|
|
109
|
-
when Proc then instance_exec(&serializer)
|
|
110
|
-
when Symbol then send(serializer)
|
|
111
|
-
else serializer
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
102
|
# Override in your model to customise the payload synced to Dexie.
|
|
116
103
|
def as_json_for_dexie
|
|
117
104
|
as_json
|
data/lib/dexiecable/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dexiecable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stefan Buhrmester
|
|
@@ -39,7 +39,7 @@ dependencies:
|
|
|
39
39
|
version: '7.0'
|
|
40
40
|
description: DexieCable augments ActionCable channels with a query DSL that mirrors
|
|
41
41
|
the Dexie.js API, letting you push database mutations from the server to the client
|
|
42
|
-
in real time. Includes an ActiveRecord macro (
|
|
42
|
+
in real time. Includes an ActiveRecord macro (streams_via) for automatic change
|
|
43
43
|
syncing.
|
|
44
44
|
email:
|
|
45
45
|
- stefan@buhrmi.de
|