sheets_db 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cdf056137eb54d33c6647240ada1498ca2527d44fe68dd8f170882ecff233725
4
- data.tar.gz: 61d76eff207e4d88bbad700ea9be592dbdbac4a2d709a1883c53dbeae055790e
3
+ metadata.gz: 8186e2c37fc147e8bcc4fed8c4bf288b05dde2466c9145e24882d7e1c41d3d35
4
+ data.tar.gz: cdaf52978086b08fed7cd9635aed44ae2f06bfb756058f1eb4d4fc0bf73e8945
5
5
  SHA512:
6
- metadata.gz: a589ac3ae9d86b63b65691d12ef212323f1ea9266bb8e2230b67972781ba0ca5ec812f3befc0341f67261e16e70fb1511bce37103583ee452869fef1df7bc24b
7
- data.tar.gz: a71d6cf51c4795e6d4185e27c37a0dadf51ea2ec8fdf55607586e510e3a437723f508a20ed7c52fb50373c98c08e8c0cfa74289b5b3da40414241a0079c520f0
6
+ metadata.gz: 89fd0245435dcfe13010330ca1220bc1d1ec1082333583021cb65f1d74857f6886eebf4325d7f1107ccdc3a406eb58877c914ef3bbdab8b9c4f1e98ffedb7e70
7
+ data.tar.gz: 2575c45b0f15e24cdbe8296d79a0429eb8120a41414cf112328106b650c70142df3312de2e1d86ffe63ae7c65e32f839bf413ee94c3ea647deae2d2eb692d77a
@@ -2,17 +2,40 @@ module SheetsDB
2
2
  class Collection < Resource
3
3
  set_resource_type GoogleDrive::Collection
4
4
 
5
- def self.has_many(resource, class_name:, resource_type: :subcollections)
6
- unless [:subcollections, :spreadsheets].include?(resource_type)
7
- raise ArgumentError, "resource_type must be :subcollections or :spreadsheets"
5
+ class << self
6
+ def has_many(resource, class_name:, resource_type: :subcollections)
7
+ unless [:subcollections, :spreadsheets].include?(resource_type)
8
+ raise ArgumentError, "resource_type must be :subcollections or :spreadsheets"
9
+ end
10
+ register_association(resource, class_name: class_name, resource_type: resource_type)
11
+ define_method(resource) do
12
+ @associated_resources ||= {}
13
+ @associated_resources[resource] ||= google_drive_resource.send(resource_type).map { |raw|
14
+ Support.constantize(class_name).new(raw)
15
+ }
16
+ end
8
17
  end
9
- register_association(resource, class_name: class_name, resource_type: resource_type)
10
- define_method(resource) do
11
- result = instance_variable_get(:"@#{resource}")
12
- result || instance_variable_set(:"@#{resource}",
13
- google_drive_resource.send(resource_type).map { |raw| Support.constantize(class_name).new(raw) }
14
- )
18
+ end
19
+
20
+ %i[
21
+ spreadsheet
22
+ subcollection
23
+ ].each do |child_resource_type|
24
+ define_method :"google_drive_#{child_resource_type}_by_title" do |title, **kwargs|
25
+ find_child_google_drive_resource_by(type: child_resource_type, title: title, **kwargs)
15
26
  end
16
27
  end
28
+
29
+ def spreadsheets
30
+ @anonymous_resources ||= {}
31
+ @anonymous_resources[:spreadsheets] ||=
32
+ google_drive_resource.spreadsheets.map { |raw| Spreadsheet.new(raw) }
33
+ end
34
+
35
+ def collections
36
+ @anonymous_resources ||= {}
37
+ @anonymous_resources[:collections] ||=
38
+ google_drive_resource.subcollections.map { |raw| Collection.new(raw) }
39
+ end
17
40
  end
18
- end
41
+ end
@@ -2,6 +2,7 @@ module SheetsDB
2
2
  class Resource
3
3
  class ResourceTypeMismatchError < StandardError; end
4
4
  class CollectionTypeAlreadyRegisteredError < StandardError; end
5
+ class ChildResourceNotFoundError < StandardError; end
5
6
 
6
7
  class << self
7
8
  attr_reader :resource_type
@@ -17,8 +18,8 @@ module SheetsDB
17
18
 
18
19
  def find_by_id(id, session: SheetsDB::Session.default)
19
20
  google_drive_resource = session.raw_file_by_id(id)
20
- if @resource_type && !google_drive_resource.is_a?(@resource_type)
21
- fail(ResourceTypeMismatchError, "The file with id #{id} is not a #{@resource_type}")
21
+ if resource_type && !google_drive_resource.is_a?(resource_type)
22
+ fail(ResourceTypeMismatchError, "The file with id #{id} is not a #{resource_type}")
22
23
  end
