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 +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +49 -0
- data/lib/dynamic-records-meritfront/version.rb +1 -1
- data/lib/dynamic-records-meritfront.rb +94 -36
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e61d44017d347ec7083448f67c2a3db1994f49b2a63c21d27c976c8a06c6b777
|
4
|
+
data.tar.gz: bbc308253515c6db53e9964701745fbbee832aee9acd7d4c1d64812b532955f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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,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
|
-
|
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
|
-
#
|
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
|
-
|
181
|
-
#
|
182
|
-
|
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
|
-
#
|
189
|
-
#
|
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
|
-
|
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
|
-
|
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.
|
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-
|
11
|
+
date: 2023-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashid-rails
|