ar_sync 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/.gitignore +13 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +53 -0
- data/LICENSE.txt +21 -0
- data/README.md +128 -0
- data/Rakefile +10 -0
- data/ar_sync.gemspec +28 -0
- data/bin/console +12 -0
- data/bin/setup +8 -0
- data/core/ActioncableAdapter.d.ts +10 -0
- data/core/ActioncableAdapter.js +29 -0
- data/core/ArSyncApi.d.ts +5 -0
- data/core/ArSyncApi.js +74 -0
- data/core/ArSyncModelBase.d.ts +71 -0
- data/core/ArSyncModelBase.js +110 -0
- data/core/ConnectionAdapter.d.ts +7 -0
- data/core/ConnectionAdapter.js +2 -0
- data/core/ConnectionManager.d.ts +19 -0
- data/core/ConnectionManager.js +75 -0
- data/core/DataType.d.ts +60 -0
- data/core/DataType.js +2 -0
- data/core/hooksBase.d.ts +29 -0
- data/core/hooksBase.js +80 -0
- data/graph/ArSyncModel.d.ts +10 -0
- data/graph/ArSyncModel.js +22 -0
- data/graph/ArSyncStore.d.ts +28 -0
- data/graph/ArSyncStore.js +593 -0
- data/graph/hooks.d.ts +3 -0
- data/graph/hooks.js +10 -0
- data/graph/index.d.ts +2 -0
- data/graph/index.js +4 -0
- data/lib/ar_sync.rb +25 -0
- data/lib/ar_sync/class_methods.rb +215 -0
- data/lib/ar_sync/collection.rb +83 -0
- data/lib/ar_sync/config.rb +18 -0
- data/lib/ar_sync/core.rb +138 -0
- data/lib/ar_sync/field.rb +96 -0
- data/lib/ar_sync/instance_methods.rb +130 -0
- data/lib/ar_sync/rails.rb +155 -0
- data/lib/ar_sync/type_script.rb +80 -0
- data/lib/ar_sync/version.rb +3 -0
- data/lib/generators/ar_sync/install/install_generator.rb +87 -0
- data/lib/generators/ar_sync/types/types_generator.rb +11 -0
- data/package-lock.json +1115 -0
- data/package.json +19 -0
- data/src/core/ActioncableAdapter.ts +30 -0
- data/src/core/ArSyncApi.ts +75 -0
- data/src/core/ArSyncModelBase.ts +126 -0
- data/src/core/ConnectionAdapter.ts +5 -0
- data/src/core/ConnectionManager.ts +69 -0
- data/src/core/DataType.ts +73 -0
- data/src/core/hooksBase.ts +86 -0
- data/src/graph/ArSyncModel.ts +21 -0
- data/src/graph/ArSyncStore.ts +567 -0
- data/src/graph/hooks.ts +7 -0
- data/src/graph/index.ts +2 -0
- data/src/tree/ArSyncModel.ts +145 -0
- data/src/tree/ArSyncStore.ts +323 -0
- data/src/tree/hooks.ts +7 -0
- data/src/tree/index.ts +2 -0
- data/tree/ArSyncModel.d.ts +39 -0
- data/tree/ArSyncModel.js +143 -0
- data/tree/ArSyncStore.d.ts +21 -0
- data/tree/ArSyncStore.js +365 -0
- data/tree/hooks.d.ts +3 -0
- data/tree/hooks.js +10 -0
- data/tree/index.d.ts +2 -0
- data/tree/index.js +4 -0
- data/tsconfig.json +15 -0
- data/vendor/assets/javascripts/ar_sync_actioncable_adapter.js.erb +7 -0
- data/vendor/assets/javascripts/ar_sync_graph.js.erb +17 -0
- data/vendor/assets/javascripts/ar_sync_tree.js.erb +17 -0
- metadata +187 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
class ArSync::Field
|
2
|
+
attr_reader :name
|
3
|
+
def initialize(name)
|
4
|
+
@name = name
|
5
|
+
end
|
6
|
+
|
7
|
+
def skip_propagation?(_parent, _child, _path)
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def action_convert(action)
|
12
|
+
action
|
13
|
+
end
|
14
|
+
|
15
|
+
def order_param; end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ArSync::DataField < ArSync::Field
|
19
|
+
def type
|
20
|
+
:data
|
21
|
+
end
|
22
|
+
|
23
|
+
def data(parent, _child, to_user:, **)
|
24
|
+
ArSync.serialize parent, name, user: to_user
|
25
|
+
end
|
26
|
+
|
27
|
+
def path(_child)
|
28
|
+
[]
|
29
|
+
end
|
30
|
+
|
31
|
+
def action_convert(_action)
|
32
|
+
:update
|
33
|
+
end
|
34
|
+
|
35
|
+
def skip_propagation?(_parent, _child, path)
|
36
|
+
!path.nil?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ArSync::HasOneField < ArSync::Field
|
41
|
+
def type
|
42
|
+
:one
|
43
|
+
end
|
44
|
+
|
45
|
+
def data(_parent, child, action:, **)
|
46
|
+
child._sync_data new_record: action == :create
|
47
|
+
end
|
48
|
+
|
49
|
+
def path(_child)
|
50
|
+
[name]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class ArSync::HasManyField < ArSync::Field
|
55
|
+
attr_reader :limit, :order, :association, :propagate_when
|
56
|
+
def type
|
57
|
+
:many
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize(name, association: nil, limit: nil, order: nil, propagate_when: nil)
|
61
|
+
super name
|
62
|
+
@limit = limit
|
63
|
+
@order = order
|
64
|
+
@association = association || name
|
65
|
+
@propagate_when = propagate_when
|
66
|
+
end
|
67
|
+
|
68
|
+
def skip_propagation?(parent, child, _path)
|
69
|
+
return false unless limit
|
70
|
+
return !propagate_when.call(child) if propagate_when
|
71
|
+
ids = parent.send(association).order(id: order).limit(limit).ids
|
72
|
+
if child.destroyed?
|
73
|
+
ids.size == limit && (order == :asc ? ids.max < child.id : child.id < ids.min)
|
74
|
+
else
|
75
|
+
!ids.include? child.id
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def data(_parent, child, action:, **)
|
80
|
+
child._sync_data new_record: action == :create
|
81
|
+
end
|
82
|
+
|
83
|
+
def order_param
|
84
|
+
{ limit: limit, order: order } if order
|
85
|
+
end
|
86
|
+
|
87
|
+
def path(child)
|
88
|
+
[name, child.id]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class ArSync::CollectionField < ArSync::HasManyField
|
93
|
+
def path(child)
|
94
|
+
[child.id]
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module ArSync::TreeSync::InstanceMethods
|
2
|
+
def _sync_notify(action)
|
3
|
+
if self.class._sync_self?
|
4
|
+
data = action == :destroy ? nil : _sync_data
|
5
|
+
ArSync.sync_tree_send to: self, action: action, path: [], data: data
|
6
|
+
end
|
7
|
+
_sync_notify_parent action
|
8
|
+
end
|
9
|
+
|
10
|
+
def _sync_data(new_record: false)
|
11
|
+
fallbacks = {}
|
12
|
+
names = []
|
13
|
+
self.class._each_sync_child do |name, info|
|
14
|
+
names << name if info.type == :data
|
15
|
+
if new_record
|
16
|
+
fallbacks[name] = [] if info.type == :many
|
17
|
+
fallbacks[name] = nil if info.type == :one
|
18
|
+
end
|
19
|
+
end
|
20
|
+
data = ArSync.serialize self, names
|
21
|
+
fallbacks.update data
|
22
|
+
end
|
23
|
+
|
24
|
+
def sync_send_event(type:, relation: nil, to_user: nil, data:)
|
25
|
+
path = [*relation]
|
26
|
+
event_data = { type: type, data: data }
|
27
|
+
if self.class._sync_self?
|
28
|
+
ArSync.sync_tree_send to: self, action: :event, path: path, data: event_data, to_user: to_user
|
29
|
+
end
|
30
|
+
_sync_notify_parent(:event, path: path, data: event_data, only_to_user: to_user)
|
31
|
+
end
|
32
|
+
|
33
|
+
def _sync_notify_parent(action, path: nil, data: nil, order_param: nil, only_to_user: nil)
|
34
|
+
self.class._each_sync_parent do |parent, inverse_name:, only_to:|
|
35
|
+
parent = send(parent) if parent.is_a? Symbol
|
36
|
+
parent = instance_exec(&parent) if parent.is_a? Proc
|
37
|
+
next unless parent
|
38
|
+
next if parent.respond_to?(:destroyed?) && parent.destroyed?
|
39
|
+
inverse_name = instance_exec(&inverse_name) if inverse_name.is_a? Proc
|
40
|
+
next unless inverse_name
|
41
|
+
association_field = parent.class._sync_child_info inverse_name
|
42
|
+
next if association_field.skip_propagation? parent, self, path
|
43
|
+
action2 = association_field.action_convert action
|
44
|
+
only_to_user2 = only_to_user
|
45
|
+
if only_to
|
46
|
+
to_user = only_to.is_a?(Symbol) ? instance_eval(&only_to) : instance_exec(&only_to)
|
47
|
+
next unless to_user
|
48
|
+
next if only_to_user && only_to_user != to_user
|
49
|
+
only_to_user2 = to_user
|
50
|
+
end
|
51
|
+
data2 = path || action2 == :destroy ? data : association_field.data(parent, self, to_user: to_user, action: action)
|
52
|
+
order_param2 = path ? order_param : association_field.order_param
|
53
|
+
path2 = [*association_field.path(self), *path]
|
54
|
+
ArSync.sync_tree_send(
|
55
|
+
to: parent, action: action2, path: path2, data: data2,
|
56
|
+
to_user: only_to_user2,
|
57
|
+
ordering: order_param2
|
58
|
+
)
|
59
|
+
parent._sync_notify_parent action2, path: path2, data: data2, order_param: order_param2, only_to_user: to_user || only_to_user
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module ArSync::GraphSync::InstanceMethods
|
65
|
+
def _sync_notify(action)
|
66
|
+
_sync_notify_parent action
|
67
|
+
_sync_notify_self if self.class._sync_self? && action == :update
|
68
|
+
end
|
69
|
+
|
70
|
+
def _sync_current_parents_info
|
71
|
+
parents = []
|
72
|
+
self.class._each_sync_parent do |parent, inverse_name:, only_to:|
|
73
|
+
parent = send parent if parent.is_a? Symbol
|
74
|
+
parent = instance_exec(&parent) if parent.is_a? Proc
|
75
|
+
if only_to
|
76
|
+
to_user = only_to.is_a?(Symbol) ? instance_eval(&only_to) : instance_exec(&only_to)
|
77
|
+
parent = nil unless to_user
|
78
|
+
end
|
79
|
+
owned = parent.class._sync_child_info(inverse_name).present? if parent
|
80
|
+
parents << [parent, [inverse_name, to_user, owned]]
|
81
|
+
end
|
82
|
+
parents
|
83
|
+
end
|
84
|
+
|
85
|
+
def _sync_notify_parent(action)
|
86
|
+
if action == :create
|
87
|
+
parents = _sync_current_parents_info
|
88
|
+
parents_was = parents.map { nil }
|
89
|
+
elsif action == :destroy
|
90
|
+
parents_was = _sync_parents_info_before_mutation
|
91
|
+
parents = parents_was.map { nil }
|
92
|
+
else
|
93
|
+
parents_was = _sync_parents_info_before_mutation
|
94
|
+
parents = _sync_current_parents_info
|
95
|
+
end
|
96
|
+
parents_was.zip(parents).each do |(parent_was, info_was), (parent, info)|
|
97
|
+
if parent_was == parent && info_was == info
|
98
|
+
parent&._sync_notify_child_changed self, *info
|
99
|
+
else
|
100
|
+
parent_was&._sync_notify_child_removed self, *info_was
|
101
|
+
parent&._sync_notify_child_added self, *info
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def _sync_notify_child_removed(child, name, to_user, owned)
|
107
|
+
if owned
|
108
|
+
ArSync.sync_graph_send to: self, action: :remove, model: child, path: name, to_user: to_user
|
109
|
+
else
|
110
|
+
ArSync.sync_graph_send to: self, action: :update, model: self, to_user: to_user
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def _sync_notify_child_added(child, name, to_user, owned)
|
115
|
+
if owned
|
116
|
+
ArSync.sync_graph_send to: self, action: :add, model: child, path: name, to_user: to_user
|
117
|
+
else
|
118
|
+
ArSync.sync_graph_send to: self, action: :update, model: self, to_user: to_user
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def _sync_notify_child_changed(_child, _name, to_user, owned)
|
123
|
+
return if owned
|
124
|
+
ArSync.sync_graph_send(to: self, action: :update, model: self, to_user: to_user)
|
125
|
+
end
|
126
|
+
|
127
|
+
def _sync_notify_self
|
128
|
+
ArSync.sync_graph_send(to: self, action: :update, model: self)
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module ArSync
|
2
|
+
module Rails
|
3
|
+
class Engine < ::Rails::Engine; end
|
4
|
+
end
|
5
|
+
|
6
|
+
class ApiNotFound < StandardError; end
|
7
|
+
|
8
|
+
on_notification do |events|
|
9
|
+
events.each do |key, patch|
|
10
|
+
ActionCable.server.broadcast key, patch
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module StaticJsonConcern
|
15
|
+
def ar_sync_static_json(record_or_records, query)
|
16
|
+
if respond_to?(ArSync.config.current_user_method)
|
17
|
+
current_user = send ArSync.config.current_user_method
|
18
|
+
end
|
19
|
+
ArSync.serialize(record_or_records, query.as_json, user: current_user)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
ActionController::Base.class_eval do
|
24
|
+
include StaticJsonConcern
|
25
|
+
def action_with_compact_ar_sync_notification(&block)
|
26
|
+
ArSync.with_compact_notification(&block)
|
27
|
+
end
|
28
|
+
around_action :action_with_compact_ar_sync_notification
|
29
|
+
end
|
30
|
+
|
31
|
+
module ApiControllerConcern
|
32
|
+
extend ActiveSupport::Concern
|
33
|
+
include ArSerializer::Serializable
|
34
|
+
|
35
|
+
included do
|
36
|
+
protect_from_forgery except: %i[sync_call static_call graphql_call]
|
37
|
+
serializer_field :__schema do
|
38
|
+
ArSerializer::GraphQL::SchemaClass.new self.class
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def sync_call
|
43
|
+
_api_call :sync do |model, current_user, query|
|
44
|
+
case model
|
45
|
+
when ArSync::Collection::Graph, ArSync::GraphSync
|
46
|
+
serialized = ArSerializer.serialize model, query, context: current_user, include_id: true, use: :sync
|
47
|
+
next serialized if model.is_a? ArSync::GraphSync
|
48
|
+
{
|
49
|
+
sync_keys: ArSync.sync_graph_keys(model, current_user),
|
50
|
+
order: { mode: model.order, limit: model.limit },
|
51
|
+
collection: serialized
|
52
|
+
}
|
53
|
+
when ArSync::Collection::Tree
|
54
|
+
ArSync.sync_collection_api model, current_user, query
|
55
|
+
when ActiveRecord::Relation, Array
|
56
|
+
ArSync.serialize model.to_a, query, user: current_user
|
57
|
+
when ActiveRecord::Base
|
58
|
+
ArSync.sync_api model, current_user, query
|
59
|
+
else
|
60
|
+
model
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def graphql_schema
|
66
|
+
render plain: ArSerializer::GraphQL.definition(self.class)
|
67
|
+
end
|
68
|
+
|
69
|
+
def graphql_call
|
70
|
+
render json: ArSerializer::GraphQL.serialize(
|
71
|
+
self,
|
72
|
+
params[:query],
|
73
|
+
operation_name: params[:operationName],
|
74
|
+
variables: (params[:variables] || {}).as_json,
|
75
|
+
context: current_user
|
76
|
+
)
|
77
|
+
rescue StandardError => e
|
78
|
+
render json: { error: handle_exception(e) }
|
79
|
+
end
|
80
|
+
|
81
|
+
def static_call
|
82
|
+
_api_call :static do |model, current_user, query|
|
83
|
+
case model
|
84
|
+
when ArSync::Collection, ActiveRecord::Relation, Array
|
85
|
+
ArSerializer.serialize model.to_a, query, context: current_user
|
86
|
+
when ActiveRecord::Base
|
87
|
+
ArSerializer.serialize model, query, context: current_user
|
88
|
+
else
|
89
|
+
model
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def _api_call(type)
|
97
|
+
if respond_to?(ArSync.config.current_user_method)
|
98
|
+
current_user = send ArSync.config.current_user_method
|
99
|
+
end
|
100
|
+
responses = params[:requests].map do |request|
|
101
|
+
begin
|
102
|
+
api_name = request[:api]
|
103
|
+
info = self.class._serializer_field_info api_name
|
104
|
+
raise ArSync::ApiNotFound, "#{type.to_s.capitalize} API named `#{api_name}` not configured" unless info
|
105
|
+
api_params = (request[:params].as_json || {}).transform_keys(&:to_sym)
|
106
|
+
model = instance_exec(current_user, api_params, &info.data_block)
|
107
|
+
{ data: yield(model, current_user, request[:query].as_json) }
|
108
|
+
rescue StandardError => e
|
109
|
+
{ error: handle_exception(e) }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
render json: responses
|
113
|
+
end
|
114
|
+
|
115
|
+
def log_internal_exception_trace(trace)
|
116
|
+
if logger.formatter&.respond_to? :tags_text
|
117
|
+
logger.fatal trace.join("\n#{logger.formatter.tags_text}")
|
118
|
+
else
|
119
|
+
logger.fatal trace.join("\n")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def exception_trace(exception)
|
124
|
+
backtrace_cleaner = request.get_header 'action_dispatch.backtrace_cleaner'
|
125
|
+
wrapper = ActionDispatch::ExceptionWrapper.new backtrace_cleaner, exception
|
126
|
+
trace = wrapper.application_trace
|
127
|
+
trace.empty? ? wrapper.framework_trace : trace
|
128
|
+
end
|
129
|
+
|
130
|
+
def log_internal_exception(exception)
|
131
|
+
ActiveSupport::Deprecation.silence do
|
132
|
+
logger.fatal ' '
|
133
|
+
logger.fatal "#{exception.class} (#{exception.message}):"
|
134
|
+
log_internal_exception_trace exception.annoted_source_code if exception.respond_to?(:annoted_source_code)
|
135
|
+
logger.fatal ' '
|
136
|
+
log_internal_exception_trace exception_trace(exception)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def handle_exception(exception)
|
141
|
+
log_internal_exception exception
|
142
|
+
backtrace = exception_trace exception unless ::Rails.env.production?
|
143
|
+
case exception
|
144
|
+
when ArSerializer::InvalidQuery, ArSync::ApiNotFound, ArSerializer::GraphQL::Parser::ParseError
|
145
|
+
{ type: 'Bad Request', message: exception.message, backtrace: backtrace }
|
146
|
+
when ActiveRecord::RecordNotFound
|
147
|
+
message = exception.message unless ::Rails.env.production?
|
148
|
+
{ type: 'Record Not Found', message: message.to_s, backtrace: backtrace }
|
149
|
+
else
|
150
|
+
message = "#{exception.class} (#{exception.message})" unless ::Rails.env.production?
|
151
|
+
{ type: 'Internal Server Error', message: message.to_s, backtrace: backtrace }
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module ArSync::TypeScript
|
2
|
+
def self.generate_typed_files(api_class, dir:, mode: nil, comment: nil)
|
3
|
+
mode ||= :graph if ActiveRecord::Base.include? ArSync::GraphSync
|
4
|
+
mode ||= :tree if ActiveRecord::Base.include? ArSync::TreeSync
|
5
|
+
raise 'ar_sync mode: graph or tree, is not specified.' unless mode
|
6
|
+
{
|
7
|
+
'types.ts' => generate_type_definition(api_class),
|
8
|
+
'ArSyncModel.ts' => generate_model_script(mode),
|
9
|
+
'hooks.ts' => generate_hooks_script(mode)
|
10
|
+
}.each { |file, code| File.write File.join(dir, file), "#{comment}#{code}" }
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.generate_type_definition(api_class)
|
14
|
+
[
|
15
|
+
ArSerializer::TypeScript.generate_type_definition(api_related_classes(api_class)),
|
16
|
+
request_type_definition(api_class)
|
17
|
+
].join "\n"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.api_related_classes(api_class)
|
21
|
+
classes = ArSerializer::TypeScript.related_serializer_types([api_class]).map(&:type)
|
22
|
+
classes - [api_class]
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.request_type_definition(api_class)
|
26
|
+
type = ArSerializer::GraphQL::TypeClass.from api_class
|
27
|
+
definitions = []
|
28
|
+
request_types = {}
|
29
|
+
type.fields.each do |field|
|
30
|
+
association_type = field.type.association_type
|
31
|
+
next unless association_type
|
32
|
+
prefix = 'Class' if field.name.match?(/\A[A-Z]/) # for class reload query
|
33
|
+
request_type_name = "Type#{prefix}#{field.name.camelize}Request"
|
34
|
+
request_types[field.name] = request_type_name
|
35
|
+
multiple = field.type.is_a? ArSerializer::GraphQL::ListTypeClass
|
36
|
+
definitions << <<~CODE
|
37
|
+
export interface #{request_type_name} {
|
38
|
+
api: '#{field.name}'
|
39
|
+
params?: #{field.args_ts_type}
|
40
|
+
query: Type#{association_type.name}Query
|
41
|
+
_meta?: { data: Type#{field.type.association_type.name}#{'[]' if multiple} }
|
42
|
+
}
|
43
|
+
CODE
|
44
|
+
end
|
45
|
+
[
|
46
|
+
'export type TypeRequest = ',
|
47
|
+
request_types.values.map { |value| " | #{value}" },
|
48
|
+
'export type ApiNameRequests = {',
|
49
|
+
request_types.map { |key, value| " #{key}: #{value}" },
|
50
|
+
'}',
|
51
|
+
definitions
|
52
|
+
].join("\n")
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.generate_model_script(mode)
|
56
|
+
<<~CODE
|
57
|
+
import { TypeRequest, ApiNameRequests } from './types'
|
58
|
+
import { DataTypeFromRequest } from 'ar_sync/core/DataType'
|
59
|
+
import ArSyncModelBase from 'ar_sync/#{mode}/ArSyncModel'
|
60
|
+
export default class ArSyncModel<R extends TypeRequest> extends ArSyncModelBase<{}> {
|
61
|
+
constructor(r: R) { super(r) }
|
62
|
+
data: DataTypeFromRequest<ApiNameRequests[R['api']], R> | null
|
63
|
+
}
|
64
|
+
CODE
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.generate_hooks_script(mode)
|
68
|
+
<<~CODE
|
69
|
+
import { TypeRequest, ApiNameRequests } from './types'
|
70
|
+
import { DataTypeFromRequest } from 'ar_sync/core/DataType'
|
71
|
+
import { useArSyncModel as useArSyncModelBase, useArSyncFetch as useArSyncFetchBase } from 'ar_sync/#{mode}/hooks'
|
72
|
+
export function useArSyncModel<R extends TypeRequest>(request: R | null) {
|
73
|
+
return useArSyncModelBase<DataTypeFromRequest<ApiNameRequests[R['api']], R>>(request)
|
74
|
+
}
|
75
|
+
export function useArSyncFetch<R extends TypeRequest>(request: R | null) {
|
76
|
+
return useArSyncFetchBase<DataTypeFromRequest<ApiNameRequests[R['api']], R>>(request)
|
77
|
+
}
|
78
|
+
CODE
|
79
|
+
end
|
80
|
+
end
|