local_model 0.1.9 → 0.1.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: acc6c4975bec354dd97d2a2ef5c320a9525437153b405e484970aa4542e024a7
4
- data.tar.gz: dc6a281ff86af1acf3ec1a414cc75342d13466393773efe90a705f30b175ae63
3
+ metadata.gz: 23ec22d2650b17792c2a03dff88d9dffbcedd78b08ebd05afd057fd124d0476a
4
+ data.tar.gz: 8c89b6eaf25891cb05c3692785d9e88979372be6078ea465d080e9fbd9a7f330
5
5
  SHA512:
6
- metadata.gz: 20d6be57b31cba2fa7f4c87a7f10235ae923e676d4a65ccc73fdf239c0c01fa757f219f3df138ffc68c41ecc6969ab266d5b8e92cd61e3b49ede6e20654c1881
7
- data.tar.gz: 0ed5744beff0da65ad2aecff072d06ddf609d75203409d79c7ba934056c7d2508ae68628721bb26a5eda6ac43f76587c66fac1870ec5e10bb1b06e88947e010d
6
+ metadata.gz: 6b770b1003097729755a6a63df94b909c58eb2c39ae64f398db5ff64083b2846307b173d8da3bd3533efa30ba4dce9dce2170f69ac3e6cc61d886d2b4cf08d5c
7
+ data.tar.gz: 405d6229dbb39b63e8fc5b9dd01d0e3dadaedf06907519f85a411a0d0547c7a1c12d6b1e7528d11f50a6d2e1cfe79f13526f5dcd6e919e1e91125ec9c03290b5
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- local_model (0.1.8)
4
+ local_model (0.1.10)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -81,7 +81,7 @@ As of now, supports:
81
81
  - #destroy, .find, .create, .new, .where, .first, .second, .last, relationships, updating,
82
82
 
83
83
  Does not support yet (notably):
84
- - .build, .update, validations, #<< to add many relationships
84
+ - .build, .update, validations
85
85
  - object equivalence if gotten from source twice
86
86
 
87
87
 
@@ -0,0 +1,41 @@
1
+ class LocalModel::Collection < Array
2
+
3
+ def self.create_from(array: , for_model: , for_collection_class:, add_to_collection_proc:)
4
+ new_obj = new(array)
5
+ new_obj.model = for_model
6
+ new_obj.collection_class = for_collection_class
7
+ new_obj.add_to_collection = add_to_collection_proc
8
+ new_obj
9
+ end
10
+
11
+ attr_accessor :model, :collection_class, :add_to_collection
12
+
13
+ def <<(arg)
14
+ self.push(arg)
15
+ end
16
+
17
+ def push(arg)
18
+ self.[]=(self.length, arg)
19
+ raise ArgumentError.new("#{arg.class} inputted, expecting #{self.collection_class}") if !arg.is_a?(self.collection_class)
20
+ add_to_collection[arg, self.model]
21
+ arg.save && self.model.save
22
+ end
23
+
24
+ def build(**args)
25
+ self.push(collection_class.create(**args))
26
+ end
27
+
28
+ def where(**args)
29
+ self.filter do |el|
30
+ found = true
31
+ args.each do |k,v|
32
+ if el.send(k.to_s) != v
33
+ found = false
34
+ break
35
+ end
36
+ end
37
+ found
38
+ end
39
+ end
40
+
41
+ end
@@ -18,15 +18,15 @@ module CSVInteractable
18
18
  rand_val = @@rand.rand(1000000)
19
19
  f = File.new("#{self.storage_path}-#{rand_val}.prep", 'w')
20
20
  f.close
21
- r = @@rand.rand / 10.0
22
- sleep(r)
21
+ # r = @@rand.rand / 10.0
22
+ # sleep(r)
23
23
 
24
24
  if File.exist?("#{self.storage_path}.bak.csv") || Dir["#{self.storage_path}-*.prep"].length > 1
25
25
  File.delete("#{self.storage_path}-#{rand_val}.prep")
26
- if @@rand.rand(2) == 1
27
- sleep(0.5)
26
+ if @@rand.rand(5) != 1
27
+ sleep(@@rand.rand / 10.0)
28
28
  end
29
- mutate_csv
29
+ mutate_csv(option, block)
30
30
  return
31
31
  else
32
32
  File.delete("#{self.storage_path}-#{rand_val}.prep")
