dynamic-records-meritfront 3.0.23 → 3.0.26

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: abe695f1cafabc83e3776b7f2527ca1647102cf8cc3aafc45bae0a5a5adb288f
4
- data.tar.gz: 44125e65532fc6aaee3de08f506194ea3a6718ae24434a5c45268f374fc4192d
3
+ metadata.gz: e61d44017d347ec7083448f67c2a3db1994f49b2a63c21d27c976c8a06c6b777
4
+ data.tar.gz: bbc308253515c6db53e9964701745fbbee832aee9acd7d4c1d64812b532955f3
5
5
  SHA512:
6
- metadata.gz: d9eab130e60095e150b352098e32442377398c735920676a2221586e82996d1d7eeabfd2f081306d4d0cb48c211dc8951d216fe92a66b30adf16fa0648d72189
7
- data.tar.gz: 1d5d4a226354ee08fd8bad951814f03bb0ca4199e5eea2c37516f76639beaf446a111d90cce8495ee4a01a92f0fbdda223f5a27e4f64296e7ca73f7f06dbf3e2
6
+ metadata.gz: f5a7ae8e89825cf74e31e99e4e422087f3eacc9bb290c727c49ec272c8a40f507d932d3e64f85ee43edf8366c6b2fe6121f3303204ff759e838aaa435ea46c55
7
+ data.tar.gz: d70bb9d0a4ab3972ad2f940f0606a1cad2b492ad5fc8daafa892d6014800513ae4d54d2d1d3d1f47d62c3b3bcd5f89c9100173e773cb042dceef4d0b5af4fbd4
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dynamic-records-meritfront (3.0.23)
4
+ dynamic-records-meritfront (3.0.26)
5
5
  hashid-rails
6
6
 
7
7
  GEM
@@ -26,7 +26,7 @@ GEM
26
26
  concurrent-ruby (~> 1.0)
27
27
  minitest (5.17.0)
28
28
  rake (12.3.3)
29
- tzinfo (2.0.5)
29
+ tzinfo (2.0.6)
30
30
  concurrent-ruby (~> 1.0)
31
31
 
32
32
  PLATFORMS
data/README.md CHANGED
@@ -315,6 +315,52 @@ the output:
315
315
  ...]}
