ar_sync 1.0.3 → 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 +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 .'
         |