@@ -200,6 +200,17 @@ module CSVInteractable
200
200
  end
201
201
  end
202
202
 
203
+ def delete_all_rows
204
+ begin
205
+ self.mutate_csv(:mutate) {}
206
+ true
207
+ rescue
208
+ File.delete("#{self.storage_path}.bak.csv")
209
+ false
210
+ end
211
+
212
+ end
213
+
203
214
  end
204
215
 
205
216
  module InstanceMethods
@@ -218,6 +229,12 @@ module CSVInteractable
218
229
  end
219
230
  end
220
231
 
232
+ def save!
233
+ if !save
234
+ raise LocalModel::RecordInvalid
235
+ end
236
+ end
237
+
221
238
  end
222
239
 
223
240
  end
@@ -22,7 +22,7 @@ class LocalModel::CSV < LocalModel::Model
22
22
  end
23
23
 
24
24
  self.define_singleton_method :columns do
25
- cols
25
+ cols
26
26
  end
27
27
 
28
28
  schema_data = cols.each_with_index.reduce({}) do |mem, (key,i)|
@@ -52,8 +52,14 @@ class LocalModel::CSV < LocalModel::Model
52
52
  all_instances
53
53
  end
54
54
 
55
+ def self.count
56
+ total = 0
57
+ self.each_record{ total += 1 }
58
+ total
59
+ end
60
+
55
61
  def self.destroy_all
56
- self.all.each{ |obj| obj.destroy }
62
+ delete_all_rows
57
63
  end
58
64
 
59
65
  def self.where(**args)
@@ -105,12 +111,27 @@ class LocalModel::CSV < LocalModel::Model
105
111
  return self.find_by(id: id)
106
112
  end
107
113
 
114
+ def self.find!(id)
115
+ found_record = find(id)
116
+ if !found_record
117
+ raise LocalModel::RecordNotFound.new
118
+ else
119
+ found_record
120
+ end
121
+ end
122
+
108
123
  def self.create(**args)
109
124
  inst = new(**args)
110
125
  inst.save
111
126
  inst
112
127
  end
113
128
 
129
+ def self.create!(**args)
130
+ inst = new(**args)
131
+ inst.save!
132
+ inst
133
+ end
134
+
114
135
  def initialize(**args)
115
136
  args.each do |k,v|
116
137
  self.send("#{k}=", v)
@@ -121,6 +142,11 @@ class LocalModel::CSV < LocalModel::Model
121
142
  def saved?
122
143
  !self.id.nil?
123
144
  end
145
+
146
+ def reload
147
+ raise LocalModel::RecordNotFound if !self.id
148
+ self.class.find!(self.id)
149
+ end
124
150
 
125
151
  def destroy
126
152
  self.class.delete_row({id: self.id})
@@ -0,0 +1,4 @@
1
+ class LocalModel::RecordInvalid < StandardError
2
+
3
+
4
+ end
@@ -0,0 +1,3 @@
1
+ class LocalModel::RecordNotFound < StandardError
2
+
3
+ end
@@ -5,7 +5,14 @@ class LocalModel::Model
5
5
  # yield(SchemaBuilder.new(self))
6
6
  end
7
7
 
8
- def self.belongs_to(association, class_name: nil, foreign_key: nil)
8
+ def self.belongs_to(association, class_name: nil, foreign_key: nil, polymorphic: false)
9
+ if foreign_key.nil?
10
+ keyname = "#{association}_id"
11
+ typename = "#{association}_type"
12
+ else
13
+ keyname = foreign_key
14
+ end
15
+
9
16
  if class_name.nil?
10
17
  association_class_name = LocalModel::Functions.snake_to_camel(association)
11
18
  association_class_name[0] = association_class_name[0].upcase
@@ -14,49 +21,86 @@ class LocalModel::Model
14
21
  association_class_name = namespace_classname(class_name)
15
22
  end
16
23
 
17
- if foreign_key.nil?
18
- keyname = "#{association}_id"
19
- else
20
- keyname = foreign_key
21
- end
22
24
 
23
25
  define_method association do