23
24
  new(google_drive_resource)
24
25
  end
@@ -26,10 +27,10 @@ module SheetsDB
26
27
  def belongs_to_many(resource, class_name:)
27
28
  register_association(resource, class_name: class_name, resource_type: :parents)
28
29
  define_method(resource) do
29
- result = instance_variable_get(:"@#{resource}")
30
- result || instance_variable_set(:"@#{resource}",
31
- google_drive_resource.parents.map { |id| Support.constantize(class_name).find_by_id(id) }
32
- )
30
+ @associated_resources ||= {}
31
+ @associated_resources[resource] ||= google_drive_resource.parents.map { |id|
32
+ Support.constantize(class_name).find_by_id(id)
33
+ }
33
34
  end
34
35
  end
35
36
 
@@ -43,6 +44,15 @@ module SheetsDB
43
44
  class_name: class_name
44
45
  }
45
46
  end
47
+
48
+ def association_methods_for_type(type)
49
+ raise ArgumentError unless %i[spreadsheet worksheet subcollection].include?(type)
50
+
51
+ google_type = type == :spreadsheet ? :file : type
52
+ create_prefix = type == :worksheet ? :add : :create
53
+
54
+ OpenStruct.new(find: :"#{google_type}_by_title", create: :"#{create_prefix}_#{type}")
55
+ end
46
56
  end
47
57
 
48
58
  extend Forwardable
@@ -56,6 +66,16 @@ module SheetsDB
56
66
  @google_drive_resource = google_drive_resource
57
67
  end
58
68
 
69
+ def reload!
70
+ @associated_resources = nil
71
+ @anonymous_resources = nil
72
+ google_drive_resource.reload_metadata
73
+ end
74
+
75
+ def delete!
76
+ google_drive_resource.delete
77
+ end
78
+
59
79
  def ==(other)
60
80
  other.is_a?(self.class) &&
61
81
  other.google_drive_resource == google_drive_resource
@@ -75,5 +95,14 @@ module SheetsDB
75
95
  updated_at: updated_at
76
96
  }
77
97
  end
98
+
99
+ def find_child_google_drive_resource_by(type:, title:, create: false)
100
+ association_methods = self.class.association_methods_for_type(type)
101
+ child_resource = google_drive_resource.public_send(association_methods.find, title)
102
+ child_resource ||= google_drive_resource.public_send(association_methods.create, title) if create
103
+ raise ChildResourceNotFoundError, [self, type, title] if child_resource.nil?
104
+
105
+ child_resource
106
+ end
78
107
  end
79
108
  end
@@ -5,33 +5,26 @@ module SheetsDB
5
5
 
6
6
  set_resource_type GoogleDrive::Spreadsheet
7
7
 
8
- def self.has_many(resource, worksheet_name:, class_name:)
9
- register_worksheet_association(resource, worksheet_name: worksheet_name, class_name: class_name)
10
- create_worksheet_association(resource, worksheet_name: worksheet_name, class_name: class_name)
11
- end
8
+ class << self
9
+ def has_many(resource, worksheet_name:, class_name:)
10
+ register_worksheet_association(resource, worksheet_name: worksheet_name, class_name: class_name)
11
+ create_worksheet_association(resource, worksheet_name: worksheet_name, class_name: class_name)
12
+ end
12
13
 
13
- def self.register_worksheet_association(resource, worksheet_name:, class_name:)
14
- @associations ||= {}
15
- if @associations.fetch(resource, nil)
16
- raise WorksheetAssociationAlreadyRegisteredError
14
+ def register_worksheet_association(resource, worksheet_name:, class_name:)
15
+ @associations ||= {}
16
+ if @associations.fetch(resource, nil)
17
+ raise WorksheetAssociationAlreadyRegisteredError
18
+ end
19
+ @associations[resource] = {
20
+ worksheet_name: worksheet_name,
21
+ class_name: class_name
22
+ }
17
23
  end
18
- @associations[resource] = {
19
- worksheet_name: worksheet_name,
20
- class_name: class_name
21
- }
22
- end
23
24
 
24
- def self.create_worksheet_association(resource, worksheet_name:, class_name:)
25
- define_method(resource) do
26
- @worksheets ||= {}
27
- @worksheets[resource] ||= begin
28
- google_drive_worksheet = google_drive_resource.worksheet_by_title(worksheet_name)
29
- raise WorksheetNotFoundError, worksheet_name if google_drive_worksheet.nil?
30
- Worksheet.new(
31
- spreadsheet: self,
32
- google_drive_resource: google_drive_worksheet,
33
- type: Support.constantize(class_name)
34
- )
25
+ def create_worksheet_association(resource, **kwargs)
26
+ define_method(resource) do
27
+ worksheet_association(resource, **kwargs)
35
28
  end
