ar_sync 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +27 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +29 -31
- data/ar_sync.gemspec +1 -1
- data/core/{ActioncableAdapter.d.ts → ActionCableAdapter.d.ts} +0 -0
- data/core/ActionCableAdapter.js +31 -0
- data/core/ArSyncApi.d.ts +8 -2
- data/core/ArSyncApi.js +123 -49
- data/core/ArSyncModel.js +69 -60
- data/core/ArSyncStore.js +522 -381
- data/core/ConnectionManager.d.ts +1 -1
- data/core/ConnectionManager.js +45 -38
- data/core/DataType.d.ts +14 -9
- data/core/hooks.d.ts +5 -0
- data/core/hooks.js +64 -36
- 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 +71 -36
- data/lib/ar_sync/collection.rb +23 -19
- data/lib/ar_sync/core.rb +3 -3
- data/lib/ar_sync/instance_methods.rb +7 -4
- data/lib/ar_sync/rails.rb +1 -1
- data/lib/ar_sync/type_script.rb +50 -14
- data/lib/ar_sync/version.rb +1 -1
- data/lib/generators/ar_sync/install/install_generator.rb +1 -1
- data/package-lock.json +1706 -227
- data/package.json +1 -1
- data/src/core/{ActioncableAdapter.ts → ActionCableAdapter.ts} +0 -0
- 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 +15 -16
- data/src/core/hooks.ts +31 -7
- data/tsconfig.json +2 -2
- data/vendor/assets/javascripts/{ar_sync_actioncable_adapter.js.erb → ar_sync_action_cable_adapter.js.erb} +1 -1
- metadata +17 -16
- data/core/ActioncableAdapter.js +0 -29
- data/lib/ar_sync/field.rb +0 -96
@@ -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
|
@@ -33,10 +33,10 @@ module ArSync::ModelBase::InstanceMethods
|
|
33
33
|
def _serializer_field_value(name)
|
34
34
|
field = self.class._serializer_field_info name
|
35
35
|
preloadeds = field.preloaders.map do |preloader|
|
36
|
-
args = [[self], nil
|
36
|
+
args = [[self], nil]
|
37
37
|
preloader.call(*(preloader.arity < 0 ? args : args.take(preloader.arity)))
|
38
38
|
end
|
39
|
-
instance_exec(*preloadeds, nil,
|
39
|
+
instance_exec(*preloadeds, nil, &field.data_block)
|
40
40
|
end
|
41
41
|
|
42
42
|
def _sync_current_belongs_to_info
|
@@ -65,11 +65,13 @@ module ArSync::ModelBase::InstanceMethods
|
|
65
65
|
parents_was = parents.map { nil }
|
66
66
|
elsif action == :destroy
|
67
67
|
parents_was = _sync_parents_info_before_mutation
|
68
|
+
return unless parents_was
|
68
69
|
parents = parents_was.map { nil }
|
69
70
|
else
|
70
71
|
parents_was = _sync_parents_info_before_mutation
|
72
|
+
return unless parents_was
|
71
73
|
parents = _sync_current_parents_info
|
72
|
-
column_values_was = _sync_watch_values_before_mutation
|
74
|
+
column_values_was = _sync_watch_values_before_mutation || {}
|
73
75
|
column_values = _sync_current_watch_values
|
74
76
|
end
|
75
77
|
parents_was.zip(parents).each do |(parent_was, info_was), (parent, info)|
|
@@ -109,6 +111,7 @@ module ArSync::ModelBase::InstanceMethods
|
|
109
111
|
|
110
112
|
def _sync_notify_self
|
111
113
|
belongs_was = _sync_belongs_to_info_before_mutation
|
114
|
+
return unless belongs_was
|
112
115
|
belongs = _sync_current_belongs_to_info
|
113
116
|
belongs.each do |name, info|
|
114
117
|
next if belongs_was[name] == info
|
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/type_script.rb
CHANGED
@@ -10,17 +10,14 @@ module ArSync::TypeScript
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.generate_type_definition(api_class)
|
13
|
+
types = ArSerializer::TypeScript.related_serializer_types([api_class]).reject { |t| t.type == api_class }
|
13
14
|
[
|
14
|
-
|
15
|
+
types.map { |t| data_type_definition t },
|
16
|
+
types.map { |t| query_type_definition t },
|
15
17
|
request_type_definition(api_class)
|
16
18
|
].join "\n"
|
17
19
|
end
|
18
20
|
|
19
|
-
def self.api_related_classes(api_class)
|
20
|
-
classes = ArSerializer::TypeScript.related_serializer_types([api_class]).map(&:type)
|
21
|
-
classes - [api_class]
|
22
|
-
end
|
23
|
-
|
24
21
|
def self.request_type_definition(api_class)
|
25
22
|
type = ArSerializer::GraphQL::TypeClass.from api_class
|
26
23
|
definitions = []
|
@@ -78,24 +75,63 @@ module ArSync::TypeScript
|
|
78
75
|
<<~CODE
|
79
76
|
import { TypeRequest, ApiNameRequests } from './types'
|
80
77
|
import { DataTypeFromRequest as DataTypeFromRequestPair } from 'ar_sync/core/DataType'
|
81
|
-
type
|
78
|
+
export type NeverMatchArgument = { __nevermatch: never }
|
79
|
+
type DataTypeFromRequest<R extends TypeRequest | NeverMatchArgument> = NeverMatchArgument extends R ? never : R extends TypeRequest ? DataTypeFromRequestPair<ApiNameRequests[R['api']], R> : never
|
82
80
|
export default DataTypeFromRequest
|
83
81
|
CODE
|
84
82
|
end
|
85
83
|
|
86
84
|
def self.generate_hooks_script
|
87
85
|
<<~CODE
|
88
|
-
import { useState, useEffect, useMemo } from 'react'
|
86
|
+
import { useState, useEffect, useMemo, useRef } from 'react'
|
89
87
|
import { TypeRequest } from './types'
|
90
|
-
import DataTypeFromRequest from './DataTypeFromRequest'
|
88
|
+
import DataTypeFromRequest, { NeverMatchArgument } from './DataTypeFromRequest'
|
91
89
|
import { initializeHooks, useArSyncModel as useArSyncModelBase, useArSyncFetch as useArSyncFetchBase } from 'ar_sync/core/hooks'
|
92
|
-
initializeHooks({ useState, useEffect, useMemo })
|
93
|
-
export function useArSyncModel<R extends TypeRequest>(request: R | null) {
|
94
|
-
return useArSyncModelBase<DataTypeFromRequest<R>>(request)
|
90
|
+
initializeHooks({ useState, useEffect, useMemo, useRef })
|
91
|
+
export function useArSyncModel<R extends TypeRequest | NeverMatchArgument>(request: R | null) {
|
92
|
+
return useArSyncModelBase<DataTypeFromRequest<R>>(request as TypeRequest)
|
95
93
|
}
|
96
|
-
export function useArSyncFetch<R extends TypeRequest>(request: R | null) {
|
97
|
-
return useArSyncFetchBase<DataTypeFromRequest<R>>(request)
|
94
|
+
export function useArSyncFetch<R extends TypeRequest | NeverMatchArgument>(request: R | null) {
|
95
|
+
return useArSyncFetchBase<DataTypeFromRequest<R>>(request as TypeRequest)
|
98
96
|
}
|
99
97
|
CODE
|
100
98
|
end
|
99
|
+
|
100
|
+
def self.query_type_definition(type)
|
101
|
+
field_definitions = type.fields.map do |field|
|
102
|
+
association_type = field.type.association_type
|
103
|
+
if association_type
|
104
|
+
qname = "Type#{association_type.name}Query"
|
105
|
+
if field.args.empty?
|
106
|
+
"#{field.name}?: true | #{qname} | { attributes?: #{qname} }"
|
107
|
+
else
|
108
|
+
"#{field.name}?: true | #{qname} | { params: #{field.args_ts_type}; attributes?: #{qname} }"
|
109
|
+
end
|
110
|
+
else
|
111
|
+
"#{field.name}?: true"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
field_definitions << "'*'?: true"
|
115
|
+
query_type_name = "Type#{type.name}Query"
|
116
|
+
base_query_type_name = "Type#{type.name}QueryBase"
|
117
|
+
<<~TYPE
|
118
|
+
export type #{query_type_name} = keyof (#{base_query_type_name}) | Readonly<(keyof (#{base_query_type_name}))[]> | #{base_query_type_name}
|
119
|
+
export interface #{base_query_type_name} {
|
120
|
+
#{field_definitions.map { |line| " #{line}" }.join("\n")}
|
121
|
+
}
|
122
|
+
TYPE
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.data_type_definition(type)
|
126
|
+
field_definitions = []
|
127
|
+
type.fields.each do |field|
|
128
|
+
field_definitions << "#{field.name}: #{field.type.ts_type}"
|
129
|
+
end
|
130
|
+
field_definitions << "_meta?: { name: '#{type.name}'; query: Type#{type.name}QueryBase }"
|
131
|
+
<<~TYPE
|
132
|
+
export interface Type#{type.name} {
|
133
|
+
#{field_definitions.map { |line| " #{line}" }.join("\n")}
|
134
|
+
}
|
135
|
+
TYPE
|
136
|
+
end
|
101
137
|
end
|
data/lib/ar_sync/version.rb
CHANGED
@@ -78,7 +78,7 @@ module ArSync
|
|
78
78
|
[
|
79
79
|
'//= require ar_sync',
|
80
80
|
'//= require action_cable',
|
81
|
-
'//= require
|
81
|
+
'//= require ar_sync_action_cable_adapter',
|
82
82
|
'ArSyncModel.setConnectionAdapter(new ArSyncActionCableAdapter(ActionCable))'
|
83
83
|
].join("\n") + "\n",
|
84
84
|
before: '//= require_tree .'
|