synced 1.4.0 → 1.5.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/README.md +42 -1
 - data/lib/synced/model.rb +17 -6
 - data/lib/synced/strategies/check.rb +22 -14
 - data/lib/synced/strategies/full.rb +57 -23
 - data/lib/synced/strategies/updated_since.rb +8 -7
 - data/lib/synced/version.rb +1 -1
 - metadata +21 -7
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: d0c560c40b86f1e58dc3d88f4c8784124f018999
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: b9c289d5ca8cda22e6d9dc7551f7bbae965d2cde
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 3aa68754bac3e77f985740aa5e65b16649075d58ded301f3d660dd9627094dd346a93a10b46c2dfec2cfb28e43786b06419f921426fb2b350005f9b96268be0e
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 465449c7d9c65f0355fc783957149fc621cb4a0f6f99c20737fc866251da48c4f60654a97ad635cf301d35eaa887009c7c83447c5ddcb3c159cab0c918835e41
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -76,6 +76,43 @@ rental = account.rentals.first 
     | 
|
| 
       76 
76 
     | 
    
         
             
            rental.synced_data.bedrooms # => 4
         
     | 
| 
       77 
77 
     | 
    
         
             
            rental.synced_data.rental_type # => "villa"
         
     | 
| 
       78 
78 
     | 
    
         
             
            ```
         
     | 
| 
      
 79 
     | 
    
         
            +
            ## Fetching data
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            You can choose between two ways of [fetching remote data](https://github.com/BookingSync/bookingsync-api#pagination):
         
     | 
| 
      
 82 
     | 
    
         
            +
            1. `auto_paginate` - default strategy, which fetches and persists all data at once. This strategy ensures that resources are fetched as quickly as possible, therefore minimizing risk of data changes during request. However, this way may become cumbersome when working with large data-sets (high memory usage).
         
     | 
| 
      
 83 
     | 
    
         
            +
            2. `pagination with block` -  fetches and persists records in batches. Especially helpful, when dealing with large data-sets. Increases overall syncing time, but significantly reduces memory usage. Number of entries per page can be customized by `:per_page` attribute inside `:query_params`
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
            In order to switch to `pagination with block`, you just need to use `auto_paginate: false`:
         
     | 
| 
      
 86 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 87 
     | 
    
         
            +
            class Rental
         
     | 
| 
      
 88 
     | 
    
         
            +
              synced auto_paginate: false, query_params: { per_page: 50 }
         
     | 
| 
      
 89 
     | 
    
         
            +
            end
         
     | 
| 
      
 90 
     | 
    
         
            +
            ```
         
     | 
| 
      
 91 
     | 
    
         
            +
            ### Persisted objects
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            There is another major difference between `auto_paginate` and `pagination with block` - when using `auto_paginate`, `.synchronize` returns collection of all **persisted** records. On the other hand, `pagination with block` returns last batch of **fetched** resources.
         
     | 
| 
      
 94 
     | 
    
         
            +
            If you need to process persisted data we encourage you to use `handle_processed_objects_proc`. This proc  takes one argument (persisted records) and is called after persisting each batch of remote objects. So when using `auto_paginate`, this:
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 97 
     | 
    
         
            +
            class Rental
         
     | 
| 
      
 98 
     | 
    
         
            +
              synced handle_processed_objects_proc: Proc.new { |persisted_rentals|
         
     | 
| 
      
 99 
     | 
    
         
            +
                  persisted_rentals.each { |rental| rental.do_stuff }
         
     | 
| 
      
 100 
     | 
    
         
            +
                }
         
     | 
| 
      
 101 
     | 
    
         
            +
            end
         
     | 
| 
      
 102 
     | 
    
         
            +
            ```
         
     | 
| 
      
 103 
     | 
    
         
            +
            would be an equivalent of overriding `.synchronize`:
         
     | 
| 
      
 104 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 105 
     | 
    
         
            +
            class Rental
         
     | 
| 
      
 106 
     | 
    
         
            +
              synced
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
              def self.synchronize(options)
         
     | 
| 
      
 109 
     | 
    
         
            +
                super.tap do |persisted_rentals|
         
     | 
| 
      
 110 
     | 
    
         
            +
                  persisted_rentals.each { |rental| rental.do_stuff }
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
      
 112 
     | 
    
         
            +
              end
         
     | 
| 
      
 113 
     | 
    
         
            +
            end
         
     | 
| 
      
 114 
     | 
    
         
            +
            ```
         
     | 
| 
      
 115 
     | 
    
         
            +
            **When using `pagination with block` only the former will work.**
         
     | 
| 
       79 
116 
     | 
    
         | 
| 
       80 
117 
     | 
    
         
             
            ## Synced strategies
         
     | 
| 
       81 
118 
     | 
    
         | 
| 
         @@ -346,6 +383,7 @@ Location.synchronize(remote: remote_locations) 
     | 