24
- association_class = Object.const_get(association_class_name)
26
+ if polymorphic
27
+ association_type = self.send(typename)
28
+ return nil if association_type.nil? || association_type.empty?
29
+ polymorphic_class_name = LocalModel::Functions.snake_to_camel(association_type.gsub("_type", ""))
30
+ polymorphic_class_name[0] = polymorphic_class_name[0].upcase
31
+ association_class = Object.const_get(polymorphic_class_name)
32
+ else
33
+ association_class = Object.const_get(association_class_name)
34
+ end
25
35
  id = self.send(keyname)
26
36
  association_class.find(id)
27
37
  end
28
38
 
29
39
  define_method "#{association}=" do |association_obj|
30
- self.send("#{keyname}=", association_obj.id)
40
+ self.send("#{keyname}=", association_obj&.id)
41
+ if polymorphic
42
+ if !association_obj.nil?
43
+ self.send("#{typename}=", association_obj.class.to_s)
44
+ end
45
+ end
31
46
  end
32
47
  end
33
48
 
34
- def self.has_many(association, through: nil, class_name: nil, foreign_key: nil)
49
+ def self.has_many(association, through: nil, class_name: nil, foreign_key: nil, as: nil)
35
50
  if class_name.nil?
36
51
  association_classname = namespace_classname(get_classname_from_association(association))
37
52
  else
38
53
  association_classname = namespace_classname(class_name)
39
54
  end
40
55
 
41
-
42
56
  if through.nil?
43
- current_class_id_methodname = foreign_key || "#{LocalModel::Functions.camel_to_snake(denamespace_classname(self))}_id"
57
+ if as.nil?
58
+ current_class_id_methodname = foreign_key || "#{LocalModel::Functions.camel_to_snake(denamespace_classname(self))}_id"
59
+ else
60
+ current_class_id_methodname = "#{as}_id"
61
+ end
44
62
  belongs_to_id_sym = current_class_id_methodname.to_sym
63
+ add_to_collection = Proc.new do |arg, model|
64
+ arg.send("#{belongs_to_id_sym}=", model.id)
65
+ end
66
+
45
67
  define_method association do
68
+ collection_args = {belongs_to_id_sym => self.id}
69
+ if !as.nil?
70
+ collection_args["#{as}_type".to_sym] = self.class.to_s
71
+ end
72
+
46
73
  association_class = Object.const_get(association_classname)
47
- association_class.where(belongs_to_id_sym => self.id)
74
+ LocalModel::Collection.create_from(
75
+ array: association_class.where(**collection_args),
76
+ for_model: self,
77
+ for_collection_class: association_class,
78
+ add_to_collection_proc: add_to_collection
79
+ )
48
80
  end
49
81
  else
50
82
  current_class_id_methodname = foreign_key || "#{LocalModel::Functions.camel_to_snake(LocalModel::Functions.singularize(association))}_id"
51
83
  belongs_to_id_sym = current_class_id_methodname.to_sym
84
+ add_to_collection = Proc.new do |arg, model|
85
+ through_collection = model.send(through)
86
+ through_classname = through_collection.collection_class
87
+ new_join = through_classname.new
88
+ new_join.send("#{belongs_to_id_sym}=", arg.id)
89
+ through_collection << new_join
90
+ end
52
91
  define_method association do
53
92
  association_class = Object.const_get(association_classname)
54
- self.send(through).map{|through_obj| association_class.find(through_obj.send(belongs_to_id_sym))}
93
+ LocalModel::Collection.create_from(
94
+ array: self.send(through).map{|through_obj| association_class.find(through_obj.send(belongs_to_id_sym))},
95
+ for_model: self,
96
+ for_collection_class: association_class,
97
+ add_to_collection_proc: add_to_collection
98
+ )
55
99
  end
56
100
  end
57
101
  end
58
102
 
59
- def self.has_one(association, through: nil, class_name: nil, foreign_key: nil)
103
+ def self.has_one(association, through: nil, class_name: nil, foreign_key: nil, as: nil)
60
104
  if class_name.nil?
61
105
  association_classname = LocalModel::Functions.snake_to_camel(association)
62
106
  association_classname[0] = association_classname[0].upcase
@@ -66,11 +110,19 @@ class LocalModel::Model
66
110
  end
67
111
 
68
112
  if through.nil?
69
- current_class_id_methodname = foreign_key || "#{LocalModel::Functions.camel_to_snake(denamespace_classname(self))}_id"
113
+ if as.nil?
114
+ current_class_id_methodname = foreign_key || "#{LocalModel::Functions.camel_to_snake(denamespace_classname(self))}_id"
115
+ else
116
+ current_class_id_methodname = "#{as}_id"
117
+ end
70
118
  belongs_to_id_sym = current_class_id_methodname.to_sym
