ar_sync 1.0.5 → 1.1.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/.github/workflows/test.yml +27 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +26 -28
- data/core/ArSyncApi.d.ts +8 -2
- data/core/ArSyncApi.js +11 -1
- data/core/ArSyncStore.js +192 -138
- data/core/ConnectionManager.d.ts +1 -1
- data/core/ConnectionManager.js +2 -0
- data/core/DataType.d.ts +14 -9
- data/core/hooks.d.ts +1 -0
- data/core/hooks.js +9 -6
- data/gemfiles/Gemfile-rails-6 +9 -0
- data/gemfiles/Gemfile-rails-7 +9 -0
- data/index.js +2 -2
- data/lib/ar_sync/class_methods.rb +64 -23
- data/lib/ar_sync/collection.rb +23 -19
- data/lib/ar_sync/core.rb +3 -3
- data/lib/ar_sync/instance_methods.rb +1 -1
- data/lib/ar_sync/rails.rb +1 -1
- data/lib/ar_sync/version.rb +1 -1
- data/package-lock.json +1706 -227
- data/package.json +1 -1
- data/src/core/ArSyncApi.ts +20 -7
- data/src/core/ArSyncStore.ts +177 -125
- data/src/core/ConnectionManager.ts +1 -0
- data/src/core/DataType.ts +14 -15
- data/src/core/hooks.ts +5 -5
- metadata +9 -7
- data/lib/ar_sync/field.rb +0 -96
data/core/hooks.js
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.useArSyncFetch = exports.useArSyncModel = exports.initializeHooks = void 0;
|
3
4
|
var ArSyncApi_1 = require("./ArSyncApi");
|
4
5
|
var ArSyncModel_1 = require("./ArSyncModel");
|
5
6
|
var useState;
|
@@ -19,9 +20,10 @@ function checkHooks() {
|
|
19
20
|
}
|
20
21
|
var initialResult = [null, { complete: false, notfound: undefined, connected: true }];
|
21
22
|
function useArSyncModel(request) {
|
23
|
+
var _a;
|
22
24
|
checkHooks();
|
23
|
-
var
|
24
|
-
var requestString = JSON.stringify(request && request.params);
|
25
|
+
var _b = useState(initialResult), result = _b[0], setResult = _b[1];
|
26
|
+
var requestString = JSON.stringify((_a = request === null || request === void 0 ? void 0 : request.id) !== null && _a !== void 0 ? _a : request === null || request === void 0 ? void 0 : request.params);
|
25
27
|
var prevRequestStringRef = useRef(requestString);
|
26
28
|
useEffect(function () {
|
27
29
|
prevRequestStringRef.current = requestString;
|
@@ -68,13 +70,14 @@ function extractParams(query, output) {
|
|
68
70
|
return output;
|
69
71
|
}
|
70
72
|
function useArSyncFetch(request) {
|
73
|
+
var _a;
|
71
74
|
checkHooks();
|
72
|
-
var
|
75
|
+
var _b = useState(initialFetchState), state = _b[0], setState = _b[1];
|
73
76
|
var query = request && request.query;
|
74
|
-
var
|
77
|
+
var resourceIdentifier = (_a = request === null || request === void 0 ? void 0 : request.id) !== null && _a !== void 0 ? _a : request === null || request === void 0 ? void 0 : request.params;
|
75
78
|
var requestString = useMemo(function () {
|
76
|
-
return JSON.stringify(extractParams(query, [
|
77
|
-
}, [query,
|
79
|
+
return JSON.stringify(extractParams(query, [resourceIdentifier]));
|
80
|
+
}, [query, resourceIdentifier]);
|
78
81
|
var prevRequestStringRef = useRef(requestString);
|
79
82
|
var loader = useMemo(function () {
|
80
83
|
var lastLoadId = 0;
|
@@ -0,0 +1,9 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in ar_sync.gemspec
|
6
|
+
gemspec path: ".."
|
7
|
+
|
8
|
+
gem "activerecord", "~> 6.0.0"
|
9
|
+
gem 'ar_serializer', github: 'tompng/ar_serializer'
|
@@ -0,0 +1,9 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in ar_sync.gemspec
|
6
|
+
gemspec path: ".."
|
7
|
+
|
8
|
+
gem "activerecord", "~> 7.0.0"
|
9
|
+
gem 'ar_serializer', github: 'tompng/ar_serializer'
|
data/index.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
var ArSyncModel_1 = require("./core/ArSyncModel");
|
4
|
-
exports
|
4
|
+
Object.defineProperty(exports, "ArSyncModel", { enumerable: true, get: function () { return ArSyncModel_1.default; } });
|
5
5
|
var ArSyncApi_1 = require("./core/ArSyncApi");
|
6
|
-
exports
|
6
|
+
Object.defineProperty(exports, "ArSyncApi", { enumerable: true, get: function () { return ArSyncApi_1.default; } });
|
@@ -1,9 +1,10 @@
|
|
1
|
-
require_relative 'field'
|
2
1
|
require_relative 'collection'
|
3
2
|
|
4
3
|
module ArSync::ModelBase::ClassMethods
|
5
4
|
def _sync_self?
|
6
|
-
|
5
|
+
return true if defined?(@_sync_self)
|
6
|
+
|
7
|
+
superclass._sync_self? if superclass < ActiveRecord::Base
|
7
8
|
end
|
8
9
|
|
9
10
|
def _sync_parents_info
|
@@ -60,30 +61,59 @@ module ArSync::ModelBase::ClassMethods
|
|
60
61
|
_sync_define name, **option, &data_block
|
61
62
|
end
|
62
63
|
|
63
|
-
def _sync_has_many(name,
|
64
|
-
raise
|
64
|
+
def _sync_has_many(name, direction: :asc, first: nil, last: nil, preload: nil, association: nil, **option, &data_block)
|
65
|
+
raise ArgumentError, 'direction not in [:asc, :desc]' unless %i[asc desc].include? direction
|
66
|
+
raise ArgumentError, 'first and last cannot be both specified' if first && last
|
67
|
+
raise ArgumentError, 'cannot use first or last with direction: :desc' if direction != :asc && !first && !last
|
65
68
|
if data_block.nil? && preload.nil?
|
66
|
-
|
69
|
+
association_name = association || name.to_s.underscore.to_sym
|
70
|
+
order_option_from_params = lambda do |params|
|
71
|
+
if first || last
|
72
|
+
params_first = first && [first, params[:first]&.to_i].compact.min
|
73
|
+
params_last = last && [last, params[:last]&.to_i].compact.min
|
74
|
+
{ direction: direction, first: params_first, last: params_last }
|
75
|
+
else
|
76
|
+
{
|
77
|
+
first: params[:first]&.to_i,
|
78
|
+
last: params[:last]&.to_i,
|
79
|
+
order_by: params[:order_by],
|
80
|
+
direction: params[:direction] || :asc
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
67
84
|
preload = lambda do |records, _context, **params|
|
68
85
|
ArSerializer::Field.preload_association(
|
69
|
-
self,
|
70
|
-
|
71
|
-
|
86
|
+
self,
|
87
|
+
records,
|
88
|
+
association_name,
|
89
|
+
**order_option_from_params.call(params)
|
72
90
|
)
|
73
91
|
end
|
74
92
|
data_block = lambda do |preloaded, _context, **params|
|
75
|
-
records = preloaded ? preloaded[id] || [] :
|
76
|
-
next records unless
|
93
|
+
records = preloaded ? preloaded[id] || [] : __send__(name)
|
94
|
+
next records unless first || last
|
77
95
|
ArSync::CollectionWithOrder.new(
|
78
96
|
records,
|
79
|
-
|
80
|
-
limit: [params && params[:limit]&.to_i, limit].compact.min
|
97
|
+
**order_option_from_params.call(params)
|
81
98
|
)
|
82
99
|
end
|
83
100
|
serializer_data_block = lambda do |preloaded, _context, **_params|
|
84
|
-
preloaded ? preloaded[id] || [] :
|
101
|
+
preloaded ? preloaded[id] || [] : __send__(name)
|
102
|
+
end
|
103
|
+
if first
|
104
|
+
params_type = { first?: :int }
|
105
|
+
elsif last
|
106
|
+
params_type = { last?: :int }
|
107
|
+
else
|
108
|
+
params_type = lambda do
|
109
|
+
orderable_keys = reflect_on_association(association_name)&.klass&._serializer_orderable_field_keys || []
|
110
|
+
orderable_keys &= [*option[:only]].map(&:to_s) if option[:only]
|
111
|
+
orderable_keys -= [*option[:except]].map(&:to_s) if option[:except]
|
112
|
+
orderable_keys |= ['id']
|
113
|
+
order_by = orderable_keys.size == 1 ? orderable_keys.first : orderable_keys.sort
|
114
|
+
{ first?: :int, last?: :int, direction?: %w[asc desc], orderBy?: order_by }
|
115
|
+
end
|
85
116
|
end
|
86
|
-
params_type = { limit?: :int, order?: [{ :* => %w[asc desc] }, 'asc', 'desc'] }
|
87
117
|
else
|
88
118
|
params_type = {}
|
89
119
|
end
|
@@ -104,18 +134,25 @@ module ArSync::ModelBase::ClassMethods
|
|
104
134
|
serializer_field name, **option, namespace: :sync, &data_block
|
105
135
|
end
|
106
136
|
|
107
|
-
def sync_define_collection(name,
|
137
|
+
def sync_define_collection(name, first: nil, last: nil, direction: :asc)
|
108
138
|
_initialize_sync_callbacks
|
109
|
-
collection = ArSync::Collection.new self, name,
|
139
|
+
collection = ArSync::Collection.new self, name, first: first, last: last, direction: direction
|
110
140
|
sync_parent collection, inverse_of: [self, name]
|
111
141
|
end
|
112
142
|
|
113
143
|
module WriteHook
|
114
144
|
def _initialize_sync_info_before_mutation
|
115
|
-
|
116
|
-
|
117
|
-
@
|
118
|
-
@
|
145
|
+
return unless defined? @_initialized
|
146
|
+
if new_record?
|
147
|
+
@_sync_watch_values_before_mutation ||= {}
|
148
|
+
@_sync_parents_info_before_mutation ||= {}
|
149
|
+
@_sync_belongs_to_info_before_mutation ||= {}
|
150
|
+
else
|
151
|
+
self.class.default_scoped.scoping do
|
152
|
+
@_sync_watch_values_before_mutation ||= _sync_current_watch_values
|
153
|
+
@_sync_parents_info_before_mutation ||= _sync_current_parents_info
|
154
|
+
@_sync_belongs_to_info_before_mutation ||= _sync_current_belongs_to_info
|
155
|
+
end
|
119
156
|
end
|
120
157
|
end
|
121
158
|
def _write_attribute(attr_name, value)
|
@@ -129,7 +166,7 @@ module ArSync::ModelBase::ClassMethods
|
|
129
166
|
end
|
130
167
|
|
131
168
|
def _initialize_sync_callbacks
|
132
|
-
return if
|
169
|
+
return if defined? @_sync_callbacks_initialized
|
133
170
|
@_sync_callbacks_initialized = true
|
134
171
|
prepend WriteHook
|
135
172
|
attr_reader :_sync_parents_info_before_mutation, :_sync_belongs_to_info_before_mutation, :_sync_watch_values_before_mutation
|
@@ -140,8 +177,12 @@ module ArSync::ModelBase::ClassMethods
|
|
140
177
|
ArSync.sync_keys self, current_user
|
141
178
|
end
|
142
179
|
|
143
|
-
|
144
|
-
{ sync_keys: ArSync.sync_keys(self, current_user) }
|
180
|
+
serializer_defaults namespace: :sync do |current_user|
|
181
|
+
{ id: id, sync_keys: ArSync.sync_keys(self, current_user) }
|
182
|
+
end
|
183
|
+
|
184
|
+
after_initialize do
|
185
|
+
@_initialized = true
|
145
186
|
end
|
146
187
|
|
147
188
|
before_destroy do
|
data/lib/ar_sync/collection.rb
CHANGED
@@ -1,21 +1,26 @@
|
|
1
|
-
require_relative 'field'
|
2
|
-
|
3
1
|
class ArSync::Collection
|
4
|
-
attr_reader :klass, :name, :
|
5
|
-
def initialize(klass, name,
|
2
|
+
attr_reader :klass, :name, :first, :last, :direction, :ordering
|
3
|
+
def initialize(klass, name, first: nil, last: nil, direction: nil)
|
4
|
+
direction ||= :asc
|
6
5
|
@klass = klass
|
7
6
|
@name = name
|
8
|
-
@
|
9
|
-
@
|
7
|
+
@first = first
|
8
|
+
@last = last
|
9
|
+
@direction = direction
|
10
|
+
@ordering = { first: first, last: last, direction: direction }.compact
|
10
11
|
self.class.defined_collections[[klass, name]] = self
|
11
12
|
define_singleton_method(name) { to_a }
|
12
13
|
end
|
13
14
|
|
14
15
|
def to_a
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
if first
|
17
|
+
klass.order(id: direction).limit(first).to_a
|
18
|
+
elsif last
|
19
|
+
rev = direction == :asc ? :desc : :asc
|
20
|
+
klass.order(id: rev).limit(last).reverse
|
21
|
+
else
|
22
|
+
klass.all.to_a
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
26
|
def self.defined_collections
|
@@ -45,14 +50,13 @@ class ArSync::Collection
|
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
48
|
-
class ArSync::CollectionWithOrder < ArSerializer::
|
49
|
-
def initialize(records,
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
[{ order: @order, collection: values }, @records.zip(values)]
|
53
|
+
class ArSync::CollectionWithOrder < ArSerializer::CustomSerializable
|
54
|
+
def initialize(records, direction:, first: nil, last: nil)
|
55
|
+
super records do |results|
|
56
|
+
{
|
57
|
+
ordering: { direction: direction || :asc, first: first, last: last }.compact,
|
58
|
+
collection: records.map(&results).compact
|
59
|
+
}
|
60
|
+
end
|
57
61
|
end
|
58
62
|
end
|
data/lib/ar_sync/core.rb
CHANGED
@@ -82,17 +82,17 @@ module ArSync
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def self.serialize(record_or_records, query, user: nil)
|
85
|
-
ArSerializer.serialize record_or_records, query, context: user,
|
85
|
+
ArSerializer.serialize record_or_records, query, context: user, use: :sync
|
86
86
|
end
|
87
87
|
|
88
88
|
def self.sync_serialize(target, user, query)
|
89
89
|
case target
|
90
90
|
when ArSync::Collection, ArSync::ModelBase
|
91
|
-
serialized = ArSerializer.serialize target, query, context: user,
|
91
|
+
serialized = ArSerializer.serialize target, query, context: user, use: :sync
|
92
92
|
return serialized if target.is_a? ArSync::ModelBase
|
93
93
|
{
|
94
94
|
sync_keys: ArSync.sync_keys(target, user),
|
95
|
-
|
95
|
+
ordering: target.ordering,
|
96
96
|
collection: serialized
|
97
97
|
}
|
98
98
|
when ActiveRecord::Relation, Array
|
@@ -8,7 +8,7 @@ module ArSync::ModelBase::InstanceMethods
|
|
8
8
|
values = {}
|
9
9
|
self.class._each_sync_parent do |_, info|
|
10
10
|
[*info[:watch]].each do |watch|
|
11
|
-
values[watch] = watch.is_a?(Proc) ? instance_exec(&watch) :
|
11
|
+
values[watch] = watch.is_a?(Proc) ? instance_exec(&watch) : __send__(watch)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
values
|
data/lib/ar_sync/rails.rb
CHANGED
@@ -94,7 +94,7 @@ module ArSync
|
|
94
94
|
info = sch.class._serializer_field_info api_name
|
95
95
|
raise ArSync::ApiNotFound, "#{type.to_s.capitalize} API named `#{api_name}` not configured" unless info
|
96
96
|
api_params = (request[:params].as_json || {}).transform_keys(&:to_sym)
|
97
|
-
model = sch.instance_exec(current_user, api_params, &info.data_block)
|
97
|
+
model = sch.instance_exec(current_user, **api_params, &info.data_block)
|
98
98
|
{ data: yield(model, current_user, request[:query].as_json) }
|
99
99
|
rescue StandardError => e
|
100
100
|
{ error: handle_exception(e) }
|
data/lib/ar_sync/version.rb
CHANGED