dynamic-records-meritfront 3.0.26 → 3.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +9 -9
- data/README.md +56 -9
- data/lib/dynamic-records-meritfront/version.rb +1 -1
- data/lib/dynamic-records-meritfront.rb +74 -30
- 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: dd63ab9cfaf15d4472c125505260f76db354e11856a8e17aefdb2aac197fd675
|
4
|
+
data.tar.gz: f15916d4f9301319c8fbbcd2355cc04406dcaebe4855bfad8395629d652d182d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5af425ecff409a85dd1bdc04b3fd3bc7e7a0ecbb974e51912d66013ad57351099d6004ecd014ee08edb74830948c0ffa0cfc6e71b9b3020151c10ea3195d9ac
|
7
|
+
data.tar.gz: d3ac6b00f58cdd803714742eb37653a57bea2523851058a174273f15329d0da3b8577d439f7f7e878246681c60fe6e979166401a954ee400ce0b678831d490c6
|
data/Gemfile.lock
CHANGED
@@ -1,30 +1,30 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dynamic-records-meritfront (3.
|
4
|
+
dynamic-records-meritfront (3.1.3)
|
5
5
|
hashid-rails
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activemodel (7.0.4.
|
11
|
-
activesupport (= 7.0.4.
|
12
|
-
activerecord (7.0.4.
|
13
|
-
activemodel (= 7.0.4.
|
14
|
-
activesupport (= 7.0.4.
|
15
|
-
activesupport (7.0.4.
|
10
|
+
activemodel (7.0.4.3)
|
11
|
+
activesupport (= 7.0.4.3)
|
12
|
+
activerecord (7.0.4.3)
|
13
|
+
activemodel (= 7.0.4.3)
|
14
|
+
activesupport (= 7.0.4.3)
|
15
|
+
activesupport (7.0.4.3)
|
16
16
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
17
|
i18n (>= 1.6, < 2)
|
18
18
|
minitest (>= 5.1)
|
19
19
|
tzinfo (~> 2.0)
|
20
|
-
concurrent-ruby (1.2.
|
20
|
+
concurrent-ruby (1.2.2)
|
21
21
|
hashid-rails (1.4.1)
|
22
22
|
activerecord (>= 4.0)
|
23
23
|
hashids (~> 1.0)
|
24
24
|
hashids (1.0.6)
|
25
25
|
i18n (1.12.0)
|
26
26
|
concurrent-ruby (~> 1.0)
|
27
|
-
minitest (5.
|
27
|
+
minitest (5.18.0)
|
28
28
|
rake (12.3.3)
|
29
29
|
tzinfo (2.0.6)
|
30
30
|
concurrent-ruby (~> 1.0)
|
data/README.md
CHANGED
@@ -5,8 +5,7 @@ Dyanmic Records Meritfront helps extend active record functionality to make it m
|
|
5
5
|
2. communicate with the backend more effectively with sql queries. This becomes especially relevant when you hit the limits of Active Record Relations and the usual way of querying in rails. For instance, if you have dynamic sql queries that are hard to convert properly into ruby.
|
6
6
|
3. add other helper methods to work with your database, such as checking if relations exist, or if a migration has been run.
|
7
7
|
|
8
|
-
Note that postgres
|
9
|
-
Also note that the gem has not been tested outside of postgres.
|
8
|
+
Note that you will have issues using the gem outside of postgres. These issue can be fixed, and I am considering a major version update to fix them. Let me know and I will probably do it.
|
10
9
|
|
11
10
|
## Basic Examples
|
12
11
|
```ruby
|
@@ -55,7 +54,7 @@ class ApplicationRecord < ActiveRecord::Base
|
|
55
54
|
end
|
56
55
|
```
|
57
56
|
|
58
|
-
|
57
|
+
## SQL methods
|
59
58
|
|
60
59
|
Methods written for easier sql usage.
|
61
60
|
|
@@ -368,6 +367,10 @@ A method used to prepare data for the instaload_sql method. It returns a hash of
|
|
368
367
|
- table_name: sets the name of the temporary postgresql table. This can then be used in further instaload sql snippets.
|
369
368
|
- relied_on: will make it so other instaload sql snippets can reference this table (it makes it use posrgresql's WITH operator)
|
370
369
|
- dont_return: when used with relied_on makes it so that this data is not returned to rails from the database.
|
370
|
+
- base_on: for relations, a proc describing how to attach to the base table
|
371
|
+
- base_name: for relations, the table name for the table to attach to
|
372
|
+
- attach_on: for relations, a proc describing how this table attaches to the the base table
|
373
|
+
- one_to_one: for relations, a boolean that flips one-to-many/one-to-one (default false)
|
371
374
|
|
372
375
|
note that the order of the instaload methods matter depending on how they reference eachother.
|
373
376
|
<details>
|
@@ -393,7 +396,7 @@ taking the output of the instaload_sql method, this method creates relations bet
|
|
393
396
|
- base_name: the name of the table we will be attaching to
|
394
397
|
- attach_name: the name of the table that will be attached
|
395
398
|
- base_on: put a proc here to override the matching key for the base table. Default is, for a user and post type, {|user| user.id}
|
396
|
-
- attach_on: put a proc here to override the matching key for the attach table. Default is, for a user and post type, {|post| post.user_id}
|
399
|
+
- attach_on: put a proc here to override the matching key for the attach table. Default is, for a user and post type, {|post| post.user_id}. Returning an array from this proc will make this object attach to base records that have one of those keys. This can be used with GROUP BY and ARRAY_AGG functions to stop duplicate rows while still attaching where needed. Think of attaching a user to a post where multiple posts can have the same user.
|
397
400
|
- one_to_one: switches between a one-to-one relationship or not
|
398
401
|
|
399
402
|
<details>
|
@@ -421,7 +424,7 @@ printed output:
|
|
421
424
|
|
422
425
|
</details>
|
423
426
|
|
424
|
-
|
427
|
+
## Hashed Global IDS
|
425
428
|
|
426
429
|
hashed global ids look like this: "gid://meritfront/User/K9YI4K". They also have an optional tag so it can also look like "gid://meritfront/User/K9YI4K@user_image". They are based on global ids.
|
427
430
|
|
@@ -448,7 +451,9 @@ See the hashid-rails gem for more (https://github.com/jcypret/hashid-rails). Als
|
|
448
451
|
|
449
452
|
## Potential Issues
|
450
453
|
|
451
|
-
- This gem was made with a postgresql database.
|
454
|
+
- This gem was made with a postgresql database. There will be some issues when using other databases. Let me know and I will help you out how I can. The main issue as far as i can tell in the transition will be with
|
455
|
+
1. dynamic_sql arrays. I assumed going into this that prepared statements were generated when the sql or name of the sql changed *at all*. This is not true, prepared statements are generated based on the underlying logical flow of the request. Because of this I was treating List types as postgresql array data types. Instead I should of converted them to ($1,$2,$3,$4,...etc) strings. This change would make them act similarly to how Lists of Lists are treated currently. This change would make necessary a major version change. There would also need to be an option to roll back to postgresql arrays on a case by case basis for backwards compatibility.
|
456
|
+
2. instaload_sql. The instaload_sql request has hardcoded sql in it that has not been tested on other databases. This may be especially problematic due to the use of the json data-type.
|
452
457
|
- If you return a password column (for example) as pwd, this gem will accept that. That would mean that the password could me accessed as model.pwd. This is cool - until all passwords are getting logged in production servers. So be wary of accessing, storing, and logging of sensative information. Active Record has in built solutions for this type of data, as long as you dont change the column name. This gem is a sharp knife, its very versitile, but its also, you know, sharp.
|
453
458
|
|
454
459
|
## Changelog
|
@@ -496,7 +501,7 @@ since things may be broken already, it seemed like a good time to do this.
|
|
496
501
|
- this also tells me that uniq'ing variables to decrease the number of them was a bad idea which could cause random failures.
|
497
502
|
- functionality improvements
|
498
503
|
- The biggest change is that names are now optional! name_modifiers is now depreciated functionality as it serves no useful purpose. Will leave in for compatibility but take out of documentation. Used to think the name was related to prepared statements. This will lead simpler ruby code.
|
499
|
-
- If name is left out, the name will be set to the location in your app which called the method. For example, when dynamic_sql was called from irb, the name was: "(irb):45:in
|
504
|
+
- If name is left out, the name will be set to the location in your app which called the method. For example, when dynamic_sql was called from irb, the name was: "(irb):45:in 'irb_binding'". This is done using stack trace functionality. In another case the name was "app/models/report.rb:364:in 'refresh_db_methods'"
|
500
505
|
- dynamic_instaload_sql is now just instaload_sql. dynamic_instaload_sql has been aliased.
|
501
506
|
- Name is optional on instaload_sql aswell
|
502
507
|
- MultiAttributeArrays (array's of arrays) which can be passed into dynamic_sql largely for inserts/upserts will now treat symbols as an attribute name. This leads to more consise sql without running into above error.
|
@@ -517,7 +522,16 @@ v3.0.6
|
|
517
522
|
- 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.
|
518
523
|
|
519
524
|
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
|
525
|
+
- 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 relation
|
526
|
+
|
527
|
+
3.1.0
|
528
|
+
- will try keeping breaking changes out of minor version here-on-out.
|
529
|
+
- better debugging messages and warnings for instaload
|
530
|
+
- returning an array in the attach_on proc will now treat each item in the array as its own attach_on key instead of all as one key. So for example you can attach one user to multiple posts, and only return one user object from the database.
|
531
|
+
- see the dynamic_attach docs above for more on that attach_on thing.
|
532
|
+
....
|
533
|
+
- took out undocumented quick_safe_increment and safe_increment as they were not relevant to the gem - and fairly basic.
|
534
|
+
|
521
535
|
|
522
536
|
## Questions
|
523
537
|
- Q: does the name of a sql operation have anything to do with prepared statements?
|
@@ -525,7 +539,40 @@ v3.0.6
|
|
525
539
|
- Q: The default name of my sql statements looks like a stack trace? Whats going on?
|
526
540
|
- A: We set the location of where you called the function as the default name for easy debugging. Its not an error, we just take some info from the stacktrace. It also includes the method name which can provide some insite into what the query is doing. Makes logs alot nicer to look at.
|
527
541
|
- Q: Whats MeritFront?
|
528
|
-
- A: I am making a social media platform
|
542
|
+
- A: I am making a social media platform. See meritfront.com, Its soft launched.
|
543
|
+
- Q: Inspect on user records doesn't seem to work properly
|
544
|
+
- A: inspect is overwritten by many diffrent libraries, in terms of devise for example, they override our override of active record's inspect. The best way to deal with this is to look at the source location of these methods and bring them together (user.method(:inspect).source_location). In my case with devise, i ended up with this in the user record:
|
545
|
+
```ruby
|
546
|
+
def inspect
|
547
|
+
#this is the same as the dynamic records inspect execpt i also melded together some of the
|
548
|
+
#devise stuff to keep passwords etc safe
|
549
|
+
|
550
|
+
inspection = if defined?(@attributes) && @attributes
|
551
|
+
self.attribute_names.filter_map do |name|
|
552
|
+
if _has_attribute?(name)
|
553
|
+
if UNSAFE_ATTRIBUTES_FOR_SERIALIZATION.include? name.to_sym
|
554
|
+
"#{name}: [redacted]"
|
555
|
+
else
|
556
|
+
"#{name}: #{attribute_for_inspect(name)}"
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end.join(", ")
|
560
|
+
else
|
561
|
+
"not initialized"
|
562
|
+
end
|
563
|
+
|
564
|
+
self.dynamic_reflections ||= []
|
565
|
+
dyna = self.dynamic_reflections.map{|dr|
|
566
|
+
[dr, self.method(dr.to_sym).call()]
|
567
|
+
}.to_h
|
568
|
+
|
569
|
+
if dyna.keys.any?
|
570
|
+
"#<#{self.class} #{inspection} | #{dyna.to_s}>"
|
571
|
+
else
|
572
|
+
"#<#{self.class} #{inspection}>"
|
573
|
+
end
|
574
|
+
end
|
575
|
+
```
|
529
576
|
|
530
577
|
## Contributing
|
531
578
|
|
@@ -78,6 +78,7 @@ module DynamicRecordsMeritfront
|
|
78
78
|
DB_TYPE_MAPS = {
|
79
79
|
String => ActiveModel::Type::String,
|
80
80
|
Symbol => ActiveModel::Type::String,
|
81
|
+
ActiveSupport::SafeBuffer => ActiveModel::Type::String,
|
81
82
|
Integer => ActiveModel::Type::BigInteger,
|
82
83
|
BigDecimal => ActiveRecord::Type::Decimal,
|
83
84
|
TrueClass => ActiveModel::Type::Boolean,
|
@@ -199,18 +200,25 @@ module DynamicRecordsMeritfront
|
|
199
200
|
|
200
201
|
#end
|
201
202
|
|
203
|
+
# pi = atr.to_sym == :current_user_follow
|
204
|
+
#DevScript.ping(self.inspect) if pi
|
202
205
|
if as_default
|
203
206
|
if self.method(atr.to_sym).call().nil?
|
204
207
|
self.method("#{atr}=".to_sym).call(value)
|
205
|
-
#
|
208
|
+
# Rails.logger.info "Y #{value.followable_type if value.respond_to? :followable_type}" if pi
|
206
209
|
end
|
210
|
+
# Rails.logger.info "#{atr} ||= #{value}" if pi
|
207
211
|
elsif push
|
208
212
|
self.method(atr.to_sym).call().push value
|
213
|
+
# Rails.logger.info #{atr} << #{value}" if pi
|
209
214
|
# DevScript.ping("atr #{atr} push #{value}")
|
210
215
|
else
|
216
|
+
#out =
|
211
217
|
self.method("#{atr}=".to_sym).call(value)
|
218
|
+
# Rails.logger.info "[#{self.class.to_s} #{self.id}].#{atr} -> #{out.inspect}" if pi
|
212
219
|
# DevScript.ping("atr #{atr} set #{value}")
|
213
220
|
end
|
221
|
+
#Rails.logger.info self.inspect if pi
|
214
222
|
|
215
223
|
# raise StandardError.new('bad options') if as_default and push
|
216
224
|
# if as_default
|
@@ -291,14 +299,14 @@ module DynamicRecordsMeritfront
|
|
291
299
|
end
|
292
300
|
|
293
301
|
self.dynamic_reflections ||= []
|
294
|
-
dyna = dynamic_reflections.map{|dr|
|
302
|
+
dyna = self.dynamic_reflections.map{|dr|
|
295
303
|
[dr, self.method(dr.to_sym).call()]
|
296
304
|
}.to_h
|
297
305
|
|
298
|
-
if dyna.any?
|
306
|
+
if dyna.keys.any?
|
299
307
|
"#<#{self.class} #{inspection} | #{dyna.to_s}>"
|
300
308
|
else
|
301
|
-
"#<#{self.class} #{inspection}
|
309
|
+
"#<#{self.class} #{inspection}>"
|
302
310
|
end
|
303
311
|
end
|
304
312
|
|
@@ -661,14 +669,22 @@ module DynamicRecordsMeritfront
|
|
661
669
|
#formatting options
|
662
670
|
for insta in insta_array
|
663
671
|
if insta[:base_name]
|
664
|
-
if insta[:as]
|
665
|
-
Rails.logger.debug "#{insta[:table_name]} as #{insta[:as]} -> #{insta[:base_name]}"
|
666
|
-
else
|
667
|
-
Rails.logger.debug "#{insta[:table_name]} -> #{insta[:base_name]}"
|
668
|
-
end
|
669
672
|
#in this case, 'as' is meant as to what pseudonym to dynamicly attach it as
|
670
|
-
dynamic_attach(ret_hash, insta[:base_name], insta[:table_name], base_on: insta[:base_on], attach_on: insta[:attach_on],
|
673
|
+
n_attached = dynamic_attach(ret_hash, insta[:base_name], insta[:table_name], base_on: insta[:base_on], attach_on: insta[:attach_on],
|
671
674
|
one_to_one: insta[:one_to_one], as: insta[:as])
|
675
|
+
|
676
|
+
if Rails.logger.level <= 1
|
677
|
+
tn = insta[:table_name]
|
678
|
+
bn = insta[:base_name]
|
679
|
+
tc = ret_hash[tn].count
|
680
|
+
btc = ret_hash[bn].count
|
681
|
+
|
682
|
+
if insta[:as]
|
683
|
+
Rails.logger.debug "#{n_attached} attached from #{tn}(#{tc}) as #{insta[:as]} -> #{bn}(#{btc})"
|
684
|
+
else
|
685
|
+
Rails.logger.debug "#{n_attached} attached from #{tn}(#{tc}) -> #{bn}(#{btc})"
|
686
|
+
end
|
687
|
+
end
|
672
688
|
elsif insta[:as]
|
673
689
|
Rails.logger.debug "#{insta[:table_name]} as #{insta[:as]}"
|
674
690
|
#in this case, the idea is more polymorphic in nature. unless they are confused and just want to rename the table (this can be done with
|
@@ -789,7 +805,7 @@ module DynamicRecordsMeritfront
|
|
789
805
|
base_arr = instaload_sql_output[base_name]
|
790
806
|
|
791
807
|
#return if there is nothing for us to attach to.
|
792
|
-
return if base_arr.nil? or not base_arr.any?
|
808
|
+
return 0 if base_arr.nil? or not base_arr.any?
|
793
809
|
|
794
810
|
#set variables for neatness and so we dont compute each time
|
795
811
|
# base class information
|
@@ -814,7 +830,7 @@ module DynamicRecordsMeritfront
|
|
814
830
|
|
815
831
|
#make sure the attach class has something going on. We do this after the default stage
|
816
832
|
attach_arr = instaload_sql_output[attach_name]
|
817
|
-
return if attach_arr.nil? or not attach_arr.any?
|
833
|
+
return 0 if attach_arr.nil? or not attach_arr.any?
|
818
834
|
|
819
835
|
# attach class information
|
820
836
|
attach_class = attach_arr.first.class
|
@@ -833,9 +849,16 @@ module DynamicRecordsMeritfront
|
|
833
849
|
end
|
834
850
|
|
835
851
|
#return an id->object hash for the base table for better access
|
836
|
-
h =
|
837
|
-
|
838
|
-
|
852
|
+
h = {}
|
853
|
+
duplicates_base = Set[]
|
854
|
+
for base_rec in base_arr
|
855
|
+
bo = base_on.call(base_rec)
|
856
|
+
if h[bo]
|
857
|
+
duplicates_base << bo
|
858
|
+
else
|
859
|
+
h[bo] = base_rec
|
860
|
+
end
|
861
|
+
end
|
839
862
|
|
840
863
|
#decide on the method of getting the matching id for the attach table
|
841
864
|
unless attach_on
|
@@ -880,20 +903,38 @@ module DynamicRecordsMeritfront
|
|
880
903
|
# 1. match base id to the attach id (both configurable)
|
881
904
|
# 2. cancel out if there is no match
|
882
905
|
# 3. otherwise add to the base object.
|
883
|
-
|
884
|
-
|
885
|
-
|
906
|
+
x = 0
|
907
|
+
|
908
|
+
attach_arr.each{|attach_rec|
|
909
|
+
#we have it plural in case it attaches to multiple, for example a user can belong to many post-cards. Yes, this
|
910
|
+
#was a bug. In order to solve it you have to do some sort of 'distinct' or 'group' sql.
|
911
|
+
|
912
|
+
attachment_keys = attach_on.call(attach_rec) #you can use null to escape the vals
|
913
|
+
|
914
|
+
if attachment_keys.nil?
|
886
915
|
Rails.logger.debug "attach_on proc output (which compares to the base_on proc) is outputting nil, this could be a problem depending on your use-case."
|
916
|
+
elsif not attachment_keys.kind_of? Array
|
917
|
+
attachment_keys = [attachment_keys]
|
887
918
|
end
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
919
|
+
|
920
|
+
if attachment_keys and attachment_keys.any?
|
921
|
+
for ak in attachment_keys
|
922
|
+
base_rec = h[ak] #it is also escaped if no base element is found
|
923
|
+
if base_rec
|
924
|
+
dupl = duplicates_base.include? ak
|
925
|
+
if dupl
|
926
|
+
Rails.logger.warn "WARNING in #{attach_name} -> #{base_name}. Duplicate base_on key being utilized (this is usually in error). Only one base record will have an attachment. For the base table, consider using GROUP BY id and ARRAY_AGG for the base_on column."
|
927
|
+
Rails.logger.warn "base_on key: #{ak.to_s}"
|
928
|
+
end
|
929
|
+
|
930
|
+
x += 1 unless dupl
|
931
|
+
add_to_base.call(base_rec, attach_rec)
|
932
|
+
end
|
892
933
|
end
|
893
934
|
end
|
894
935
|
}
|
895
936
|
|
896
|
-
return
|
937
|
+
return x
|
897
938
|
end
|
898
939
|
alias swiss_attach dynamic_attach
|
899
940
|
|
@@ -915,10 +956,11 @@ module DynamicRecordsMeritfront
|
|
915
956
|
return record
|
916
957
|
end
|
917
958
|
end
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
959
|
+
|
960
|
+
#undocumented and simple
|
961
|
+
#def quick_safe_increment(id, col, val)
|
962
|
+
# where(id: id).update_all("#{col} = #{col} + #{val}")
|
963
|
+
#end
|
922
964
|
|
923
965
|
|
924
966
|
end
|
@@ -955,8 +997,10 @@ module DynamicRecordsMeritfront
|
|
955
997
|
self.class.headache_preload(records, associations)
|
956
998
|
end
|
957
999
|
|
958
|
-
|
959
|
-
|
960
|
-
|
1000
|
+
|
1001
|
+
#undocumented and simple
|
1002
|
+
# def safe_increment(col, val) #also used in follow, also used in comment#kill
|
1003
|
+
# self.class.where(id: self.id).update_all("#{col} = #{col} + #{val}")
|
1004
|
+
# end
|
961
1005
|
|
962
1006
|
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.
|
4
|
+
version: 3.1.3
|
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-
|
11
|
+
date: 2023-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashid-rails
|