ar_sync 1.0.5 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/core/DataType.d.ts CHANGED
@@ -3,9 +3,7 @@ declare type RecordType = {
3
3
  query: any;
4
4
  };
5
5
  };
6
- declare type Values<T> = T extends {
7
- [K in keyof T]: infer U;
8
- } ? U : never;
6
+ declare type Values<T> = T[keyof T];
9
7
  declare type AddNullable<Test, Type> = null extends Test ? Type | null : Type;
10
8
  declare type DataTypeExtractField<BaseType, Key extends keyof BaseType> = Exclude<BaseType[Key], null> extends RecordType ? AddNullable<BaseType[Key], {}> : BaseType[Key] extends RecordType[] ? {}[] : BaseType[Key];
11
9
  declare type DataTypeExtractFieldsFromQuery<BaseType, Fields> = '*' extends Fields ? {
@@ -33,17 +31,24 @@ declare type CheckAttributesField<P, Q> = Q extends {
33
31
  declare type IsAnyCompareLeftType = {
34
32
  __any: never;
35
33
  };
36
- declare type CollectExtraFields<Type, Path> = IsAnyCompareLeftType extends Type ? null : Type extends ExtraFieldErrorType ? Path : Type extends (infer R)[] ? _CollectExtraFields<R> : _CollectExtraFields<Type>;
37
- declare type _CollectExtraFields<Type> = Type extends object ? (keyof (Type) extends never ? null : Values<{
38
- [key in keyof Type]: CollectExtraFields<Type[key], key>;
39
- }>) : null;
34
+ declare type CollectExtraFields<Type, Key> = IsAnyCompareLeftType extends Type ? never : Type extends ExtraFieldErrorType ? Key : Type extends (infer R)[] ? {
35
+ 0: Values<{
36
+ [key in keyof R]: CollectExtraFields<R[key], key>;
37
+ }>;
38
+ 1: never;
39
+ }[R extends object ? 0 : 1] : {
40
+ 0: Values<{
41
+ [key in keyof Type]: CollectExtraFields<Type[key], key>;
42
+ }>;
43
+ 1: never;
44
+ }[Type extends object ? 0 : 1];
40
45
  declare type SelectString<T> = T extends string ? T : never;
41
46
  declare type _ValidateDataTypeExtraFileds<Extra, Type> = SelectString<Extra> extends never ? Type : {
42
47
  error: {
43
- extraFields: SelectString<Extra>;
48
+ extraFields: Extra;
44
49
  };
45
50
  };
46
- declare type ValidateDataTypeExtraFileds<Type> = _ValidateDataTypeExtraFileds<CollectExtraFields<Type, []>, Type>;
51
+ declare type ValidateDataTypeExtraFileds<Type> = _ValidateDataTypeExtraFileds<CollectExtraFields<Type, never>, Type>;
47
52
  declare type RequestBase = {
48
53
  api: string;
49
54
  query: any;
data/core/hooks.d.ts CHANGED
@@ -20,6 +20,7 @@ export declare type DataAndStatus<T> = [T | null, ModelStatus];
20
20
  export interface Request {
21
21
  api: string;
22
22
  params?: any;
23
+ id?: number;
23
24
  query: any;
24
25
  }
25
26
  export declare function useArSyncModel<T>(request: Request | null): DataAndStatus<T>;
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 _a = useState(initialResult), result = _a[0], setResult = _a[1];
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 _a = useState(initialFetchState), state = _a[0], setState = _a[1];
75
+ var _b = useState(initialFetchState), state = _b[0], setState = _b[1];
73
76
  var query = request && request.query;
74
- var params = request && request.params;
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, [params]));
77
- }, [query, params]);
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.ArSyncModel = ArSyncModel_1.default;
4
+ Object.defineProperty(exports, "ArSyncModel", { enumerable: true, get: function () { return ArSyncModel_1.default; } });
5
5
  var ArSyncApi_1 = require("./core/ArSyncApi");