|
| 
       346 
383 
     | 
    
         
             
            ```
         
     | 
| 
       347 
384 
     | 
    
         | 
| 
       348 
385 
     | 
    
         
             
            NOTE: Partial updates are disabled when providing remote objects.
         
     | 
| 
      
 386 
     | 
    
         
            +
            **WARNING:** When using `remove: true` with `remote`, remember that synced will remove **ALL** records that are not passed to `remote`.
         
     | 
| 
       349 
387 
     | 
    
         | 
| 
       350 
388 
     | 
    
         
             
            ## Removing local objects
         
     | 
| 
       351 
389 
     | 
    
         | 
| 
         @@ -418,6 +456,7 @@ If you want to access synced attribute with different name, you can pass a Hash: 
     | 
|
| 
       418 
456 
     | 
    
         
             
            class Photo < ActiveRecord::Base
         
     | 
| 
       419 
457 
     | 
    
         
             
              synced delegate_attributes: {title: :name}
         
     | 
| 
       420 
458 
     | 
    
         
             
            end
         
     | 
| 
      
 459 
     | 
    
         
            +
            ```
         
     | 
| 
       421 
460 
     | 
    
         | 
| 
       422 
461 
     | 
    
         
             
            keys are delegated attributes' names and values are keys on synced data Hash. This is a simpler
         
     | 
| 
       423 
462 
     | 
    
         
             
            version of `delegate :name, to: :synced_data` which works with Hash reserved attributes names, like
         
     | 
| 
         @@ -436,7 +475,9 @@ Option name          | Default value    | Description 
     | 
|
| 
       436 