36
29
  end
37
30
  end
@@ -51,5 +44,35 @@ module SheetsDB
51
44
  def select_from_association(association_name, &block)
52
45
  send(association_name).select(&block)
53
46
  end
47
+
48
+ def worksheet_association(association_name, worksheet_name:, class_name:)
49
+ @associated_resources ||= {}
50
+ @associated_resources[association_name] ||=
51
+ find_or_create_worksheet!(title: worksheet_name, type: Support.constantize(class_name))
52
+ end
53
+
54
+ def worksheets
55
+ @anonymous_resources ||= {}
56
+ @anonymous_resources[:worksheets] ||= google_drive_resource.worksheets.map { |raw|
57
+ set_up_worksheet!(google_drive_resource: raw)
58
+ }
59
+ end
60
+
61
+ def set_up_worksheet!(google_drive_resource:, type: nil)
62
+ Worksheet.new(
63
+ google_drive_resource: google_drive_resource,
64
+ spreadsheet: self,
65
+ type: type
66
+ ).set_up!
67
+ end
68
+
69
+ def find_or_create_worksheet!(title:, type: nil)
70
+ resource = google_drive_worksheet_by_title(title, create: true)
71
+ set_up_worksheet!(google_drive_resource: resource, type: type)
72
+ end
73
+
74
+ def google_drive_worksheet_by_title(title, **kwargs)
75
+ find_child_google_drive_resource_by(type: :worksheet, title: title, **kwargs)
76
+ end
54
77
  end
55
78
  end
@@ -1,3 +1,3 @@
1
1
  module SheetsDB
2
- VERSION = "0.11.0"
2
+ VERSION = "0.12.0"
3
3
  end
@@ -172,6 +172,7 @@ module SheetsDB
172
172
  def reload!
173
173
  worksheet.reload!
174
174
  reset_attributes_and_associations_cache
175
+ self
175
176
  end
176
177
 
177
178
  def save!
@@ -179,6 +180,7 @@ module SheetsDB
179
180
  worksheet.update_attributes_at_row_position(staged_attributes, row_position: row_position)
180
181
  save_changed_foreign_items!
181
182
  reset_attributes_and_associations_cache
183
+ self
182
184
  end
183
185
 
184
186
  def assign_next_row_position_if_not_set
@@ -192,6 +194,7 @@ module SheetsDB
192
194
  def reset_attributes_and_associations_cache
193
195
  @loaded_attributes = {}
194
196
  @loaded_associations = {}
197
+ self
195
198
  end
196
199
 
197
200
  def staged_attributes
@@ -7,15 +7,34 @@ module SheetsDB
7
7
 
8
8
  include Enumerable
9
9
 
10
- attr_reader :spreadsheet, :google_drive_resource, :type, :synchronizing
10
+ attr_reader :spreadsheet, :worksheet_title, :google_drive_resource, :synchronizing
11
11
 
12
- def initialize(spreadsheet:, google_drive_resource:, type:)
12
+ def initialize(spreadsheet:, google_drive_resource:, type: nil)
13
13
  @spreadsheet = spreadsheet
14
14
  @google_drive_resource = google_drive_resource
15
+ @worksheet_title = google_drive_resource.title
15
16
  @type = type
16
17
  @synchronizing = true
17
18
  end
18
19
 
20
+ def set_up!
21
+ if google_drive_resource.num_rows == 0
22
+ registered_column_names = attribute_definitions.map { |name, definition| definition[:column_name] }
23
+ write_matrix!([registered_column_names])
24
+ end
25
+ self
26
+ end
27
+
28
+ def type
29
+ @type || @generated_type ||= begin
30
+ Class.new(Row).tap { |generated_type_class|
31
+ column_names.each do |name|
32
+ generated_type_class.attribute name.to_sym
33
+ end
34
+ }
35
+ end
36
+ end
37
+
19
38
  def ==(other)
20
39
  other.is_a?(self.class) &&
21
40
  other.google_drive_resource == google_drive_resource &&
@@ -31,7 +50,8 @@ module SheetsDB
31
50
  def columns
32
51
  @columns ||= begin