6
- exports.ArSyncApi = ArSyncApi_1.default;
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
- instance_variable_defined? '@_sync_self'
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, order: :asc, limit: nil, preload: nil, association: nil, **option, &data_block)
64
- raise "order not in [:asc, :desc] : #{order}" unless %i[asc desc].include? order
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
- underscore_name = name.to_s.underscore.to_sym
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, records, association || underscore_name,
70
- order: (!limit && params && params[:order]) || order,
71
- limit: [params && params[:limit]&.to_i, limit].compact.min
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] || [] : send(name)
76
- next records unless limit || order == :asc
93
+ records = preloaded ? preloaded[id] || [] : __send__(name)
94
+ next records unless first || last
77
95
  ArSync::CollectionWithOrder.new(
78
96
  records,
79
- order: (!limit && params && params[:order]) || order,
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] || [] : send(name)
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, limit: nil, order: :asc)
137
+ def sync_define_collection(name, first: nil, last: nil, direction: :asc)
108
138
  _initialize_sync_callbacks
109
- collection = ArSync::Collection.new self, name, limit: limit, order: order
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
- self.class.default_scoped.scoping do
116
- @_sync_watch_values_before_mutation ||= _sync_current_watch_values
117
- @_sync_parents_info_before_mutation ||= _sync_current_parents_info
118
- @_sync_belongs_to_info_before_mutation ||= _sync_current_belongs_to_info
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 instance_variable_defined? '@_sync_callbacks_initialized'
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
- _sync_define :defaults, namespace: :sync do |current_user|
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
@@ -1,21 +1,26 @@
1
- require_relative 'field'
2
-
3
1
  class ArSync::Collection
4
- attr_reader :klass, :name, :limit, :order
5
- def initialize(klass, name, limit: nil, order: nil)
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
- @limit = limit
9
- @order = order
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
- all = klass.all
16
- all = all.order id: order if order
17
- all = all.limit limit if limit
18
- all
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::CompositeValue
49
- def initialize(records, order:, limit:)
50
- @records = records
51
- @order = { mode: order, limit: limit }
52
- end
53
-
54
- def ar_serializer_build_sub_calls
55
- values = @records.map { {} }
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, include_id: true, use: :sync
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, include_id: true, use: :sync
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
- order: { mode: target.order, limit: target.limit },
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) : send(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
@@ -47,8 +47,8 @@ module ArSync
47
47
  end
48
48
 
49
49
  def sync_call
50
- _api_call :sync do |model, current_user, query|
51
- ArSync.sync_serialize model, current_user, query
50
+ _api_call :sync do |schema, current_user, query|
51
+ ArSync.sync_serialize schema, current_user, query
52
52
  end
53
53
  end
54
54
 
@@ -69,15 +69,8 @@ module ArSync
69
69
  end
70
70
 
71
71
  def static_call
72
- _api_call :static do |model, current_user, query|
73
- case model
74
- when ArSync::Collection, ActiveRecord::Relation, Array
75
- ArSerializer.serialize model.to_a, query, context: current_user
76
- when ArSerializer::Serializable
77
- ArSerializer.serialize model, query, context: current_user
78
- else
79
- model
80
- end
72
+ _api_call :static do |schema, current_user, query|
73
+ ArSerializer.serialize schema, query, context: current_user
81
74
  end
82
75
  end
83
76
 
@@ -87,15 +80,19 @@ module ArSync
87
80
  if respond_to?(ArSync.config.current_user_method)
88
81
  current_user = send ArSync.config.current_user_method
89
82
  end
83
+ sch = schema
90
84
  responses = params[:requests].map do |request|
91
85
  begin
92
86
  api_name = request[:api]
93
- sch = schema
94
- info = sch.class._serializer_field_info api_name
95
- raise ArSync::ApiNotFound, "#{type.to_s.capitalize} API named `#{api_name}` not configured" unless info
96
- api_params = (request[:params].as_json || {}).transform_keys(&:to_sym)
97
- model = sch.instance_exec(current_user, api_params, &info.data_block)
98
- { data: yield(model, current_user, request[:query].as_json) }
87
+ raise ArSync::ApiNotFound, "#{type.to_s.capitalize} API named `#{api_name}` not configured" unless sch.class._serializer_field_info api_name
88
+ query = {
89
+ api_name => {
90
+ as: :data,
91
+ params: request[:params].as_json,
92
+ attributes: request[:query].as_json
93
+ }
94
+ }
95
+ yield schema, current_user, query
99
96
  rescue StandardError => e
100
97
  { error: handle_exception(e) }
101
98
  end
@@ -1,3 +1,3 @@
1
1
  module ArSync
2
- VERSION = '1.0.5'
2
+ VERSION = '1.1.1'
3
3
  end