316
316
  ```
317
317
  </details>
318
+
319
+ <details>
320
+ <summary>above example with relations (no need for dynamic_attach)</summary>
321
+ #get list of users, those users friends, and who those users follow, all in one request.
322
+
323
+ ```ruby
324
+ friend_attach = attach_on: Proc.new {|users_friend|
325
+ users_friend.friended_to
326
+ }
327
+
328
+ output = ApplicationRecord.instaload_sql([
329
+ User.instaload(%Q{
330
+ select id
331
+ from users
332
+ where users.id = any (:user_ids) and users.created_at > :time
333
+ }, table_name: :limited_users, relied_on: true),
334
+ User.instaload(%Q{
335
+ select friends.smaller_user_id as id, friends.bigger_user_id as friended_to
336
+ from friends
337
+ inner join limited_users on limited_users.id = bigger_user_id
338
+ union
339
+ select friends.bigger_user_id as id, friends.smaller_user_id as friended_to
340
+ from friends
341
+ inner join limited_users ON limited_users.id = smaller_user_id
342
+ }, table_name: :users_friends, base_name: :limited_users, attach_on: attach_on),
343
+ ApplicationRecord.instaload(%Q{
344
+ SELECT follows.followable_id, follows.follower_id
345
+ FROM follows
346
+ INNER JOIN limited_users ON follows.follower_id = limited_users.id
347
+ }, table_name: :users_follows, base_name: :limited_users)
348
+ ], user_ids: uids, time: t)
349
+
350
+ pp out['limited_users']
351
+
352
+ ```
353
+ sql output: same as example above this example
354
+
355
+ printed output (same as in dynamic attach example):
356
+ ```ruby
357
+ #<User id: 3, users_friends: [#<User id: 5, friended_to: 3>, #<User id: 6, friended_to: 3>, #<User id: 21, friended_to: 3>], users_follows: [{"followable_id"=>935, "follower_id"=>3}, {"followable_id"=>938, "follower_id"=>3}, ...]>,
358
+ #<User id: 14, users_friends: [#<User id: 9, friended_to: 14>, #<User id: 21, friended_to: 14>, ...], users_follows: [{"followable_id"=>936, "follower_id"=>14}, {"followable_id"=>937, "follower_id"=>14}, {"followable_id"=>938, "follower_id"=>14}, ...]>,
359
+ #<User id: 9, users_friends: [#<User id: 14, friended_to: 9>, #<User id: 22, friended_to: 9>, ...], users_follows: [{"followable_id"=>938, "follower_id"=>9}, {"followable_id"=>937, "follower_id"=>9}, ...]>,
360
+ #<User id: 19, users_friends: [#<User id: 1, friended_to: 19>, #<User id: 18, friended_to: 19>, ...], users_follows: [{"followable_id"=>935, "follower_id"=>19}, {"followable_id"=>936, "follower_id"=>19}, {"followable_id"=>938, "follower_id"=>19}, ...]>,
361
+ ```
362
+
363
+ </details>
318
364
 
319
365
  #### self.instaload(sql, table_name: nil, relied_on: false, dont_return: false)
320
366
  A method used to prepare data for the instaload_sql method. It returns a hash of options.
@@ -470,6 +516,9 @@ v3.0.6
470
516
  - changed how variables are set for ActiveRecord objects, I gave up on figuring out what ActiveRecord is doing for *the most part* and i now just do a eval("self.#{parameter}=value") type deal. Works well. Allows you to override relations when doing polymorphic stuff which is a pretty big use case.
471
517
  - I am thinking of changing how arrays are handled as that is really the only postgresql based dependency here and that will allow the library to open up to other databases. Issue is all the code I have already written in my app dependant on such things.
472
518
 
519
+ 3.0.24
520
+ - changed how questionable_attribute_set works again, this time by using attr_accessors on the singleton class. Seems to paper over the default reflections nicely which has been a huge issue. They use this weird delegate thing which has been throwing me off. Anyway, no more evals which is nice. This fixed an issue with dynamic attach one-to-many relations.
521
+
473
522
  ## Questions
474
523
  - Q: does the name of a sql operation have anything to do with prepared statements?
475
524
  - A: no, the prepared statement determines uniqueness in some other way, dont worry about collisions. The only issue with prepared statements that I can determine is when you write a statement where things change every time, thus preparing potentially infinite prepared statements. This can be alleviated by using sql arguments correctly. Using arguments correctly also will stop sql injection attacks so. You know. Do it properly. Dont just hard code them into the query.
@@ -1,5 +1,5 @@
1
1
 
2
2
  module DynamicRecordsMeritfront
3
- VERSION = '3.0.23'
3
+ VERSION = '3.0.26'
4
4
  end
5
5
  #this file gets overwritten automatically on minor updates, major ones need to be manually changed
@@ -1,7 +1,7 @@
1
1
  require "dynamic-records-meritfront/version"
2
2
  require 'hashid/rails'
3
3
 
4
- #this file contains multiple classes which should honestly be split up
4
+ #this file contains multiple classes which should honestly be split up.
5
5
 
6
6
  module DynamicRecordsMeritfront
7
7
  extend ActiveSupport::Concern
@@ -22,7 +22,7 @@ module DynamicRecordsMeritfront
22
22
  #Note we defined here as it breaks early on as Rails.application returns nil
23
23
  PROJECT_NAME = Rails.application.class.to_s.split("::").first.to_s.downcase
24
24
  DYNAMIC_SQL_RAW = true
25
-
25
+ attr_accessor :dynamic_reflections
26
26
  end
27
27
 
28
28
  class DynamicSqlVariables
@@ -86,13 +86,11 @@ module DynamicRecordsMeritfront
86
86
  DateTime => ActiveModel::Type::DateTime,
87
87
  Time => ActiveModel::Type::Time,
88
88
  Float => ActiveModel::Type::Float,
89
- NilClass => ActiveModel::Type::Boolean,
90
- Array => Proc.new{ |first_el_class| ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.new(DB_TYPE_MAPS[first_el_class].new) }
89
+ NilClass => ActiveModel::Type::Boolean,
90
+ Array => Proc.new{ |first_el_class| ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.new(DB_TYPE_MAPS[first_el_class].new) } #this one was a mistake
91
91
  }
92
92
 
93
93
  def convert_to_query_attribute(name, v)
94
- #yes its dumb I know dont look at me look at rails
95
-
96
94
  # https://stackoverflow.com/questions/40407700/rails-exec-query-bindings-ignored
97
95
  # binds = [ ActiveRecord::Relation::QueryAttribute.new(
98
96
  # "id", 6, ActiveRecord::Type::Integer.new
@@ -106,11 +104,7 @@ module DynamicRecordsMeritfront
106
104
 
107
105
  type = DB_TYPE_MAPS[v.class]
108
106
  if type.nil?
109
- # if v.class == NilClass
110
- # raise StandardError.new("")
111
- # else
112
- raise StandardError.new("#{name} (of value: #{v}, class: #{v.class}) unsupported class for ApplicationRecord#headache_sql")
113
- # end
107
+ raise StandardError.new("#{name} (of value: #{v}, class: #{v.class}) unsupported class for ApplicationRecord#headache_sql")
114
108
  elsif type.class == Proc
115
109
  a = v[0]
116
110
  # if a.nil?
@@ -168,35 +162,86 @@ module DynamicRecordsMeritfront
168
162
 
169
163
  def questionable_attribute_set(atr, value, as_default: false, push: false)
170
164
  #this is needed on initalization of a new variable after the actual thing has been made already.
165
+ #this is used for attaching records to other records in one-to-one or one-to-many
166
+
167
+ #basically the way this works is by using singletons to paper over the fact that normal reflections
168
+ #even exist. We dont integrate at all with their patterns as they use some crazy delegation stuff
169
+ #that messes just about everything up.
170
+
171
+ #man i thought i was meta coding, these association people just want to see the world burn.
172
+
173
+ #keeping the old code commented for a while because this area keeps breaking and i want a log of what i have tried.
174
+
175
+ self.dynamic_reflections ||= []
176
+
177
+ unless dynamic_reflections.include?(atr.to_s)
178
+ self.dynamic_reflections << atr.to_s
179
+ singleton_class.instance_eval do
180
+ attr_accessor atr.to_sym
181
+ end
182
+ end
183
+ # # if _reflections.keys.include? atr.to_s
184
+ # has_method = methods.include?(atr.to_sym)
185
+ #
186
+ # DevScript.ping(has_method)
187
+ # override = (not(has_method) or (
188
+ # _reflections.keys.include? atr.to_s
189
+ # and not
190
+
191
+ # )
192
+ # DevScript.ping(override)
193
+
194
+ # if override
195
+
196
+
197
+ # end
198
+ #elsif
199
+
200
+ #end
171
201
 
172
- #note that the below is the value lookup for ActiveModel, but values seems to have all the database columns
173
- #in it anyways
174
- #
175
- # def key?(name)
176
- # (values.key?(name) || types.key?(name) || @attributes.key?(name)) && self[name].initialized?
177
- # end
178
- raise StandardError.new('bad options') if as_default and push
179
202
  if as_default
180
- unless self.respond_to? atr
181
- #make sure its accesible in some way
182
- values = @attributes.instance_variable_get(:@values)
183
- if not values.keys.include?(atr)
184
- values[atr] = value
185
- end
203
+ if self.method(atr.to_sym).call().nil?
204
+ self.method("#{atr}=".to_sym).call(value)
205
+ # DevScript.ping("atr #{atr} def #{value}")
186
206
  end
207
+ elsif push
208
+ self.method(atr.to_sym).call().push value
209
+ # DevScript.ping("atr #{atr} push #{value}")
187
210
  else
188
- #no getter/setter methodsout, probably catches missing methods and then redirects to attributes. Lots of magic.
189
- # After multiple attempts, I gave up, so now we use eval. I guess I cant be too mad about magic as
190
- # that seems to be my bread and butter. Hope eval doesnt make it go too slow. Guess everything is evaled
191
- # on some level though?
192
- s = self #afraid self will be a diffrent self in eval. Possibly depending on parser. IDK. Just seemed risky.
193
- if push
194
- eval "s.#{atr} << value"
195
- else
196
- eval "s.#{atr} = value"
197
- end
211
+ self.method("#{atr}=".to_sym).call(value)
212
+ # DevScript.ping("atr #{atr} set #{value}")
198
213
  end
199
214
 
215
+ # raise StandardError.new('bad options') if as_default and push
216
+ # if as_default
217
+ # unless self.respond_to? atr
218
+ # #make sure its accesible in some way
219
+ # values = @attributes.instance_variable_get(:@values)
220
+ # if not values.keys.include?(atr)
221
+ # values[atr] = value
222
+ # end
223
+ # end
224
+ # else
225
+ # if self.reflections.keys.include? atr.to_s
226
+ #
227
+ # else
228
+ # values ||= @attributes.instance_variable_get(:@values)
229
+ # values[atr] << value
230
+ #
231
+ #
232
+ # end
233
+ # #no getter/setter methodsout, probably catches missing methods and then redirects to attributes. Lots of magic.
234
+ # # After multiple attempts, I gave up, so now we use eval. I guess I cant be too mad about magic as
235
+ # # that seems to be my bread and butter. Hope eval doesnt make it go too slow. Guess everything is evaled
236
+ # # on some level though?
237
+ # s = self #afraid self will be a diffrent self in eval. Possibly depending on parser. IDK. Just seemed risky.
238
+ # if push
239
+ # eval "s.#{atr} << value"
240
+ # else
241
+ # eval "s.#{atr} = value"
242
+ # end
243
+ # end
244
+
200
245
  # atr = atr.to_s
201
246
  # setter = "#{atr}="
202
247
  # if respond_to?(setter)
@@ -232,6 +277,9 @@ module DynamicRecordsMeritfront
232
277
  #basically the same as the upstream active record function (as of october 25 2022 on AR V7.0.4)
233
278
  #except that I changed self.class.attribute_names -> self.attribute_names to pick up our
234
279
  #dynamic insanity. Was this a good idea? Well I guess its better than not doing it
280
+
281
+ #I also added dynamic_reflections
282
+
235
283
  inspection = if defined?(@attributes) && @attributes
236
284
  self.attribute_names.filter_map do |name|
237
285
  if _has_attribute?(name)
@@ -242,7 +290,16 @@ module DynamicRecordsMeritfront
242
290
  "not initialized"
243
291
  end
244
292
 
245
- "#<#{self.class} #{inspection}>"
293
+ self.dynamic_reflections ||= []
294
+ dyna = dynamic_reflections.map{|dr|
295
+ [dr, self.method(dr.to_sym).call()]
296
+ }.to_h
297
+
298
+ if dyna.any?
299
+ "#<#{self.class} #{inspection} | #{dyna.to_s}>"
300
+ else
301
+ "#<#{self.class} #{inspection} >"
302
+ end
246
303
  end
247
304
 
248
305
  module ClassMethods
@@ -895,8 +952,9 @@ module DynamicRecordsMeritfront
895
952
 
896
953
  #just for ease of use
897
954
  def headache_preload(records, associations)
898
- self.class.headache_preload(records, associations)
955
+ self.class.headache_preload(records, associations)
899
956
  end
957
+
900
958
  def safe_increment(col, val) #also used in follow, also used in comment#kill
901
959
  self.class.where(id: self.id).update_all("#{col} = #{col} + #{val}")
902
960
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dynamic-records-meritfront
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.23
4
+ version: 3.0.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luke Clancy
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-02-02 00:00:00.000000000 Z
11
+ date: 2023-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashid-rails