71
119
  define_method association do
120
+ collection_args = {belongs_to_id_sym => self.id}
121
+ if !as.nil?
122
+ collection_args["#{as}_type".to_sym] = self.class.to_s
123
+ end
72
124
  association_class = Object.const_get(association_classname)
73
- association_class.where(belongs_to_id_sym => self.id).first
125
+ association_class.where(**collection_args).first
74
126
  end
75
127
  else
76
128
  current_class_id_methodname = foreign_key || "#{LocalModel::Functions.camel_to_snake(association)}_id"
@@ -113,6 +165,29 @@ class LocalModel::Model
113
165
  "#{LocalModel.path}#{slash}#{self}.csv"
114
166
  end
115
167
 
168
+ def update(**args)
169
+ args.each do |k,v|
170
+ self.send("#{k.to_s}=", v)
171
+ end
172
+ self.save
173
+ end
174
+
175
+ def update!(**args)
176
+ args.each do |k,v|
177
+ self.send("#{k.to_s}=", v)
178
+ end
179
+ self.save!
180
+ end
181
+
182
+ def reload
183
+ self.class.find(self.id)
184
+ end
185
+
186
+ def ==(other)
187
+ self.class == other.class &&
188
+ self.id == other.id
189
+ end
190
+
116
191
 
117
192
  class SchemaBuilder
118
193
 
@@ -1,3 +1,3 @@
1
1
  module LocalModel
2
- VERSION = "0.1.9"
2
+ VERSION = "0.1.12"
3
3
  end
data/lib/local_model.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require_relative "./local_model/version"
2
2
  require 'csv'
3
+ require_relative './local_model/errors/record_invalid'
4
+ require_relative './local_model/errors/record_not_found'
3
5
  require_relative './local_model/sandbox'
6
+ require_relative './local_model/collection'
4
7
  require_relative './local_model/adapters/boolean_adapter'
5
8
  require_relative './local_model/adapters/datetime_adapter'
6
9
  require_relative './local_model/adapters/float_adapter'
@@ -36,6 +39,13 @@ module LocalModel
36
39
  @@path
37
40
  end
38
41
 
42
+ def self.db_drop
43
+ Dir.foreach(@@path) do |f|
44
+ fn = File.join(@@path, f)
45
+ File.delete(fn) if f != '.' && f != '..'
46
+ end
47
+ end
48
+
39
49
  def self.config(&block)
40
50
  configuration = Configuration.new
41
51
  if block_given?
@@ -45,10 +55,7 @@ module LocalModel
45
55
  @@namespace = configuration.namespace
46
56
  Dir.mkdir(configuration.path) unless Dir.exist?(configuration.path)
47
57
  if configuration.cleanup_on_start
48
- Dir.foreach(configuration.path) do |f|
49
- fn = File.join(configuration.path, f)
50
- File.delete(fn) if f != '.' && f != '..'
51
- end
58
+ db_drop
52
59
  end
53
60
  end
54
61
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: local_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micah Shute
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-26 00:00:00.000000000 Z
11
+ date: 2022-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -77,8 +77,11 @@ files:
77
77
  - lib/local_model/adapters/float_adapter.rb
78
78
  - lib/local_model/adapters/integer_adapter.rb
79
79
  - lib/local_model/adapters/string_adapter.rb
80
+ - lib/local_model/collection.rb
80
81
  - lib/local_model/concerns/csv_interactable.rb
81
82
  - lib/local_model/csv.rb
83
+ - lib/local_model/errors/record_invalid.rb
84
+ - lib/local_model/errors/record_not_found.rb
82
85
  - lib/local_model/helpers/functions.rb
83
86
  - lib/local_model/helpers/pluralized_words.rb
84
87
  - lib/local_model/model.rb
@@ -107,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
110
  - !ruby/object:Gem::Version
108
111
  version: '0'
109
112
  requirements: []
110
- rubygems_version: 3.2.3
113
+ rubygems_version: 3.3.7
111
114
  signing_key:
112
115
  specification_version: 4
113
116
  summary: Easily set up a schema persisted with CSV but interactable with AR-like methods