class Ferret::Table
Attributes
name[R]
primary_key[R]
FIXME: move to the section for data model
Public Class Methods
new(name)
click to toggle source
Calls superclass method
# File lib/sql-ferret.rb, line 551 def initialize name raise 'type mismatch' unless name.is_a? String super() @name = name @fields = {} # keyed by forced-lowercase names return end
Public Instance Methods
[](name)
click to toggle source
# File lib/sql-ferret.rb, line 559 def [] name return @fields[name.downcase] end
add_field(field)
click to toggle source
- [Table#add_field]
-
is how new [[Field]]:s get added to a
- [Table]
-
as it gets parsed from a
Ferret
schema. Thus, we
check for field name duplication and primary key clashes here. This is also a convenient place to set up [[Table@primary_key]], too, as well as to check against a table having been declared with multiple primary keys.
# File lib/sql-ferret.rb, line 584 def add_field field raise 'type mismatch' unless field.is_a? Ferret::Field raise 'assertion failed' \ unless field.table.object_id == self.object_id dname = field.name.downcase ugh? table: @name do ugh 'duplicate-field', field: field.name \ if @fields.has_key? dname if field.primary_key? then if @primary_key then ugh 'primary-key-clash', key1: @primary_key.name, key2: field.name end @primary_key = field end end @fields[dname] = field return field end
columns()
click to toggle source
# File lib/sql-ferret.rb, line 567 def columns return @fields.values.select(&:column?) end
empty?()
click to toggle source
# File lib/sql-ferret.rb, line 563 def empty? return @fields.empty? end
has_columns?()
click to toggle source
# File lib/sql-ferret.rb, line 571 def has_columns? return @fields.values.any?(&:column?) end
resolve_column_names(names)
click to toggle source
# File lib/sql-ferret.rb, line 699 def resolve_column_names names results = [] names.each do |fn| raise 'type mismatch' \ unless fn.is_a? String field = @fields[fn.downcase] ugh 'unknown-field', field: fn, known_fields: @fields.values.map(&:name). join(', ') \ unless field ugh 'not-a-column', field: field.name \ unless field.column? ugh 'duplicate-field', field: field.name \ if results.include? field results.push field end return results end
sole_unique_column_among(column_names)
click to toggle source
Given a list of column names, figure out which of them is the one and only unique (or primary key) field for this table. Ugh if any of them is not a field name; if any field is mentioned multiple times; if multiple [[unique]] fields are mentioned; or if no [[unique]] fields are mentioned.
# File lib/sql-ferret.rb, line 648 def sole_unique_column_among column_names ugh? table: @name do given_columns = resolve_column_names column_names unique_column = nil given_columns.each do |column| if column.unique? then if unique_column then ugh 'unique-column-conflict', field1: unique_column.name, field2: column.name end unique_column = column end end ugh 'no-unique-column-given', fields: given_columns.map(&:name).join(', '), known_unique_fields: @fields.values.select(&:unique?). map(&:name).join(', ') \ unless unique_column return unique_column end end
sql_to_change(given_column_names)
click to toggle source
# File lib/sql-ferret.rb, line 605 def sql_to_change given_column_names key_column = sole_unique_column_among given_column_names given_columns = resolve_column_names given_column_names sql = "insert or replace into " + @name + "(" + columns.map(&:name).join(', ') + ") " ag = Ferret::Alias_Generator.new [@name, *@fields.keys] old_alias, new_alias = %w{old new}.map do |prefix| ag.available?(prefix) ? ag.reserve(prefix) : ag.create(prefix) end # Specify which field values are new and which ones are to # be retained (or initialised from defaults) sql << "select " << columns.map{|column| '%s.%s' % [ given_columns.include?(column) ? new_alias : old_alias, column.name, ]}.join(', ') # Encode the changes as a subquery sql << " from (select " << given_column_names.map{|fn| ":#{fn} as #{fn}"}.join(', ') << ")" # Left-join the subquery against the preƫxisting table sql << (" as %{new} left join %{table} as %{old} " + "on %{new}.%{key} = %{old}.%{key}") % { :old => old_alias, :new => new_alias, :key => key_column.name, :table => @name, } return sql end
sql_to_create()
click to toggle source
# File lib/sql-ferret.rb, line 718 def sql_to_create # No trailing semicolon. return "create table #{name} (\n " + @fields.values.select(&:column?). map(&:sql_to_declare).join(",\n ") + ")" end
sql_to_insert(given_column_names)
click to toggle source
# File lib/sql-ferret.rb, line 672 def sql_to_insert given_column_names ugh? table: @name do # We have to check this, lest we generate broken SQL. ugh 'inserting-null-tuple' \ if given_column_names.empty? given_columns = resolve_column_names given_column_names # Check that all the mandatory fields are given @fields.each_value do |field| next if field.optional? or field.default next if given_columns.include? field # SQLite can autopopulate the [[integer primary key]] # field. next if field.primary_key? and field.type == 'integer' ugh 'mandatory-value-missing', table: @name, column: field.name, given_columns: given_columns.map(&:name).join(' ') end return "insert into " + "#{@name}(#{given_columns.map(&:name).join ', '}) " + "values(:#{given_column_names.join ', :'})" end end