33
52
  {}.tap { |directory|
34
- google_drive_resource.rows.first.each_with_index do |name, i|
53
+ header_row = google_drive_resource.rows.first || []
54
+ header_row.each_with_index do |name, i|
35
55
  unless name == ""
36
56
  directory[name] = Column.new(name: name, column_position: i + 1)
37
57
  end
@@ -98,12 +118,20 @@ module SheetsDB
98
118
 
99
119
  def update_attributes_at_row_position(staged_attributes, row_position:)
100
120
  staged_attributes.each do |attribute_name, value|
101
- attribute_definition, column = get_definition_and_column(attribute_name)
102
- raise ColumnNotFoundError, column unless column
103
- assignment_value = attribute_definition[:multiple] ? value.join(",") : value
104
- google_drive_resource[row_position, column.column_position] = assignment_value
121
+ update_attribute_at_row_position(
122
+ attribute_name: attribute_name,
123
+ value: value,
124
+ row_position: row_position
125
+ )
105
126
  end
106
- google_drive_resource.synchronize if synchronizing
127
+ synchronize! if synchronizing
128
+ end
129
+
130
+ def update_attribute_at_row_position(attribute_name:, value:, row_position:)
131
+ attribute_definition, column = get_definition_and_column(attribute_name)
132
+ raise ColumnNotFoundError, column unless column
133
+ assignment_value = attribute_definition[:multiple] ? value.join(",") : value
134
+ google_drive_resource[row_position, column.column_position] = assignment_value
107
135
  end
108
136
 
109
137
  def next_available_row_position
@@ -163,7 +191,11 @@ module SheetsDB
163
191
  end
164
192
 
165
193
  def reload!
194
+ @columns = nil
195
+ @existing_raw_data = nil
196
+ @generated_type = nil
166
197
  google_drive_resource.reload
198
+ self
167
199
  end
168
200
 
169
201
  def convert_to_boolean(raw_value)
@@ -205,9 +237,64 @@ module SheetsDB
205
237
  def transaction
206
238
  disable_synchronization!
207
239
  yield
208
- google_drive_resource.synchronize
240
+ synchronize!
209
241
  ensure
210
242
  enable_synchronization!
211
243
  end
244
+
245
+ def delete_google_drive_resource!
246
+ google_drive_resource.delete
247
+ @google_drive_resource = nil
248
+ spreadsheet.reload!
249
+ end
250
+
251
+ def truncate!
252
+ clear_google_drive_resource!
253
+ set_up!
254
+ reload!
255
+ end
256
+
257
+ def write_matrix(matrix, rewrite: false, save: false)
258
+ clear_google_drive_resource if rewrite
259
+ google_drive_resource.update_cells(1, 1, matrix)
260
+ synchronize! if save
261
+ self
262
+ end
263
+
264
+ def write_matrix!(matrix, **options)
265
+ write_matrix(matrix, **options.merge(save: true))
266
+ end
267
+
268
+ def write_raw_data(data, **options)
269
+ raise ArgumentError, "mismatched keys" if data.map(&:keys).uniq.count > 1
270
+
271
+ write_matrix(data.map(&:values).prepend(data.first.keys), **options)
272
+ end
273
+
274
+ def write_raw_data!(data, **options)
275
+ write_raw_data(data, **options.merge(save: true))
276
+ end
277
+
278
+ def clear_google_drive_resource(save: false)
279
+ empty_matrix = Array.new(google_drive_resource.num_rows, Array.new(google_drive_resource.num_cols))
280
+ write_matrix(empty_matrix, save: save)
281
+ end
282
+
283
+ def clear_google_drive_resource!
284
+ clear_google_drive_resource(save: true)
285
+ end
286
+
287
+ def synchronize!
288
+ google_drive_resource.synchronize
289
+ @existing_raw_data = nil
290
+ self
291
+ end
292
+
293
+ def existing_raw_data
294
+ @existing_raw_data ||= begin
295
+ rows = google_drive_resource.rows
296
+ rows.drop(1).map { |row| Hash[rows.first.zip(row)] }
297
+ end
298
+ end
212
299
  end
213
300
  end
data/sheets_db.gemspec CHANGED
@@ -22,6 +22,6 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 2.1"
24
24
  spec.add_development_dependency "rake", "~> 13"
25
- spec.add_development_dependency "rspec", "~> 3.10"
25
+ spec.add_development_dependency "rspec", "~> 3.11"
26
26
  spec.add_development_dependency "simplecov"
27
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sheets_db
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ravi Gadad
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-17 00:00:00.000000000 Z
11
+ date: 2023-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google_drive
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.10'
61
+ version: '3.11'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.10'
68
+ version: '3.11'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: simplecov
71
71
  requirement: !ruby/object:Gem::Requirement