475 
     | 
    
         
             
            `:include`           | `[]`             | [An array of associations to be fetched](#including-associations-in-synced_data)  | YES    | YES         |
         
     | 
| 
       437 
476 
     | 
    
         
             
            `:fields`            | `[]`             | [An array of fields to be fetched](#selecting-fields-to-be-synchronized)          | YES    | YES         |
         
     | 
| 
       438 
477 
     | 
    
         
             
            `:remote`            | `nil`            | [Remote objects to be synchronized with local ones](#synchronization-of-given-remote-objects) | NO | YES |
         
     | 
| 
       439 
     | 
    
         
            -
            `:delegate_attributes`| `[]`            | [Define delegators to synced data Hash attributes](#delegate-attributes) 
     | 
| 
      
 478 
     | 
    
         
            +
            `:delegate_attributes`| `[]`            | [Define delegators to synced data Hash attributes](#delegate-attributes)          | YES    | NO |
         
     | 
| 
      
 479 
     | 
    
         
            +
            `:auto_paginate`     | `true`           | [Whether data should be fetched in batches or as one response](#fetching-methods)                 | YES    | YES |
         
     | 
| 
      
 480 
     | 
    
         
            +
            `:handle_processed_objects_proc` | `nil` | [Custom proc taking persisted remote objects, called after persisting batch of data](#persisted-objects)   | YES    | NO |
         
     | 
| 
       440 
481 
     | 
    
         | 
| 
       441 
482 
     | 
    
         
             
            ## Documentation
         
     | 
| 
       442 
483 
     | 
    
         | 
    
        data/lib/synced/model.rb
    CHANGED
    
    | 
         @@ -35,16 +35,21 @@ module Synced 
     | 
|
| 
       35 
35 
     | 
    
         
             
                #   on synchronized object and delegated to synced_data Hash
         
     | 
| 
       36 
36 
     | 
    
         
             
                # @option options [Hash] query_params: Given attributes and their values
         
     | 
| 
       37 
37 
     | 
    
         
             
                #   which will be passed to api client to perform search
         
     | 
| 
      
 38 
     | 
    
         
            +
                # @option options [Boolean] auto_paginate: If true (default) will fetch and save all
         
     | 
| 
      
 39 
     | 
    
         
            +
                #   records at once. If false will fetch and save records in batches.
         
     | 
| 
      
 40 
     | 
    
         
            +
                # @option options [Proc] handle_processed_objects_proc: Proc taking one argument (persisted remote objects).
         
     | 
| 
      
 41 
     | 
    
         
            +
                #   Called after persisting remote objects (once in case of auto_paginate, after each batch
         
     | 
| 
      
 42 
     | 
    
         
            +
                #   when paginating with block).
         
     | 
| 
       38 
43 
     | 
    
         
             
                def synced(strategy: :updated_since, **options)
         
     | 
| 
       39 
44 
     | 
    
         
             
                  options.assert_valid_keys(:associations, :data_key, :fields,
         
     | 
| 
       40 
45 
     | 
    
         
             
                    :globalized_attributes, :id_key, :include, :initial_sync_since,
         
     | 
| 
       41 
     | 
    
         
            -
                    :local_attributes, :mapper, :only_updated, :remove,
         
     | 
| 
       42 
     | 
    
         
            -
                    :delegate_attributes, :query_params, :timestamp_strategy)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    :local_attributes, :mapper, :only_updated, :remove, :auto_paginate,
         
     | 
| 
      
 47 
     | 
    
         
            +
                    :delegate_attributes, :query_params, :timestamp_strategy, :handle_processed_objects_proc)
         
     | 
| 
       43 
48 
     | 
    
         
             
                  class_attribute :synced_id_key, :synced_data_key,
         
     | 
| 
       44 
49 
     | 
    
         
             
                    :synced_local_attributes, :synced_associations, :synced_only_updated,
         
     | 
| 
       45 
     | 
    
         
            -
                    :synced_mapper, :synced_remove, :synced_include, :synced_fields,
         
     | 
| 
      
 50 
     | 
    
         
            +
                    :synced_mapper, :synced_remove, :synced_include, :synced_fields, :synced_auto_paginate,
         
     | 
| 
       46 
51 
     | 
    
         
             
                    :synced_globalized_attributes, :synced_initial_sync_since, :synced_delegate_attributes,
         
     | 
| 
       47 
     | 
    
         
            -
                    :synced_query_params, :synced_timestamp_strategy, :synced_strategy
         
     | 
| 
      
 52 
     | 
    
         
            +
                    :synced_query_params, :synced_timestamp_strategy, :synced_strategy, :synced_handle_processed_objects_proc
         
     | 
| 
       48 
53 
     | 
    
         
             
                  self.synced_strategy              = strategy
         
     | 
| 
       49 
54 
     | 
    
         
             
                  self.synced_id_key                = options.fetch(:id_key, :synced_id)
         
     | 
| 
       50 
55 
     | 
    
         
             
                  self.synced_data_key              = options.fetch(:data_key,
         
     | 
| 
         @@ -63,6 +68,8 @@ module Synced 
     | 
|
| 
       63 
68 
     | 
    
         
             
                  self.synced_delegate_attributes   = options.fetch(:delegate_attributes, [])
         
     | 
| 
       64 
69 
     | 
    
         
             
                  self.synced_query_params          = options.fetch(:query_params, {})
         
     | 
| 
       65 
70 
     | 
    
         
             
                  self.synced_timestamp_strategy    = options.fetch(:timestamp_strategy, nil)
         
     | 
| 
      
 71 
     | 
    
         
            +
                  self.synced_auto_paginate         = options.fetch(:auto_paginate, true)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  self.synced_handle_processed_objects_proc  = options.fetch(:handle_processed_objects_proc, nil)
         
     | 
| 
       66 
73 
     | 
    
         
             
                  include Synced::DelegateAttributes
         
     | 
| 
       67 
74 
     | 
    
         
             
                  include Synced::HasSyncedData
         
     | 
| 
       68 
75 
     | 
    
         
             
                end
         
     | 
| 
         @@ -84,6 +91,8 @@ module Synced 
     | 
|
| 
       84 
91 
     | 
    
         
             
                #   You can also force method to remove local objects by passing it
         
     | 
| 
       85 
92 
     | 
    
         
             
                #   to remove: :mark_as_missing. This option can be defined in the model
         
     | 
| 
       86 
93 
     | 
    
         
             
                #   and then overwritten in the synchronize method.
         
     | 
| 
      
 94 
     | 
    
         
            +
                # @param auto_paginate [Boolean] - If true (default) will fetch and save all
         
     | 
| 
      
 95 
     | 
    
         
            +
                #   records at once. If false will fetch and save records in batches.
         
     | 
| 
       87 
96 
     | 
    
         
             
                # @param api [BookingSync::API::Client] - API client to be used for fetching
         
     | 
| 
       88 
97 
     | 
    
         
             
                #   remote objects
         
     | 
| 
       89 
98 
     | 
    
         
             
                # @example Synchronizing amenities
         
     | 
| 
         @@ -97,11 +106,12 @@ module Synced 
     | 
|
| 
       97 
106 
     | 
    
         
             
                #  website.rentals.synchronize(remote: remote_rentals)
         
     | 
| 
       98 
107 
     | 
    
         
             
                #
         
     | 
| 
       99 
108 
     | 
    
         
             
                def synchronize(scope: scope_from_relation, strategy: synced_strategy, **options)
         
     | 
| 
       100 
     | 
    
         
            -
                  options.assert_valid_keys(:api, :fields, :include, :remote, :remove, :query_params, :association_sync)
         
     | 
| 
      
 109 
     | 
    
         
            +
                  options.assert_valid_keys(:api, :fields, :include, :remote, :remove, :query_params, :association_sync, :auto_paginate)
         
     | 
| 
       101 
110 
     | 
    
         
             
                  options[:remove]  = synced_remove unless options.has_key?(:remove)
         
     | 
| 
       102 
111 
     | 
    
         
             
                  options[:include] = Array.wrap(synced_include) unless options.has_key?(:include)
         
     | 
| 
       103 
112 
     | 
    
         
             
                  options[:fields]  = Array.wrap(synced_fields) unless options.has_key?(:fields)
         
     | 
| 
       104 
113 
     | 
    
         
             
                  options[:query_params] = synced_query_params unless options.has_key?(:query_params)
         
     | 
| 
      
 114 
     | 
    
         
            +
                  options[:auto_paginate] = synced_auto_paginate unless options.has_key?(:auto_paginate)
         
     | 
| 
       105 
115 
     | 
    
         
             
                  options.merge!({
         
     | 
| 
       106 
116 
     | 
    
         
             
                    scope:                 scope,
         
     | 
| 
       107 
117 
     | 
    
         
             
                    strategy:              strategy,
         
     | 
| 
         @@ -114,7 +124,8 @@ module Synced 
     | 
|
| 
       114 
124 
     | 
    
         
             
                    mapper:                synced_mapper,
         
     | 
| 
       115 
125 
     | 
    
         
             
                    globalized_attributes: synced_globalized_attributes,
         
     | 
| 
       116 
126 
     | 
    
         
             
                    initial_sync_since:    synced_initial_sync_since,
         
     | 
| 
       117 
     | 
    
         
            -
                    timestamp_strategy:    synced_timestamp_strategy
         
     | 
| 
      
 127 
     | 
    
         
            +
                    timestamp_strategy:    synced_timestamp_strategy,
         
     | 
| 
      
 128 
     | 
    
         
            +
                    handle_processed_objects_proc:  synced_handle_processed_objects_proc
         
     | 
| 
       118 
129 
     | 
    
         
             
                  })
         
     | 
| 
       119 
130 
     | 
    
         
             
                  Synced::Synchronizer.new(self, options).perform
         
     | 
| 
       120 
131 
     | 
    
         
             
                end
         
     | 
| 
         @@ -19,24 +19,32 @@ module Synced 
     | 
|
| 
       19 
19 
     | 
    
         
             
                  #      ActiveRecord::Model #changes hash is returned - changed objects
         
     | 
| 
       20 
20 
     | 
    
         
             
                  # @return [Synced::Strategies::Check::Result] Integrity check result
         
     | 
| 
       21 
21 
     | 
    
         
             
                  def perform
         
     | 
| 
      
 22 
     | 
    
         
            +
                    process_remote_objects(remote_objects_tester)
         
     | 
| 
       22 
23 
     | 
    
         
             
                    result.additional = remove_relation.to_a
         
     | 
| 
       23 
     | 
    
         
            -
                     
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
                           
     | 
| 
      
 24 
     | 
    
         
            +
                    result
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def remote_objects_tester
         
     | 
| 
      
 28 
     | 
    
         
            +
                    lambda do |remote_objects|
         
     | 
| 
      
 29 
     | 
    
         
            +
                      @remote_objects_ids.concat(remote_objects.map(&:id))
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                      remote_objects.map do |remote|
         
     | 
| 
      
 32 
     | 
    
         
            +
                        if local_object = local_object_by_remote_id(remote.id)
         
     | 
| 
      
 33 
     | 
    
         
            +
                          remote.extend(@mapper) if @mapper
         
     | 
| 
      
 34 
     | 
    
         
            +
                          local_object.attributes = default_attributes_mapping(remote)
         
     | 
| 
      
 35 
     | 
    
         
            +
                          local_object.attributes = local_attributes_mapping(remote)
         
     | 
| 
      
 36 
     | 
    
         
            +
                          if @globalized_attributes.present?
         
     | 
| 
      
 37 
     | 
    
         
            +
                            local_object.attributes = globalized_attributes_mapping(remote,
         
     | 
| 
      
 38 
     | 
    
         
            +
                              local_object.translations.translated_locales)
         
     | 
| 
      
 39 
     | 
    
         
            +
                          end
         
     | 
| 
      
 40 
     | 
    
         
            +
                          if local_object.changed?
         
     | 
| 
      
 41 
     | 
    
         
            +
                            result.changed << [{ id: local_object.id }, local_object.changes]
         
     | 
| 
      
 42 
     | 
    
         
            +
                          end
         
     | 
| 
      
 43 
     | 
    
         
            +
                        else
         
     | 
| 
      
 44 
     | 
    
         
            +
                          result.missing << remote
         
     | 
| 
       34 
45 
     | 
    
         
             
                        end
         
     | 
| 
       35 
     | 
    
         
            -
                      else
         
     | 
| 
       36 
     | 
    
         
            -
                        result.missing << remote
         
     | 
| 
       37 
46 
     | 
    
         
             
                      end
         
     | 
| 
       38 
47 
     | 
    
         
             
                    end
         
     | 
| 
       39 
     | 
    
         
            -
                    result
         
     | 
| 
       40 
48 
     | 
    
         
             
                  end
         
     | 
| 
       41 
49 
     | 
    
         | 
| 
       42 
50 
     | 
    
         
             
                  # If we check model which uses cancel instead of destroy, we skip canceled
         
     | 
| 
         @@ -42,6 +42,8 @@ module Synced 
     | 
|
| 
       42 
42 
     | 
    
         
             
                  #   mapping remote objects attributes into local object attributes
         
     | 
| 
       43 
43 
     | 
    
         
             
                  # @option options [Array|Hash] globalized_attributes: A list of attributes
         
     | 
| 
       44 
44 
     | 
    
         
             
                  #   which will be mapped with their translations.
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # @option options [Boolean] auto_paginate: If true (default) will fetch and save all
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #   records at once. If false will fetch and save records in batches.
         
     | 
| 
       45 
47 
     | 
    
         
             
                  def initialize(model_class, options = {})
         
     | 
| 
       46 
48 
     | 
    
         
             
                    @model_class           = model_class
         
     | 
| 
       47 
49 
     | 
    
         
             
                    @scope                 = options[:scope]
         
     | 
| 
         @@ -61,30 +63,21 @@ module Synced 
     | 
|
| 
       61 
63 
     | 
    
         
             
                    @remote_objects        = Array.wrap(options[:remote]) unless @perform_request
         
     | 
| 
       62 
64 
     | 
    
         
             
                    @globalized_attributes = synced_attributes_as_hash(options[:globalized_attributes])
         
     | 
| 
       63 
65 
     | 
    
         
             
                    @query_params         = options[:query_params]
         
     | 
| 
      
 66 
     | 
    
         
            +
                    @auto_paginate         = options[:auto_paginate]
         
     | 
| 
      
 67 
     | 
    
         
            +
                    @handle_processed_objects_proc = options[:handle_processed_objects_proc]
         
     | 
| 
      
 68 
     | 
    
         
            +
                    @remote_objects_ids = []
         
     | 
| 
       64 
69 
     | 
    
         
             
                  end
         
     | 
| 
       65 
70 
     | 
    
         | 
| 
       66 
71 
     | 
    
         
             
                  def perform
         
     | 
| 
       67 
72 
     | 
    
         
             
                    instrument("perform.synced", model: @model_class) do
         
     | 
| 
       68 
73 
     | 
    
         
             
                      relation_scope.transaction do
         
     | 
| 
      
 74 
     | 
    
         
            +
                        processed_objects = instrument("sync_perform.synced", model: @model_class) do
         
     | 
| 
      
 75 
     | 
    
         
            +
                          process_remote_objects(remote_objects_persistor)
         
     | 
| 
      
 76 
     | 
    
         
            +
                        end
         
     | 
| 
       69 
77 
     | 
    
         
             
                        instrument("remove_perform.synced", model: @model_class) do
         
     | 
| 
       70 
78 
     | 
    
         
             
                          remove_relation.send(remove_strategy) if @remove
         
     | 
| 
       71 
79 
     | 
    
         
             
                        end
         
     | 
| 
       72 
     | 
    
         
            -
                         
     | 
| 
       73 
     | 
    
         
            -
                          remote_objects.map do |remote|
         
     | 
| 
       74 
     | 
    
         
            -
                            remote.extend(@mapper) if @mapper
         
     | 
| 
       75 
     | 
    
         
            -
                            local_object = local_object_by_remote_id(remote.id) || relation_scope.new
         
     | 
| 
       76 
     | 
    
         
            -
                            local_object.attributes = default_attributes_mapping(remote)
         
     | 
| 
       77 
     | 
    
         
            -
                            local_object.attributes = local_attributes_mapping(remote)
         
     | 
| 
       78 
     | 
    
         
            -
                            if @globalized_attributes.present?
         
     | 
| 
       79 
     | 
    
         
            -
                              local_object.attributes = globalized_attributes_mapping(remote,
         
     | 
| 
       80 
     | 
    
         
            -
                                local_object.translations.translated_locales)
         
     | 
| 
       81 
     | 
    
         
            -
                            end
         
     | 
| 
       82 
     | 
    
         
            -
                            local_object.save! if local_object.changed?
         
     | 
| 
       83 
     | 
    
         
            -
                            local_object.tap do |local_object|
         
     | 
| 
       84 
     | 
    
         
            -
                              synchronize_associations(remote, local_object)
         
     | 
| 
       85 
     | 
    
         
            -
                            end
         
     | 
| 
       86 
     | 
    
         
            -
                          end
         
     | 
| 
       87 
     | 
    
         
            -
                        end
         
     | 
| 
      
 80 
     | 
    
         
            +
                        processed_objects
         
     | 
| 
       88 
81 
     | 
    
         
             
                      end
         
     | 
| 
       89 
82 
     | 
    
         
             
                    end
         
     | 
| 
       90 
83 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -95,6 +88,32 @@ module Synced 
     | 
|
| 
       95 
88 
     | 
    
         | 
| 
       96 
89 
     | 
    
         
             
                  private
         
     | 
| 
       97 
90 
     | 
    
         | 
| 
      
 91 
     | 
    
         
            +
                  def remote_objects_persistor
         
     | 
| 
      
 92 
     | 
    
         
            +
                    lambda do |remote_objects|
         
     | 
| 
      
 93 
     | 
    
         
            +
                      additional_errors_check
         
     | 
| 
      
 94 
     | 
    
         
            +
                      @remote_objects_ids.concat(remote_objects.map(&:id))
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                      processed_objects =
         
     | 
| 
      
 97 
     | 
    
         
            +
                        remote_objects.map do |remote|
         
     | 
| 
      
 98 
     | 
    
         
            +
                          remote.extend(@mapper) if @mapper
         
     | 
| 
      
 99 
     | 
    
         
            +
                          local_object = local_object_by_remote_id(remote.id) || relation_scope.new
         
     | 
| 
      
 100 
     | 
    
         
            +
                          local_object.attributes = default_attributes_mapping(remote)
         
     | 
| 
      
 101 
     | 
    
         
            +
                          local_object.attributes = local_attributes_mapping(remote)
         
     | 
| 
      
 102 
     | 
    
         
            +
                          if @globalized_attributes.present?
         
     | 
| 
      
 103 
     | 
    
         
            +
                            local_object.attributes = globalized_attributes_mapping(remote,
         
     | 
| 
      
 104 
     | 
    
         
            +
                              local_object.translations.translated_locales)
         
     | 
| 
      
 105 
     | 
    
         
            +
                          end
         
     | 
| 
      
 106 
     | 
    
         
            +
                          local_object.save! if local_object.changed?
         
     | 
| 
      
 107 
     | 
    
         
            +
                          local_object.tap do |local_object|
         
     | 
| 
      
 108 
     | 
    
         
            +
                            synchronize_associations(remote, local_object)
         
     | 
| 
      
 109 
     | 
    
         
            +
                          end
         
     | 
| 
      
 110 
     | 
    
         
            +
                        end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                      @handle_processed_objects_proc.call(processed_objects) if @handle_processed_objects_proc.respond_to?(:call)
         
     | 
| 
      
 113 
     | 
    
         
            +
                      processed_objects
         
     | 
| 
      
 114 
     | 
    
         
            +
                    end
         
     | 
| 
      
 115 
     | 
    
         
            +
                  end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
       98 
117 
     | 
    
         
             
                  def synchronize_associations(remote, local_object)
         
     | 
| 
       99 
118 
     | 
    
         
             
                    @associations.each do |association|
         
     | 
| 
       100 
119 
     | 
    
         
             
                      klass = association.to_s.classify.constantize
         
     | 
| 
         @@ -158,20 +177,32 @@ module Synced 
     | 
|
| 
       158 
177 
     | 
    
         
             
                  end
         
     | 
| 
       159 
178 
     | 
    
         | 
| 
       160 
179 
     | 
    
         
             
                  def local_objects
         
     | 
| 
       161 
     | 
    
         
            -
                     
     | 
| 
      
 180 
     | 
    
         
            +
                    relation_scope.where(@id_key => remote_objects_ids).to_a
         
     | 
| 
       162 
181 
     | 
    
         
             
                  end
         
     | 
| 
       163 
182 
     | 
    
         | 
| 
       164 
183 
     | 
    
         
             
                  def remote_objects_ids
         
     | 
| 
       165 
     | 
    
         
            -
                    @remote_objects_ids 
     | 
| 
      
 184 
     | 
    
         
            +
                    @remote_objects_ids
         
     | 
| 
       166 
185 
     | 
    
         
             
                  end
         
     | 
| 
       167 
186 
     | 
    
         | 
| 
       168 
     | 
    
         
            -
                  def  
     | 
| 
       169 
     | 
    
         
            -
                    @remote_objects 
     | 
| 
      
 187 
     | 
    
         
            +
                  def process_remote_objects(processor)
         
     | 
| 
      
 188 
     | 
    
         
            +
                    if @remote_objects
         
     | 
| 
      
 189 
     | 
    
         
            +
                      processor.call(@remote_objects)
         
     | 
| 
      
 190 
     | 
    
         
            +
                    elsif @perform_request
         
     | 
| 
      
 191 
     | 
    
         
            +
                      fetch_and_save_remote_objects(processor)
         
     | 
| 
      
 192 
     | 
    
         
            +
                    else
         
     | 
| 
      
 193 
     | 
    
         
            +
                      nil
         
     | 
| 
      
 194 
     | 
    
         
            +
                    end
         
     | 
| 
       170 
195 
     | 
    
         
             
                  end
         
     | 
| 
       171 
196 
     | 
    
         | 
| 
       172 
     | 
    
         
            -
                  def  
     | 
| 
      
 197 
     | 
    
         
            +
                  def fetch_and_save_remote_objects(processor)
         
     | 
| 
       173 
198 
     | 
    
         
             
                    instrument("fetch_remote_objects.synced", model: @model_class) do
         
     | 
| 
       174 
     | 
    
         
            -
                       
     | 
| 
      
 199 
     | 
    
         
            +
                      if @auto_paginate
         
     | 
| 
      
 200 
     | 
    
         
            +
                        processor.call(api.paginate(resource_name, api_request_options))
         
     | 
| 
      
 201 
     | 
    
         
            +
                      else
         
     | 
| 
      
 202 
     | 
    
         
            +
                        api.paginate(resource_name, api_request_options) do |batch|
         
     | 
| 
      
 203 
     | 
    
         
            +
                          processor.call(batch)
         
     | 
| 
      
 204 
     | 
    
         
            +
                        end
         
     | 
| 
      
 205 
     | 
    
         
            +
                      end
         
     | 
| 
       175 
206 
     | 
    
         
             
                    end
         
     | 
| 
       176 
207 
     | 
    
         
             
                  end
         
     | 
| 
       177 
208 
     | 
    
         | 
| 
         @@ -183,7 +214,7 @@ module Synced 
     | 
|
| 
       183 
214 
     | 
    
         
             
                        options[:include] += @include
         
     | 
| 
       184 
215 
     | 
    
         
             
                      end
         
     | 
| 
       185 
216 
     | 
    
         
             
                      options[:fields] = @fields if @fields.present?
         
     | 
| 
       186 
     | 
    
         
            -
                      options[:auto_paginate] =  
     | 
| 
      
 217 
     | 
    
         
            +
                      options[:auto_paginate] = @auto_paginate
         
     | 
| 
       187 
218 
     | 
    
         
             
                    end.merge(query_params)
         
     | 
| 
       188 
219 
     | 
    
         
             
                  end
         
     | 
| 
       189 
220 
     | 
    
         | 
| 
         @@ -223,6 +254,9 @@ module Synced 
     | 
|
| 
       223 
254 
     | 
    
         
             
                    Synced.instrumenter.instrument(*args, &block)
         
     | 
| 
       224 
255 
     | 
    
         
             
                  end
         
     | 
| 
       225 
256 
     | 
    
         | 
| 
      
 257 
     | 
    
         
            +
                  def additional_errors_check
         
     | 
| 
      
 258 
     | 
    
         
            +
                  end
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
       226 
260 
     | 
    
         
             
                  class MissingAPIClient < StandardError
         
     | 
| 
       227 
261 
     | 
    
         
             
                    def initialize(scope, model_class)
         
     | 
| 
       228 
262 
     | 
    
         
             
                      @scope = scope
         
     | 
| 
         @@ -16,11 +16,8 @@ module Synced 
     | 
|
| 
       16 
16 
     | 
    
         
             
                  end
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                  def perform
         
     | 
| 
       19 
     | 
    
         
            -
                    raise MissingTimestampError.new unless first_request_timestamp
         
     | 
| 
       20 
19 
     | 
    
         
             
                    super.tap do |local_objects|
         
     | 
| 
       21 
20 
     | 
    
         
             
                      instrument("update_synced_timestamp_perform.synced", model: @model_class) do
         
     | 
| 
       22 
     | 
    
         
            -
                        # TODO: it can't be Time.now. this value has to be fetched from the API as well
         
     | 
| 
       23 
     | 
    
         
            -
                        # https://github.com/BookingSync/synced/issues/29
         
     | 
| 
       24 
21 
     | 
    
         
             
                        @timestamp_strategy.update(first_request_timestamp)
         
     | 
| 
       25 
22 
     | 
    
         
             
                      end
         
     | 
| 
       26 
23 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -62,13 +59,13 @@ module Synced 
     | 
|
| 
       62 
59 
     | 
    
         
             
                  end
         
     | 
| 
       63 
60 
     | 
    
         | 
| 
       64 
61 
     | 
    
         
             
                  def meta
         
     | 
| 
       65 
     | 
    
         
            -
                     
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
      
 62 
     | 
    
         
            +
                    @meta ||=
         
     | 
| 
      
 63 
     | 
    
         
            +
                      (api.last_response && api.last_response.meta) || {}
         
     | 
| 
       67 
64 
     | 
    
         
             
                  end
         
     | 
| 
       68 
65 
     | 
    
         | 
| 
       69 
66 
     | 
    
         
             
                  def first_response_headers
         
     | 
| 
       70 
     | 
    
         
            -
                     
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
      
 67 
     | 
    
         
            +
                    @first_response_headers ||=
         
     | 
| 
      
 68 
     | 
    
         
            +
                      (api.pagination_first_response && api.pagination_first_response.headers) || {}
         
     | 
| 
       72 
69 
     | 
    
         
             
                  end
         
     | 
| 
       73 
70 
     | 
    
         | 
| 
       74 
71 
     | 
    
         
             
                  # Remove all objects with ids from deleted_ids field in the meta key
         
     | 
| 
         @@ -76,6 +73,10 @@ module Synced 
     | 
|
| 
       76 
73 
     | 
    
         
             
                    relation_scope.where(@id_key => deleted_remote_objects_ids)
         
     | 
| 
       77 
74 
     | 
    
         
             
                  end
         
     | 
| 
       78 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
                  def additional_errors_check
         
     | 
| 
      
 77 
     | 
    
         
            +
                    raise MissingTimestampError.new unless first_request_timestamp
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
       79 
80 
     | 
    
         
             
                  class CannotDeleteDueToNoDeletedIdsError < StandardError
         
     | 
| 
       80 
81 
     | 
    
         
             
                    def initialize(model_class)
         
     | 
| 
       81 
82 
     | 
    
         
             
                      @model_class = model_class
         
     | 
    
        data/lib/synced/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: synced
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.5.0
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Sebastien Grosjean
         
     | 
| 
         @@ -9,7 +9,7 @@ authors: 
     | 
|
| 
       9 
9 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       10 
10 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       11 
11 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       12 
     | 
    
         
            -
            date:  
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2017-02-27 00:00:00.000000000 Z
         
     | 
| 
       13 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       14 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       15 
15 
     | 
    
         
             
              name: rails
         
     | 
| 
         @@ -31,14 +31,14 @@ dependencies: 
     | 
|
| 
       31 
31 
     | 
    
         
             
                requirements:
         
     | 
| 
       32 
32 
     | 
    
         
             
                - - ">="
         
     | 
| 
       33 
33 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       34 
     | 
    
         
            -
                    version: 0.1. 
     | 
| 
      
 34 
     | 
    
         
            +
                    version: 0.1.4
         
     | 
| 
       35 
35 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       36 
36 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       37 
37 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       38 
38 
     | 
    
         
             
                requirements:
         
     | 
| 
       39 
39 
     | 
    
         
             
                - - ">="
         
     | 
| 
       40 
40 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       41 
     | 
    
         
            -
                    version: 0.1. 
     | 
| 
      
 41 
     | 
    
         
            +
                    version: 0.1.4
         
     | 
| 
       42 
42 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       43 
43 
     | 
    
         
             
              name: hashie
         
     | 
| 
       44 
44 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -53,6 +53,20 @@ dependencies: 
     | 
|
| 
       53 
53 
     | 
    
         
             
                - - ">="
         
     | 
| 
       54 
54 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       55 
55 
     | 
    
         
             
                    version: '0'
         
     | 
| 
      
 56 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 57 
     | 
    
         
            +
              name: appraisal
         
     | 
| 
      
 58 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 59 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 60 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 61 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 62 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 63 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 64 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 65 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 66 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 67 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 68 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 69 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
       56 
70 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       57 
71 
     | 
    
         
             
              name: sqlite3
         
     | 
| 
       58 
72 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -155,14 +169,14 @@ dependencies: 
     | 
|
| 
       155 
169 
     | 
    
         
             
              name: globalize
         
     | 
| 
       156 
170 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       157 
171 
     | 
    
         
             
                requirements:
         
     | 
| 
       158 
     | 
    
         
            -
                - - " 
     | 
| 
      
 172 
     | 
    
         
            +
                - - ">="
         
     | 
| 
       159 
173 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       160 
174 
     | 
    
         
             
                    version: 4.0.2
         
     | 
| 
       161 
175 
     | 
    
         
             
              type: :development
         
     | 
| 
       162 
176 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       163 
177 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       164 
178 
     | 
    
         
             
                requirements:
         
     | 
| 
       165 
     | 
    
         
            -
                - - " 
     | 
| 
      
 179 
     | 
    
         
            +
                - - ">="
         
     | 
| 
       166 
180 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       167 
181 
     | 
    
         
             
                    version: 4.0.2
         
     | 
| 
       168 
182 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
         @@ -224,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       224 
238 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       225 
239 
     | 
    
         
             
            requirements: []
         
     | 
| 
       226 
240 
     | 
    
         
             
            rubyforge_project: 
         
     | 
| 
       227 
     | 
    
         
            -
            rubygems_version: 2. 
     | 
| 
      
 241 
     | 
    
         
            +
            rubygems_version: 2.6.10
         
     | 
| 
       228 
242 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       229 
243 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       230 
244 
     | 
    
         
             
            summary: Keep your BookingSync Application synced with BookingSync.
         
     |