Module: DynamicRecordsMeritfront::ClassMethods
- Defined in:
- lib/dynamic-records-meritfront.rb
Instance Method Summary collapse
- #_dynamic_instaload_handle_with_statements(with_statements) ⇒ Object
- #_dynamic_instaload_union(insta_array) ⇒ Object
- #blind_hgid(id, tag: nil, encode: true) ⇒ Object
- #dynamic_attach(instaload_sql_output, base_name, attach_name, base_on: nil, attach_on: nil, one_to_one: false, as: nil) ⇒ Object (also: #swiss_attach)
- #dynamic_init(klass, input) ⇒ Object
-
#dynamic_preload(records, associations) ⇒ Object
(also: #headache_preload)
allows us to preload on a list and not a active record relation.
-
#dynamic_sql(*args) ⇒ Object
(also: #headache_sql)
see below for opts.
- #get_hgid_tag(hgid_string) ⇒ Object
- #has_association?(*args) ⇒ Boolean
- #has_run_migration?(nm) ⇒ Boolean
- #instaload(sql, table_name: nil, relied_on: false, dont_return: false, base_name: nil, base_on: nil, attach_on: nil, one_to_one: false, as: nil, with: nil) ⇒ Object
-
#instaload_sql(*args) ⇒ Object
(also: #swiss_instaload_sql, #dynamic_instaload_sql)
name, insta_array, opts = { }).
- #list_associations ⇒ Object
- #locate_hgid(hgid_string, with_associations: nil, returns_nil: false) ⇒ Object
- #string_as_selector(str, attribute: 'id') ⇒ Object
- #test_drmf(model_with_an_id_column_and_timestamps) ⇒ Object
- #zip_ar_result(x) ⇒ Object
Instance Method Details
#_dynamic_instaload_handle_with_statements(with_statements) ⇒ Object
595 596 597 598 599 600 601 602 603 604 605 |
# File 'lib/dynamic-records-meritfront.rb', line 595 def _dynamic_instaload_handle_with_statements(with_statements) %Q{WITH #{ with_statements.map{|ws| if(ws[:with]) "#{ws[:with]} AS (\n#{ws[:sql]}\n)" else "#{ws[:table_name]} AS (\n#{ws[:sql]}\n)" end }.join(", \n") }} end |
#_dynamic_instaload_union(insta_array) ⇒ Object
607 608 609 610 611 612 613 614 615 616 617 618 619 620 |
# File 'lib/dynamic-records-meritfront.rb', line 607 def _dynamic_instaload_union(insta_array) insta_array.select{|insta| not insta[:dont_return] }.map{|insta| start = "SELECT row_to_json(#{insta[:table_name]}.*) AS row, '#{insta[:klass]}' AS _klass, '#{insta[:table_name]}' AS _table_name FROM " if insta[:relied_on] ending = "#{insta[:table_name]}\n" else ending = "(\n#{insta[:sql]}\n) AS #{insta[:table_name]}\n" end next start + ending }.join(" UNION ALL \n") #{ other_statements.map{|os| "SELECT row_to_json(#{os[:table_name]}.*) AS row, '#{os[:klass]}' AS _klass FROM (\n#{os[:sql]}\n)) AS #{os[:table_name]}\n" }.join(' UNION ALL ')} end |
#blind_hgid(id, tag: nil, encode: true) ⇒ Object
380 381 382 383 384 385 386 387 388 389 390 391 392 |
# File 'lib/dynamic-records-meritfront.rb', line 380 def blind_hgid(id, tag: nil, encode: true) # this method is to get an hgid for a class without actually calling it down from the database. # For example Notification.blind_hgid 1 will give gid://PROJECT_NAME/Notification/69DAB69 etc. if id.class == Integer and encode id = self.encode_id id end gid = "gid://#{PROJECT_NAME}/#{self.to_s}/#{id}" if !tag gid else "#{gid}@#{tag}" end end |
#dynamic_attach(instaload_sql_output, base_name, attach_name, base_on: nil, attach_on: nil, one_to_one: false, as: nil) ⇒ Object Also known as: swiss_attach
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 |
# File 'lib/dynamic-records-meritfront.rb', line 800 def dynamic_attach(instaload_sql_output, base_name, attach_name, base_on: nil, attach_on: nil, one_to_one: false, as: nil) #as just lets it attach us anywhere on the base class, and not just as the attach_name. #Can be useful in polymorphic situations, otherwise may lead to confusion. #oh the errors base_name = base_name.to_s attach_name = attach_name.to_s as ||= attach_name base_arr = instaload_sql_output[base_name] #return if there is nothing for us to attach to. if base_arr.nil? Rails.logger.error("base table " + base_name + " was not set") return 0 elsif not base_arr.any? Rails.logger.debug("no items in base table " + base_name) return 0 end #set variables for neatness and so we dont compute each time # base class information base_class = base_arr.first.class base_class_is_hash = base_class <= Hash #variable accessors and defaults. Make sure it only sets if not defined already as #the 'as' option allows us to override to what value it actually gets set in the end, #and in polymorphic situations this could be called in multiple instances base_arr.each{ |o| if not base_class_is_hash if one_to_one #attach name must be a string o.questionable_attribute_set(as, nil, as_default: true) else o.questionable_attribute_set(as, [], as_default: true) end elsif not one_to_one o[as] ||= [] end } #make sure the attach class has something going on. We do this after the default stage attach_arr = instaload_sql_output[attach_name] if attach_arr.nil? Rails.logger.error("attaching table " + attach_name + " was not set") return 0 elsif not attach_arr.any? Rails.logger.debug("no items in attach table " + attach_name) return 0 end # attach class information attach_class = attach_arr.first.class attach_class_is_hash = attach_class <= Hash # default attach column info default_attach_col = (base_class.to_s.downcase + "_id") #decide on the method of getting the matching id for the base table unless base_on if base_class_is_hash base_on = Proc.new{|x| x['id']} else base_on = Proc.new{|x| x.id} end end #return an id->object hash for the base table for better access h = {} duplicates_base = Set[] for base_rec in base_arr bo = base_on.call(base_rec) if h[bo] duplicates_base << bo else h[bo] = base_rec end end #decide on the method of getting the matching id for the attach table unless attach_on if attach_class_is_hash attach_on = Proc.new{|x| x[default_attach_col]} else attach_on = Proc.new{|x| x.attributes[default_attach_col] } end end # if debug # Rails.logger.info(base_arr.map{|b| # base_on.call(b) # }) # Rails.logger.info(attach_arr.map{|a| # attach_on.call(a) # }) # end #method of adding the object to the base #(b=base, a=attach) add_to_base = Proc.new{|b, a| if base_class_is_hash if one_to_one b[as] = a else b[as].push a end else #getting a lil tired of the meta stuff. if one_to_one b.questionable_attribute_set(as, a) else b.questionable_attribute_set(as, a, push: true) end end } #for every attachable # 1. match base id to the attach id (both configurable) # 2. cancel out if there is no match # 3. otherwise add to the base object. x = 0 attach_arr.each{|attach_rec| #we have it plural in case it attaches to multiple, for example a user can belong to many post-cards. Yes, this #was a bug. In order to solve it you have to do some sort of 'distinct' or 'group' sql. = attach_on.call(attach_rec) #you can use null to escape the vals if .nil? 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." elsif not .kind_of? Array = [] end if and .any? for ak in base_rec = h[ak] #it is also escaped if no base element is found if base_rec dupl = duplicates_base.include? ak if dupl 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." Rails.logger.warn "base_on key: #{ak.to_s}" end x += 1 unless dupl add_to_base.call(base_rec, attach_rec) end end end } if Rails.logger.level <= 1 if as Rails.logger.debug "#{x}/#{attach_arr.count} attached from #{attach_name} as #{as} -> #{base_name}(#{x}/#{base_arr.count})" else Rails.logger.debug "#{x}/#{attach_arr.count} attached from #{attach_name} -> #{base_name}(#{x}/#{base_arr.count})" end end return x end |
#dynamic_init(klass, input) ⇒ Object
971 972 973 974 975 976 977 978 979 980 981 982 983 984 |
# File 'lib/dynamic-records-meritfront.rb', line 971 def dynamic_init(klass, input) if klass.abstract_class return input else record = klass.instantiate(input.stringify_keys ) #trust me they need to be stringified # #handle attributes through ar if allowed. Throws an error on unkown variables, except apparently for devise classes? 😡 # active_record_handled = input.slice(*(klass.attribute_names & input.keys)) # record = klass.instantiate(active_record_handled) # #set those that were not necessarily expected # not_expected = input.slice(*(input.keys - klass.attribute_names)) # record.dynamic = OpenStruct.new(not_expected.transform_keys{|k|k.to_sym}) if not_expected.keys.any? return record end end |
#dynamic_preload(records, associations) ⇒ Object Also known as: headache_preload
allows us to preload on a list and not a active record relation. So basically from the output of headache_sql
458 459 460 |
# File 'lib/dynamic-records-meritfront.rb', line 458 def dynamic_preload(records, associations) ActiveRecord::Associations::Preloader.new(records: records, associations: associations).call end |
#dynamic_sql(*args) ⇒ Object Also known as: headache_sql
see below for opts
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
# File 'lib/dynamic-records-meritfront.rb', line 464 def dynamic_sql(*args) #see below for opts # call like: dynamic_sql(name, sql, option_1: 1, option_2: 2) # or like: dynamic_sql(sql, {option: 1, option_2: 2}) # or like: dynamic_sql(sql, option: 1, option_2: 2) # or just: dynamic_sql(sql) # # Options: (options not listed will be sql arguments) # - instantiate_class - returns User, Post, etc objects instead of straight sql output. # I prefer doing the alterantive # User.headache_class(...) # which is also supported # - prepare sets whether the db will preprocess the strategy for lookup (defaults true) (I dont think turning this off works...) # - name_modifiers allows one to change the preprocess associated name, useful in cases of dynamic sql. # - multi_query allows more than one query (you can seperate an insert and an update with ';' I dont know how else to say it.) # this disables other options (except name_modifiers). Not sure how it effects prepared statements. Its a fairly useless # command as you can do multiple queries anyway with 'WITH' statements and also gain the other options. # - raw switches between using a Hash or a ActiveRecord::Response object when used on a abstract class args << {} unless args[-1].kind_of? Hash if args.length == 3 name, sql, opts = args elsif args.length == 2 sql, opts = args #give default name functionality as a pointer to source code location #of the method that called this. Love ruby. Meta up the a$$ first_app_stack_trace = caller[0...3].select{|str| not str.include?('dynamic_records_meritfront.rb')}.first shorter_source_loc = first_app_stack_trace.split('/')[-1] name = shorter_source_loc else raise StandardError.new("bad input to DynamicRecordsMeritfront#dynamic_sql method.") end #grab options from the opts hash instantiate_class = opts.delete(:instantiate_class) name_modifiers = opts.delete(:name_modifiers) raw = opts.delete(:raw) raw = DYNAMIC_SQL_RAW if raw.nil? name_modifiers ||= [] prepare = opts.delete(:prepare) != false multi_query = opts.delete(:multi_query) == true params = opts #unique value hash cuts down on the number of repeated arguments like in an update or insert statement #by checking if there is an equal existing argument and then using that argument number instead. #If this functionality is used at a lower level we should probably remove this. #________________________________ #got this error: ActiveRecord::StatementInvalid (PG::ProtocolViolation: ERROR: bind message supplies 3 parameters, but prepared statement "a27" requires 4) #this error tells me two things # 1. the name of a sql statement actually has no effect on prepared statements (whoops). # This means we should accept queries with no name. # 2. Need to get rid of the unique variable name functionality which uniques all the variables # to decrease the amount sent to database #name_modifiers are super unnecessary now I realize the given name is not actually related #to prepped statements. But will keep it as it is backwards compatitable and sorta useful maybe. for mod in name_modifiers name << "_#{mod.to_s}" unless mod.nil? end begin var_track = DynamicSqlVariables.new(params) unless multi_query #https://stackoverflow.com/questions/49947990/can-i-execute-a-raw-sql-query-leverage-prepared-statements-and-not-use-activer/67442353#67442353 #change the keys to $1, $2 etc. this step is needed for ex. {id: 1, id_user: 2}. #doing the longer ones first prevents id replacing :id_user -> $1_user keys = params.keys.sort{|a,b| b.to_s.length <=> a.to_s.length} for key in keys #replace MultiRowExpressions v = params[key] #check if it looks like one looks_like_multi_row_expression = ((v.class == Array) and (not v.first.nil?) and (v.first.class == Array)) if v.class == MultiRowExpression or looks_like_multi_row_expression #we need to substitute with the correct sql now. v = MultiRowExpression.new(v) if looks_like_multi_row_expression #standardize #process into appropriate sql while keeping track of variables sql_for_replace = v.for_query(key, var_track) #replace the key with the sql sql.gsub!(":#{key}", sql_for_replace) else #check if its currently in the sql argument list x = var_track.key_index(key) if x.nil? #if not, get the next number that it will be assigned and replace the key w/ that number. x = var_track.next_sql_num if sql.gsub!(":#{key}", "$#{x}") #only actually add to sql arguments when we know the attribute was used. var_track.add_key_value(key, v) end else #its already in use as a sql argument and has a number, use that number. sql.gsub!(":#{key}", "$#{x}") end end end sql_vals = var_track.get_array_for_exec_query ret = ActiveRecord::Base.connection.exec_query sql, name, sql_vals, prepare: prepare else ret = ActiveRecord::Base.connection.execute sql, name end rescue Exception => e #its ok if some of these are empty, just dont want the error name ||= '' sql ||= '' sql_vals ||= '' prepare ||= '' Rails.logger.error(%Q{ DynamicRecords#dynamic_sql debug info. name: #{name.to_s} sql: #{sql.to_s} sql_vals: #{sql_vals.to_s} prepare: #{prepare.to_s} }) raise e end #this returns a PG::Result object, which is pretty basic. To make this into User/Post/etc objects we do #the following if instantiate_class or not self.abstract_class instantiate_class = self if not instantiate_class #no I am not actually this cool see https://stackoverflow.com/questions/30826015/convert-pgresult-to-an-active-record-model ret = ret.to_a return ret.map{|r| dynamic_init(instantiate_class, r)} else if raw return ret else return ret.to_a end end end |
#get_hgid_tag(hgid_string) ⇒ Object
449 450 451 452 453 454 455 |
# File 'lib/dynamic-records-meritfront.rb', line 449 def get_hgid_tag(hgid_string) if hgid_string.include?('@') return hgid_string.split('@')[-1] else return nil end end |
#has_association?(*args) ⇒ Boolean
369 370 371 372 373 374 375 376 377 378 379 |
# File 'lib/dynamic-records-meritfront.rb', line 369 def has_association?(*args) #checks whether current class has needed association (for example, checks it has comments) #associations can be seen in has_many belongs_to and other similar methods #flattens so you can pass self.has_association?(:comments, :baseable_comments) aswell as # self.has_association?([:comments, :baseable_comments]) without issue # args = args.flatten.map { |a| a.to_sym } associations = list_associations (args.length == (associations & args).length) end |
#has_run_migration?(nm) ⇒ Boolean
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/dynamic-records-meritfront.rb', line 315 def has_run_migration?(nm) #put in a string name of the class and it will say if it has allready run the migration. #good during enum migrations as the code to migrate wont run if enumerate is there #as it is not yet enumerated (causing an error when it loads the class that will have the #enumeration in it). This can lead it to being impossible to commit clean code. # # example usage one: only create the record class if it currently exists in the database # if ApplicationRecord.has_run_migration?('UserImageRelationsTwo') # class UserImageRelation < ApplicationRecord # belongs_to :imageable, polymorphic: true # belongs_to :image # end # else # class UserImageRelation; end # end # example usage two: only load relation if it exists in the database # class UserImageRelation < ApplicationRecord # if ApplicationRecord.has_run_migration?('UserImageRelationsTwo') # belongs_to :imageable, polymorphic: true # end # end # #current version of migrations cv = ActiveRecord::Base.connection.migration_context.current_version #find the migration object for the name migration = ActiveRecord::Base.connection.migration_context.migrations.filter!{|a| a.name == nm }.first #if the migration object is nil, it has not yet been created if migration.nil? Rails.logger.info "No migration found for #{nm}. The migration has not yet been created, or is foreign to this database." return false end #get the version number for the migration name needed_version = migration.version #if current version is above or equal, the migration has allready been run migration_ran = (cv >= needed_version) if migration_ran Rails.logger.info "#{nm} migration was run on #{needed_version}. If old and all instances are migrated, consider removing code check." else Rails.logger.info "#{nm} migration has not run yet. This may lead to limited functionality" end return migration_ran end |
#instaload(sql, table_name: nil, relied_on: false, dont_return: false, base_name: nil, base_on: nil, attach_on: nil, one_to_one: false, as: nil, with: nil) ⇒ Object
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 |
# File 'lib/dynamic-records-meritfront.rb', line 622 def instaload(sql, table_name: nil, relied_on: false, dont_return: false, base_name: nil, base_on: nil, attach_on: nil, one_to_one: false, as: nil, with: nil) #this function just makes everything a little easier to deal with by providing defaults, making it nicer to call, and converting potential symbols to strings. #At the end of the day it just returns a hash with the settings in it though. So dont overthink it too much. as = as.to_s if as base_name = base_name.to_s if base_name if table_name table_name = table_name.to_s else table_name = "_" + self.to_s.underscore.downcase.pluralize end klass = self.to_s sql = "\t" + sql.strip raise StandardError.new("base_on needs to be nil or a Proc") unless base_on.nil? or base_on.kind_of? Proc raise StandardError.new("attach_on needs to be nil or a Proc") unless attach_on.nil? or attach_on.kind_of? Proc return { table_name: table_name, klass: klass, sql: sql, relied_on: relied_on, dont_return: dont_return, base_name: base_name, base_on: base_on, attach_on: attach_on, one_to_one: one_to_one, as: as, with: with } end |
#instaload_sql(*args) ⇒ Object Also known as: swiss_instaload_sql, dynamic_instaload_sql
name, insta_array, opts = { })
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
# File 'lib/dynamic-records-meritfront.rb', line 644 def instaload_sql(*args) #name, insta_array, opts = { }) args << {} unless args[-1].kind_of? Hash if args.length == 3 name, insta_array, opts = args elsif args.length == 2 insta_array, opts = args name = nil else raise StandardError.new("bad input to DynamicRecordsMeritfront#instaload_sql method.") end with_statements = insta_array.select{|a| a[:relied_on] or a[:with]} sql = %Q{ #{ _dynamic_instaload_handle_with_statements(with_statements) if with_statements.any? } #{ _dynamic_instaload_union(insta_array)} } insta_array = insta_array.select{|ar| not ar[:dont_return]} ret_hash = insta_array.map{|ar| [ar[:table_name].to_s, []]}.to_h opts[:raw] = true #annoying bug s = self unless s.abstract_class? s = s.superclass end s.dynamic_sql(name, sql, opts).rows.each{|row| #need to pre-parsed as it has a non-normal output. table_name = row[2] klass = row[1].constantize json = row[0] parsed = JSON.parse(json) ret_hash[table_name].push dynamic_init(klass, parsed) } insta_array.each{|a| a.delete(:sql)} #formatting options for insta in insta_array if insta[:base_name] #in this case, 'as' is meant as to what pseudonym to dynamicly attach it as #we are attaching to the base table. Variable could of been less confusing. My bad. dynamic_attach(ret_hash, insta[:base_name], insta[:table_name], base_on: insta[:base_on], attach_on: insta[:attach_on], one_to_one: insta[:one_to_one], as: insta[:as]) elsif insta[:as] Rails.logger.debug "#{insta[:table_name]} as #{insta[:as]}" #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 # table_name) if ret_hash[insta[:as]] ret_hash[insta[:as]] += ret_hash[insta[:table_name]] else ret_hash[insta[:as]] = ret_hash[insta[:table_name]].dup #only top level dup end else Rails.logger.debug "#{insta[:table_name]}" end end return ret_hash end |
#list_associations ⇒ Object
365 366 367 368 |
# File 'lib/dynamic-records-meritfront.rb', line 365 def list_associations #lists associations (see has_association? below) reflect_on_all_associations.map(&:name) end |
#locate_hgid(hgid_string, with_associations: nil, returns_nil: false) ⇒ Object
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 |
# File 'lib/dynamic-records-meritfront.rb', line 398 def locate_hgid(hgid_string, with_associations: nil, returns_nil: false) if hgid_string == nil or hgid_string.class != String if returns_nil return nil else raise StandardError.new("non-string class passed to DynamicRecordsMeritfront#locate_hgid as the hgid_string variable") end end if PROJECT_NAME == 'midflip' #should be fine to take out in a month or so, just got lazy and pretty sure I am the only one using this gem. #dont want to kill me jobs. hgid_string = hgid_string.gsub('ApplicationRecord', 'Record') end if hgid_string.include?('@') hgid_string = hgid_string.split('@') hgid_string.pop hgid_string = hgid_string.join('@') # incase the model was a tag that was tagged. (few months later: Wtf? Guess ill keep it) end #split the thing splitz = hgid_string.split('/') #get the class begin cls = splitz[-2].constantize rescue NameError, NoMethodError if returns_nil nil else raise StandardError.new 'Unusual or unavailable string or hgid' end end #get the hash hash = splitz[-1] # if self == ApplicationRecord (for instance), then check that cls is a subclass # if self is not ApplicationRecord, then check cls == this objects class # if with_associations defined, make sure that the class has the associations given (see has_association above) if ((self.abstract_class? and cls < self) or ( (not self.abstract_class?) and cls == self )) and ( with_associations == nil or cls.has_association?(with_associations) ) #if all is as expected, return the object with its id. if block_given? yield(hash) else cls.hfind(hash) end elsif returns_nil #allows us to handle issues with input nil else #stops execution as default raise StandardError.new 'Not the expected class or subclass.' end end |
#string_as_selector(str, attribute: 'id') ⇒ Object
393 394 395 396 397 |
# File 'lib/dynamic-records-meritfront.rb', line 393 def string_as_selector(str, attribute: 'id') #this is needed to allow us to quey various strange characters in the id etc. (see hgids) #also useful for querying various attributes return "*[#{attribute}=\"#{str}\"]" end |
#test_drmf(model_with_an_id_column_and_timestamps) ⇒ Object
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 |
# File 'lib/dynamic-records-meritfront.rb', line 707 def test_drmf() m = ar = m.superclass mtname = m.table_name transaction do puts 'test recieving columns not normally in the record.' rec = m.dynamic_sql(%Q{ SELECT id, 5 AS random_column from #{mtname} LIMIT 10 }).first raise StandardError.new('no id') unless rec.id raise StandardError.new('no dynamic column') unless rec.random_column puts 'pass 1' puts 'test raw off with a custom name' recs = ar.dynamic_sql('test_2', %Q{ SELECT id, 5 AS random_column from #{mtname} LIMIT 10 }, raw: false) raise StandardError.new('not array of hashes') unless recs.first.class == Hash and recs.class == Array rec = recs.first raise StandardError.new('no id [raw off]') unless rec['id'] raise StandardError.new('no dynamic column [raw off]') unless rec['random_column'] puts 'pass 2' puts 'test raw on' recs = ar.dynamic_sql('test_3', %Q{ SELECT id, 5 AS random_column from #{mtname} LIMIT 10 }, raw: true) raise StandardError.new('not raw') unless recs.class == ActiveRecord::Result rec = recs.first raise StandardError.new('no id [raw]') unless rec['id'] raise StandardError.new('no dynamic column [raw]') unless rec['random_column'] puts 'pass 3' puts 'test when some of the variables are diffrent then the same (#see version 3.0.1 notes)' x = Proc.new { |a, b| recs = ar.dynamic_sql('test_4', %Q{ SELECT id, 5 AS random_column from #{mtname} WHERE id > :a LIMIT :b }, a: a, b: b) } x.call(1, 2) x.call(1, 1) puts 'pass 4' puts 'test MultiAttributeArrays, including symbols and duplicate values.' time = DateTime.now ids = m.limit(5).pluck(:id) values = ids.map{|id| [id, :time, time] } ar.dynamic_sql(%Q{ INSERT INTO #{mtname} (id, created_at, updated_at) VALUES :values ON CONFLICT (id) DO NOTHING }, values: values, time: time) puts 'pass 5' puts 'test arrays' recs = ar.dynamic_sql(%Q{ SELECT id from #{mtname} where id = ANY(:idz) }, idz: ids, raw: false) puts recs raise StandardError.new('wrong length') if recs.length != 5 puts 'pass 6' puts 'test instaload_sql' out = ar.instaload_sql([ ar.instaload("SELECT id FROM users", relied_on: true, dont_return: true, table_name: "users_2"), ar.instaload("SELECT id FROM users_2 WHERE id % 2 != 0 LIMIT :limit", table_name: 'a'), m.instaload("SELECT id FROM users_2 WHERE id % 2 != 1 LIMIT :limit", table_name: 'b') ], limit: 2) puts out raise StandardError.new('Bad return') if out["users_2"] raise StandardError.new('Bad return') unless out["a"] raise StandardError.new('Bad return') unless out["b"] puts 'pass 7' puts "test dynamic_sql V3.0.6 error to do with multi_attribute_arrays which is hard to describe" time = DateTime.now values = [[1, :time, :time], [2, :time, :time]] out = ar.dynamic_sql(%Q{ insert into #{mtname} (id, created_at, updated_at) values :values on conflict (id) do update set updated_at = :time }, time: time, values: values) puts 'pass 8' raise ActiveRecord::Rollback #ApplicationRecord.dynamic_sql("SELECT * FROM") end end |
#zip_ar_result(x) ⇒ Object
967 968 969 |
# File 'lib/dynamic-records-meritfront.rb', line 967 def zip_ar_result(x) x.to_a end |