Class: FlexiRecord::BaseRecord
- Inherits:
-
AbstractRecord
- Object
- AbstractRecord
- FlexiRecord::BaseRecord
- Includes:
- MonitorMixin
- Defined in:
- lib/flexirecord.rb
Overview
A record representing a row of a database table or query result.
Direct Known Subclasses
Relationship, FlexiRecordDemo::Medium, FlexiRecordDemo::MediumEntry, FlexiRecordDemo::Movie, FlexiRecordDemo::Person
Class Method Summary collapse
-
.add_connected_references(destination_class1, column_info1, src_to_dst_attr1, dst_to_src_attr1, class1_to_class2_attr, destination_class2, column_info2, src_to_dst_attr2, dst_to_src_attr2, class2_to_class1_attr) ⇒ Object
Adds two ManyToOneReferences and connects them to form a many-to-many relation between two other record classes.
-
.add_many_to_one_reference(destination_class, *arguments) ⇒ Object
Adds a ManyToOneReference to the class (by simply creating it).
-
.add_one_to_one_reference(destination_class, *arguments) ⇒ Object
Adds an OneToOneReference to the class (by simply creating it).
-
.add_read_option(attr, symbol, value) ⇒ Object
Adds a “shortcut” for a parameter to reader and loader functions.
-
.after_select(records) ⇒ Object
This method is used on each Array of records being selected from the database via the ‘sql’ or ‘select’ method.
-
.autodetect_columns ⇒ Object
Autodetects the columns (and primary key columns) of the underlaying table, to be later retrieved by the ‘columns’ and the ‘primary_columns’ methods.
-
.columns ⇒ Object
Returns an array of columns (String’s) of the underlaying table.
-
.connection_pool ⇒ Object
Returns the connection pool being used for this class in general.
-
.connection_pool=(pool) ⇒ Object
Sets the connection pool to use for this class in general.
-
.db_execute(command_template, *command_arguments) ⇒ Object
Executes the given SQL command with optional arguments on the database being used to store objects of this class.
-
.db_query(command_template, *command_arguments) ⇒ Object
Executes the given SQL query with optional arguments on the database being used to store objects of this class.
-
.db_query1(*arguments) ⇒ Object
Executes the given SQL query with optional arguments on the database being used to store objects of this class.
-
.isolation_level ⇒ Object
Returns the isolation_level of a transaction in progress on the connection used for accessing the table of this class.
-
.loader(attr) ⇒ Object
Returns the loader function (a Proc object) for a certain attribute.
-
.lock(mode) ⇒ Object
Locks the table used to store objects of this class.
-
.prepare_read_parameters(attr, parameters) ⇒ Object
Modifies a parameter array by replacing “shortcut” symbols being defined by add_read_option.
-
.primary_columns ⇒ Object
Returns an array of columns (String’s) being part of the primary key of the underlaying table.
-
.read_option_value(attr, symbol) ⇒ Object
Returns the value of a “shortcut” for a parameter to reader and loader functions.
-
.reader(attr) ⇒ Object
Returns the reader function (a Proc object) for a certain attribute.
-
.reader_attrs ⇒ Object
Returns an array containing all attributes having a reader Proc stored in the class.
-
.schema_name ⇒ Object
Returns the database schema name of this class (or of it’s superclass, if it has no own schema name).
-
.schema_name! ⇒ Object
Returns the database schema name, even if no schema is set (in this case “public” is returned).
-
.schema_name=(schema_name) ⇒ Object
Sets the database schema name for this class.
-
.select(sql_snippet = nil, *arguments) ⇒ Object
Wrapper for the ‘sql’ method including already a part of the SQL select command.
-
.select1(*arguments) ⇒ Object
Same as ‘select’, but returns only the first member of the Array, or nil.
-
.select_by_value_set(keys, set_of_values, sql_snippet = nil, *arguments) ⇒ Object
Executes an SQL query, selecting rows matching a given set of keys and values, optionally appending a given SQL snippet with parameters.
-
.set_loader(attr, &loader) ⇒ Object
Sets a given block to be the “loader function” for a particular attribute.
-
.set_reader(attr, &reader) ⇒ Object
Sets a given block to be the “reader function” for a particlular attribute.
-
.set_setter(attr, &setter) ⇒ Object
Sets a given block to be the “setter function” for a particular attribute.
-
.setter(attr) ⇒ Object
Returns the setter function (a Proc object) for a certain attribute.
-
.sql(command_template, *command_arguments) ⇒ Object
Executes the given SQL query with optional arguments on the database being used to store objects of this class.
-
.sql1(*arguments) ⇒ Object
Executes the given SQL query with optional arguments on the database being used to store objects of this class.
-
.table ⇒ Object
Returns an SQL snippet including the quoted schema and table name.
-
.table_name ⇒ Object
Returns the table name of this class (or of it’s superclass, if it has no own table name).
-
.table_name! ⇒ Object
Returns the table name, or raises an error, if no name is found.
-
.table_name=(table_name) ⇒ Object
Sets the database table name for this class.
-
.thread_connection_pool ⇒ Object
Returns the ConnectionPool being used for the current thread, if an explicit pool was set for the current thread.
-
.thread_connection_pool=(pool) ⇒ Object
Sets the ConnectionPool to use for this class in the current thread.
-
.transaction(*arguments) ⇒ Object
Wraps the given block in a transaction of the database being used to store objects of this class.
-
.transaction? ⇒ Boolean
Returns true, if a transaction is in progress on the connection used for accessing the table of this class.
-
.use_connection ⇒ Object
Calls the given block with a Connection object to the database being used to store objects of this class.
Instance Method Summary collapse
-
#[](*key) ⇒ Object
Reads a value (whose key can consist of multiple fields) from the internal cache.
-
#[]=(*arguments) ⇒ Object
Writes a value to the internal cache.
-
#delete_from_cache(*key) ⇒ Object
Deletes an entry from the internal cache, and returns it’s value.
-
#destroy ⇒ Object
Destroys the record in the database, by executing a DELETE command.
-
#dup ⇒ Object
Duplicates a record, including it’s internal state.
-
#has_key?(*key) ⇒ Boolean
Returns true, if the internal cache has stored the specified entry, otherwise false.
-
#inspect ⇒ Object
Returns a string representation of the record for debugging purposes.
-
#method_missing(method_symbol, *arguments) ⇒ Object
Provides easy access to the fields of the record.
-
#read(attr, *arguments) ⇒ Object
Reads an attribute.
-
#reload ⇒ Object
Reloads the record from the database.
-
#replace(backup) ⇒ Object
Replaces the internal state with the state of a backup.
-
#save ⇒ Object
Saves the record in the database, either by INSERT’ing or UPDATE’ing it.
-
#saved? ⇒ Boolean
Returns true, if the record has been saved in database once, otherwise false.
-
#set(attr, value) ⇒ Object
Sets an attribute.
-
#to_s ⇒ Object
Alias for the inspect method.
-
#transaction(*arguments, &block) ⇒ Object
Wraps the given block in a transaction of the database being used to store the object.
-
#update(data) ⇒ Object
Rewrites several attributes given by the keys and values in the ‘data’ hash.
-
#used_columns ⇒ Object
Returns an array of strings of the columns in the backend database, which have either values in the internal cache, or which have a dynamic reader function.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method_symbol, *arguments) ⇒ Object
Provides easy access to the fields of the record.
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 |
# File 'lib/flexirecord.rb', line 1018 def method_missing(method_symbol, *arguments) synchronize do attr = method_symbol.to_s if attr[-1, 1] == '=' attr = attr[0, attr.length-1] mode = :write value = arguments.pop else mode = :read end reader = self.class.reader(attr) loader = self.class.loader(attr) table_column_existent = self.class.columns.include?(attr) if mode == :write data_hash_key = [attr] + arguments setter = self.class.setter(attr) if setter setter.call(self, value) return nil elsif @data_hash.has_key?(data_hash_key) or reader or loader or table_column_existent @data_hash[data_hash_key] = value return nil end elsif mode == :read self.class.prepare_read_parameters(attr, arguments) data_hash_key = [attr] + arguments if reader return reader.call(self, arguments) elsif @data_hash.has_key?(data_hash_key) return @data_hash[data_hash_key] elsif loader loader.call(FlexiRecord::RecordArray.new(self.class, [self]), arguments) unless @data_hash.has_key?(data_hash_key) puts data_hash_key.inspect raise "Record loader failed." end return @data_hash[data_hash_key] elsif table_column_existent unless arguments.empty? raise ArgumentError, "Attribute getter method does not support arguments." end return nil end end return super end end |
Class Method Details
.add_connected_references(destination_class1, column_info1, src_to_dst_attr1, dst_to_src_attr1, class1_to_class2_attr, destination_class2, column_info2, src_to_dst_attr2, dst_to_src_attr2, class2_to_class1_attr) ⇒ Object
Adds two ManyToOneReferences and connects them to form a many-to-many relation between two other record classes. Please look at the FlexiRecordDemo module to see how this works.
847 848 849 |
# File 'lib/flexirecord.rb', line 847 def add_connected_references(destination_class1, column_info1, src_to_dst_attr1, dst_to_src_attr1, class1_to_class2_attr, destination_class2, column_info2, src_to_dst_attr2, dst_to_src_attr2, class2_to_class1_attr) self.add_many_to_one_reference(destination_class1, column_info1, src_to_dst_attr1, dst_to_src_attr1).combine(self.add_many_to_one_reference(destination_class2, column_info2, src_to_dst_attr2, dst_to_src_attr2), class1_to_class2_attr, class2_to_class1_attr) end |
.add_many_to_one_reference(destination_class, *arguments) ⇒ Object
Adds a ManyToOneReference to the class (by simply creating it). The first argument is the destination class, followed by arguments being passed to Reference.new.
840 841 842 843 844 |
# File 'lib/flexirecord.rb', line 840 def add_many_to_one_reference(destination_class, *arguments) return FlexiRecord::ManyToOneReference.new( self, destination_class, *arguments ) end |
.add_one_to_one_reference(destination_class, *arguments) ⇒ Object
Adds an OneToOneReference to the class (by simply creating it). The first argument is the destination class, followed by arguments being passed to Reference.new.
833 834 835 836 837 |
# File 'lib/flexirecord.rb', line 833 def add_one_to_one_reference(destination_class, *arguments) return FlexiRecord::OneToOneReference.new( self, destination_class, *arguments ) end |
.add_read_option(attr, symbol, value) ⇒ Object
Adds a “shortcut” for a parameter to reader and loader functions.
Example: List.add_read_option :items, :by_name, ‘ORDER BY “name”’
769 770 771 772 773 774 |
# File 'lib/flexirecord.rb', line 769 def add_read_option(attr, symbol, value) unless symbol.kind_of? Symbol raise "Symbol expected as second argument to 'add_read_option'." end (@read_options ||= {})[[attr.to_s, symbol]] = value end |
.after_select(records) ⇒ Object
This method is used on each Array of records being selected from the database via the ‘sql’ or ‘select’ method. It does nothing, but can be extended to automatically preload certain fields for example.
690 691 |
# File 'lib/flexirecord.rb', line 690 def after_select(records) end |
.autodetect_columns ⇒ Object
Autodetects the columns (and primary key columns) of the underlaying table, to be later retrieved by the ‘columns’ and the ‘primary_columns’ methods.
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
# File 'lib/flexirecord.rb', line 650 def autodetect_columns columns = [] primary_columns = [] db_query('SELECT ' << '"pg_attribute"."attname", ' << '"pg_constraint"."conkey" @> ARRAY["pg_attribute"."attnum"] AS "primary" ' << 'FROM "pg_attribute" ' << 'JOIN "pg_class" ON "pg_attribute"."attrelid" = "pg_class"."oid" ' << 'JOIN "pg_namespace" ON "pg_class"."relnamespace" = "pg_namespace"."oid" ' << 'LEFT JOIN "pg_constraint" ON "pg_class"."oid" = "pg_constraint"."conrelid" ' << 'WHERE "pg_attribute"."attnum" > 0 AND "pg_attribute"."attisdropped" = FALSE ' << 'AND "pg_class"."relname" = $ ' << 'AND "pg_namespace"."nspname" = $ ' << 'AND "pg_constraint"."contype" = $ ' << 'ORDER BY "attnum"', table_name!, schema_name!, 'p').each do |attribute_record| attribute_record.attname.freeze columns << attribute_record.attname primary_columns << attribute_record.attname if attribute_record.primary end @primary_columns = primary_columns.freeze @columns = columns.freeze nil end |
.columns ⇒ Object
Returns an array of columns (String’s) of the underlaying table. The columns may be autodetected (and cached) at the first call of this method.
676 677 678 679 680 |
# File 'lib/flexirecord.rb', line 676 def columns return [].freeze if table_name.nil? autodetect_columns if @columns.nil? return @columns end |
.connection_pool ⇒ Object
Returns the connection pool being used for this class in general.
573 574 575 |
# File 'lib/flexirecord.rb', line 573 def connection_pool @connection_pool end |
.connection_pool=(pool) ⇒ Object
Sets the connection pool to use for this class in general.
568 569 570 |
# File 'lib/flexirecord.rb', line 568 def connection_pool=(pool) @connection_pool = pool end |
.db_execute(command_template, *command_arguments) ⇒ Object
Executes the given SQL command with optional arguments on the database being used to store objects of this class. Returns nil.
728 729 730 731 732 |
# File 'lib/flexirecord.rb', line 728 def db_execute(command_template, *command_arguments) use_connection do |connection| return connection.execute(command_template, *command_arguments) end end |
.db_query(command_template, *command_arguments) ⇒ Object
Executes the given SQL query with optional arguments on the database being used to store objects of this class. Returns an array of BaseRecord’s (but NOT sub-classes of BaseRecord) containing the data of all rows of the query result.
716 717 718 719 720 |
# File 'lib/flexirecord.rb', line 716 def db_query(command_template, *command_arguments) use_connection do |connection| return connection.query(command_template, *command_arguments) end end |
.db_query1(*arguments) ⇒ Object
Executes the given SQL query with optional arguments on the database being used to store objects of this class. Returns an array of BaseRecord’s (but NOT sub-classes of BaseRecord) containing the data of the first row of the query result.
723 724 725 |
# File 'lib/flexirecord.rb', line 723 def db_query1(*arguments) db_query(*arguments).first end |
.isolation_level ⇒ Object
Returns the isolation_level of a transaction in progress on the connection used for accessing the table of this class.
622 623 624 625 626 |
# File 'lib/flexirecord.rb', line 622 def isolation_level use_connection do |connection| return connection.isolation_level end end |
.loader(attr) ⇒ Object
Returns the loader function (a Proc object) for a certain attribute.
818 819 820 |
# File 'lib/flexirecord.rb', line 818 def loader(attr) (@loaders || {})[attr.to_s] or ((superclass <= FlexiRecord::BaseRecord) ? superclass.loader(attr) : nil) end |
.lock(mode) ⇒ Object
Locks the table used to store objects of this class. Calling this command only makes sense, if a transaction is in progress.
639 640 641 642 643 644 645 646 647 |
# File 'lib/flexirecord.rb', line 639 def lock(mode) if not mode.kind_of? FlexiRecord::LockMode and mode.respond_to? :to_sym mode = FlexiRecord::LockMode.by_symbol(mode) end if mode.nil? raise "Table lock mode expected" end db_execute("LOCK #{table} IN #{mode}") end |
.prepare_read_parameters(attr, parameters) ⇒ Object
Modifies a parameter array by replacing “shortcut” symbols being defined by add_read_option. Returns the parameter array.
782 783 784 785 786 787 788 789 790 791 |
# File 'lib/flexirecord.rb', line 782 def prepare_read_parameters(attr, parameters) option = parameters.first value = read_option_value(attr, option.nil? ? :default : option) if value parameters[0] = value elsif option == :default parameters.shift end return parameters end |
.primary_columns ⇒ Object
Returns an array of columns (String’s) being part of the primary key of the underlaying table. (This will be in most cases an Array with one entry.) The columns may be autodetected (and cached) at the first call of this method.
683 684 685 686 687 |
# File 'lib/flexirecord.rb', line 683 def primary_columns return [].freeze if table_name.nil? autodetect_columns if @primary_columns.nil? return @primary_columns end |
.read_option_value(attr, symbol) ⇒ Object
Returns the value of a “shortcut” for a parameter to reader and loader functions.
777 778 779 |
# File 'lib/flexirecord.rb', line 777 def read_option_value(attr, symbol) value = (@read_options || {})[[attr.to_s, symbol]] || ((superclass <= FlexiRecord::BaseRecord) ? superclass.read_option_value(attr, symbol) : nil) end |
.reader(attr) ⇒ Object
Returns the reader function (a Proc object) for a certain attribute.
799 800 801 |
# File 'lib/flexirecord.rb', line 799 def reader(attr) (@readers || {})[attr.to_s] or ((superclass <= FlexiRecord::BaseRecord) ? superclass.reader(attr) : nil) end |
.reader_attrs ⇒ Object
Returns an array containing all attributes having a reader Proc stored in the class.
804 805 806 807 808 809 810 |
# File 'lib/flexirecord.rb', line 804 def reader_attrs (@readers || {}).keys + ( (superclass <= FlexiRecord::BaseRecord) ? superclass.reader_attrs : [] ) end |
.schema_name ⇒ Object
Returns the database schema name of this class (or of it’s superclass, if it has no own schema name)
532 533 534 535 536 537 538 |
# File 'lib/flexirecord.rb', line 532 def schema_name @schema_name or ( (superclass <= FlexiRecord::BaseRecord) ? superclass.schema_name : nil ) end |
.schema_name! ⇒ Object
Returns the database schema name, even if no schema is set (in this case “public” is returned).
541 542 543 |
# File 'lib/flexirecord.rb', line 541 def schema_name! schema_name or "public".freeze end |
.schema_name=(schema_name) ⇒ Object
Sets the database schema name for this class.
522 523 524 |
# File 'lib/flexirecord.rb', line 522 def schema_name=(schema_name) @schema_name = schema_name ? schema_name.to_s.dup.freeze : nil end |
.select(sql_snippet = nil, *arguments) ⇒ Object
Wrapper for the ‘sql’ method including already a part of the SQL select command. Please see the source code to understand how this method works.
735 736 737 |
# File 'lib/flexirecord.rb', line 735 def select(sql_snippet=nil, *arguments) sql("SELECT #{FlexiRecord::DefaultTableAlias}.* FROM #{table} #{FlexiRecord::DefaultTableAlias}#{sql_snippet ? ' ' : ''}#{sql_snippet}", *arguments) end |
.select1(*arguments) ⇒ Object
Same as ‘select’, but returns only the first member of the Array, or nil.
740 741 742 |
# File 'lib/flexirecord.rb', line 740 def select1(*arguments) select(*arguments).first end |
.select_by_value_set(keys, set_of_values, sql_snippet = nil, *arguments) ⇒ Object
Executes an SQL query, selecting rows matching a given set of keys and values, optionally appending a given SQL snippet with parameters. Returns an Array of records.
745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
# File 'lib/flexirecord.rb', line 745 def select_by_value_set(keys, set_of_values, sql_snippet=nil, *arguments) flattened_values = set_of_values.to_ary.flatten if flattened_values.empty? return sql(nil) else if sql_snippet return sql( 'SELECT ' << FlexiRecord::DefaultTableAlias << '.* FROM (' << 'SELECT * FROM ' << table << ' WHERE (' << keys.collect { |key| '"' << key << '"' }.join(', ') << ') ' << 'IN (' << set_of_values.collect { |values| '(' << values.collect { |value| '$' }.join(', ') << ')' }.join(', ') << ')' << ') AS ' << FlexiRecord::DefaultTableAlias << ' ' << sql_snippet.to_s, *(flattened_values + arguments) ) else return sql( 'SELECT * FROM ' << table << ' WHERE (' << keys.collect { |key| '"' << key << '"' }.join(', ') << ') ' << 'IN (' << set_of_values.collect { |values| '(' << values.collect { |value| '$' }.join(', ') << ')' }.join(', ') << ')', *(flattened_values + arguments) ) end end end |
.set_loader(attr, &loader) ⇒ Object
Sets a given block to be the “loader function” for a particular attribute. Loader functions are invoked, when you try to read an uncached value of the given attribute of a record, or when you preload data for a whole Array of records. Two arguments are passed to the block. The first is an Array of records, whose data is to be loaded, the second is an Array of arguments passed to the method used for accessing the value. The block has to evaluate to an Array of records, which can be used for more than one level deep preloads.
813 814 815 |
# File 'lib/flexirecord.rb', line 813 def set_loader(attr, &loader) (@loaders ||= {})[attr.to_s] = loader end |
.set_reader(attr, &reader) ⇒ Object
Sets a given block to be the “reader function” for a particlular attribute. A reader function is invoked, when you try to read a value of the given attribute of a record. Two arguments are passed to the block. The first is the record, whose data is to be read, the second is an Array of arguments passed to the method used for reading the value. The block has to evaluate to the value which should be read.
794 795 796 |
# File 'lib/flexirecord.rb', line 794 def set_reader(attr, &reader) (@readers ||= {})[attr.to_s] = reader end |
.set_setter(attr, &setter) ⇒ Object
Sets a given block to be the “setter function” for a particular attribute. The setter function is invoked, when you set the value of the given attribute of a record. Two arguments are passed to the block. The first is the record, whose data is to be changed, the second is the new value to be written into the field.
823 824 825 |
# File 'lib/flexirecord.rb', line 823 def set_setter(attr, &setter) (@setters ||= {})[attr.to_s] = setter end |
.setter(attr) ⇒ Object
Returns the setter function (a Proc object) for a certain attribute.
828 829 830 |
# File 'lib/flexirecord.rb', line 828 def setter(attr) (@setters || {})[attr.to_s] or ((superclass <= FlexiRecord::BaseRecord) ? superclass.setter(attr) : nil) end |
.sql(command_template, *command_arguments) ⇒ Object
Executes the given SQL query with optional arguments on the database being used to store objects of this class. Returns an array of objects of the class this method is used on (containing the data of all rows of the query result).
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 |
# File 'lib/flexirecord.rb', line 694 def sql(command_template, *command_arguments) records = nil if command_template transaction(:unless_open, :serializable) do use_connection do |connection| records = connection.record_query(self, command_template, *command_arguments) end after_select(records) end else records = FlexiRecord::RecordArray.new(self) after_select(records) end return records end |
.sql1(*arguments) ⇒ Object
Executes the given SQL query with optional arguments on the database being used to store objects of this class. Returns a single object of the class this method is used on (containing the data of the first row of the query result.)
711 712 713 |
# File 'lib/flexirecord.rb', line 711 def sql1(*arguments) sql(*arguments).first end |
.table ⇒ Object
Returns an SQL snippet including the quoted schema and table name.
561 562 563 564 565 |
# File 'lib/flexirecord.rb', line 561 def table schema_name ? %Q("#{schema_name}"."#{table_name!}") : %Q("#{table_name!}") end |
.table_name ⇒ Object
Returns the table name of this class (or of it’s superclass, if it has no own table name)
546 547 548 549 550 551 552 |
# File 'lib/flexirecord.rb', line 546 def table_name @table_name or ( (superclass <= FlexiRecord::BaseRecord) ? superclass.table_name : nil ) end |
.table_name! ⇒ Object
Returns the table name, or raises an error, if no name is found.
555 556 557 558 |
# File 'lib/flexirecord.rb', line 555 def table_name! table_name or raise "No table name set for #{self.name}." end |
.table_name=(table_name) ⇒ Object
Sets the database table name for this class. This must only be used on sub-classes of BaseRecord, and never on BaseRecord itself.
527 528 529 |
# File 'lib/flexirecord.rb', line 527 def table_name=(table_name) @table_name = table_name ? table_name.to_s.dup.freeze : nil end |
.thread_connection_pool ⇒ Object
Returns the ConnectionPool being used for the current thread, if an explicit pool was set for the current thread.
589 590 591 |
# File 'lib/flexirecord.rb', line 589 def thread_connection_pool (Thread.current[:flexirecord_thread_connection_pools] ||= {})[self] end |
.thread_connection_pool=(pool) ⇒ Object
Sets the ConnectionPool to use for this class in the current thread.
578 579 580 581 582 583 584 585 586 |
# File 'lib/flexirecord.rb', line 578 def thread_connection_pool=(pool) pool_hash = Thread.current[:flexirecord_thread_connection_pools] ||= {} if pool.nil? pool_hash.delete(self) else pool_hash[self] = pool end nil end |
.transaction(*arguments) ⇒ Object
Wraps the given block in a transaction of the database being used to store objects of this class. See FlexiRecord::Connection#transaction for details of the command.
629 630 631 632 633 634 635 636 |
# File 'lib/flexirecord.rb', line 629 def transaction(*arguments) use_connection do |connection| connection.transaction(*arguments) do return yield end end result end |
.transaction? ⇒ Boolean
Returns true, if a transaction is in progress on the connection used for accessing the table of this class.
615 616 617 618 619 |
# File 'lib/flexirecord.rb', line 615 def transaction? use_connection do |connection| return connection.transaction? end end |
.use_connection ⇒ Object
Calls the given block with a Connection object to the database being used to store objects of this class.
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 |
# File 'lib/flexirecord.rb', line 594 def use_connection pool = nil catch :found do current_class = self while current_class <= FlexiRecord::BaseRecord throw :found if pool = current_class.thread_connection_pool current_class = current_class.superclass end current_class = self while current_class <= FlexiRecord::BaseRecord throw :found if pool = current_class.connection_pool current_class = current_class.superclass end raise "No connection pool set for #{self.name}." end pool.use_connection do |connection| return yield(connection) end end |
Instance Method Details
#[](*key) ⇒ Object
Reads a value (whose key can consist of multiple fields) from the internal cache. The first argument is by convention usually a name of a column as String(!), but NOT as a Symbol.
920 921 922 923 924 |
# File 'lib/flexirecord.rb', line 920 def [](*key) synchronize do return @data_hash[key] end end |
#[]=(*arguments) ⇒ Object
Writes a value to the internal cache. The first argument is by convention usually a name of a column as String(!), but NOT as a Symbol.
927 928 929 930 931 932 933 |
# File 'lib/flexirecord.rb', line 927 def []=(*arguments) synchronize do value = arguments.pop key = arguments return @data_hash[key] = value end end |
#delete_from_cache(*key) ⇒ Object
Deletes an entry from the internal cache, and returns it’s value.
943 944 945 946 947 |
# File 'lib/flexirecord.rb', line 943 def delete_from_cache(*key) synchronize do return @data_hash.delete(key) end end |
#destroy ⇒ Object
Destroys the record in the database, by executing a DELETE command.
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 |
# File 'lib/flexirecord.rb', line 1124 def destroy if self.saved? self.class.db_execute('DELETE FROM ' << self.class.table << ' WHERE ' << (self.class.primary_columns.collect { |column| '"' << column << '" = $' }.join(' AND ')), *( self.class.primary_columns.collect { |column| @old_primary_key[column] } ) ) @saved = false end return self end |
#dup ⇒ Object
Duplicates a record, including it’s internal state.
902 903 904 905 906 907 908 |
# File 'lib/flexirecord.rb', line 902 def dup synchronize do duplicate = super duplicate.dup_internal_state return duplicate end end |
#has_key?(*key) ⇒ Boolean
Returns true, if the internal cache has stored the specified entry, otherwise false.
936 937 938 939 940 |
# File 'lib/flexirecord.rb', line 936 def has_key?(*key) synchronize do return @data_hash.has_key?(key) end end |
#inspect ⇒ Object
Returns a string representation of the record for debugging purposes.
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 |
# File 'lib/flexirecord.rb', line 991 def inspect synchronize do processed_objects = Thread.current[:flexirecord_baserecord_inspect_cycle_check] ||= {} if processed_objects[self] return "#<#{self.class}:0x#{sprintf "%08x", object_id}" else begin processed_objects[self] = true return "#<#{self.class}:0x#{sprintf "%08x", object_id} #{@saved ? 'saved' : 'unsaved'}, old_primary_key = {" << self.class.primary_columns.dup.delete_if { |column| not @old_primary_key.has_key?(column) }. collect { |column| column.inspect << '=>' << @old_primary_key[column].inspect }.join(', ') << "}, data = {" << self.class.columns.dup.delete_if { |column| not (@data_hash.has_key?([column]) or self.class.reader(column)) }. collect { |column| column.inspect << '=>' << read(column).inspect }.join(', ') << "}>" ensure processed_objects.delete(self) end end end end |
#read(attr, *arguments) ⇒ Object
Reads an attribute. If there is a dynamic reader, this reader is used, otherwise an existent assigned loader function is invoked or the internal cache will give a result. If there is no data for the attribute with the given name, then nil will be returned.
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 |
# File 'lib/flexirecord.rb', line 950 def read(attr, *arguments) attr = attr.to_s self.class.prepare_read_parameters(attr, arguments) data_hash_key = [attr] + arguments reader = self.class.reader(attr) loader = self.class.loader(attr) synchronize do if reader return reader.call(self, arguments) elsif @data_hash.has_key?(data_hash_key) return @data_hash[data_hash_key] elsif loader loader.call(FlexiRecord::RecordArray.new(self.class, [self]), arguments) unless @data_hash.has_key?(data_hash_key) raise "Record loader failed." end end return @data_hash[data_hash_key] end end |
#reload ⇒ Object
Reloads the record from the database. It can not be used on records, which have not been saved to the database yet.
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 |
# File 'lib/flexirecord.rb', line 1136 def reload synchronize do if self.class.primary_columns.empty? raise "Can not reload a record, which has no primary key." end unless self.saved? raise "Can not reload a record, which has not been saved yet." end reloaded_record = self.class.db_query1( 'SELECT * FROM ' << self.class.table << 'WHERE ' << (self.class.primary_columns.collect { |column| '"' << column << '" = $' }.join(' AND ')), *( self.class.primary_columns.collect { |column| @old_primary_key[column] } ) ) if reloaded_record.nil? raise DatabaseError, "Could not reload data." end new_data_hash = {} self.class.columns.each { |column| new_data_hash[[column]] = reloaded_record.read(column) } @data_hash = new_data_hash return self end end |
#replace(backup) ⇒ Object
Replaces the internal state with the state of a backup. This method is needed for transaction rollbacks.
911 912 913 914 915 916 917 |
# File 'lib/flexirecord.rb', line 911 def replace(backup) synchronize do raise TypeError, "Can not restore backup of objects of other classes." unless backup.class == self.class @data_hash, @saved, @old_primary_key = backup.read_internal_state return self end end |
#save ⇒ Object
Saves the record in the database, either by INSERT’ing or UPDATE’ing it.
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 |
# File 'lib/flexirecord.rb', line 1074 def save synchronize do used_columns = self.used_columns primary_key = nil if @saved if self.class.primary_columns.empty? raise "Can not re-save a record of a table without a primary key." end primary_key = self.class.db_query1( 'UPDATE ' << self.class.table << ' SET ' << (used_columns.collect { |column| '"' << column << '" = $' }.join(', ')) << ' WHERE ' << (self.class.primary_columns.collect { |column| '"' << column << '" = $' }.join(' AND ')) << ' RETURNING ' << (self.class.primary_columns.collect { |column| '"' << column << '"' }.join(', ')), *( used_columns.collect { |column| read(column) } + self.class.primary_columns.collect { |column| @old_primary_key[column] } ) ) else if used_columns.empty? primary_key = self.class.db_query1('INSERT INTO ' << self.class.table << ' DEFAULT VALUES' << (self.class.primary_columns.empty? ? '' : ( ' RETURNING ' << (self.class.primary_columns.collect { |column| '"' << column << '"' }.join(', ')) ))) else primary_key = self.class.db_query1( 'INSERT INTO ' << self.class.table << ' (' << (used_columns.collect { |column| '"' << column << '"' }.join(', ')) << ')' << ' VALUES (' << (used_columns.collect { |column| '$' }.join(', ')) << ')' << (self.class.primary_columns.empty? ? '' : ( ' RETURNING ' << (self.class.primary_columns.collect { |column| '"' << column << '"' }.join(', ')) )), *( used_columns.collect { |column| read(column) } ) ) end @saved = true end unless primary_key.nil? self.class.primary_columns.each do |column| self.set(column, primary_key.read(column)) end end copy_primary_key return self end end |
#saved? ⇒ Boolean
Returns true, if the record has been saved in database once, otherwise false.
1067 1068 1069 1070 1071 |
# File 'lib/flexirecord.rb', line 1067 def saved? synchronize do @saved end end |
#set(attr, value) ⇒ Object
Sets an attribute. If there is a dynamic setter, this setter is used, otherwise the value get’s written in the internal cache.
972 973 974 975 976 977 978 979 980 981 |
# File 'lib/flexirecord.rb', line 972 def set(attr, value) attr = attr.to_s setter = self.class.setter(attr) if setter setter.call(self, value) return @data_hash[[attr]] else return @data_hash[[attr]] = value end end |
#to_s ⇒ Object
Alias for the inspect method.
1012 1013 1014 |
# File 'lib/flexirecord.rb', line 1012 def to_s inspect end |
#transaction(*arguments, &block) ⇒ Object
Wraps the given block in a transaction of the database being used to store the object. See FlexiRecord::Connection#transaction for details of the command. This object is automatically passed to the FlexiRecord::Connection#transaction method, to rollback changes, in case an Error is raised.
1162 1163 1164 |
# File 'lib/flexirecord.rb', line 1162 def transaction(*arguments, &block) self.class.transaction(self, *arguments, &block) end |
#update(data) ⇒ Object
Rewrites several attributes given by the keys and values in the ‘data’ hash. Note: A SQL UPDATE command is not executed before ‘save’ is called, this method just updates the ruby object. Returns self.
894 895 896 897 898 899 |
# File 'lib/flexirecord.rb', line 894 def update(data) synchronize do data.each { |key, value| self.set(key, value) } return self end end |
#used_columns ⇒ Object
Returns an array of strings of the columns in the backend database, which have either values in the internal cache, or which have a dynamic reader function.
984 985 986 987 988 |
# File 'lib/flexirecord.rb', line 984 def used_columns synchronize do return self.class.columns & (self.class.reader_attrs + @data_hash.keys.reject { |key| key.length > 1 }.collect { |key| key.first }) end end |