Class: Ferret::Table
- Inherits:
-
Object
- Object
- Ferret::Table
- Defined in:
- lib/sql-ferret.rb
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#primary_key ⇒ Object
readonly
FIXME: move to the section for data model.
Instance Method Summary collapse
- #[](name) ⇒ Object
-
#add_field(field) ⇒ Object
- [Table#add_field]
-
is how new [[Field]]:s get added to a [[Table]] as it gets parsed from a Ferret schema.
- #columns ⇒ Object
- #empty? ⇒ Boolean
- #has_columns? ⇒ Boolean
-
#initialize(name) ⇒ Table
constructor
A new instance of Table.
- #resolve_column_names(names) ⇒ Object
-
#sole_unique_column_among(column_names) ⇒ Object
Given a list of column names, figure out which of them is the one and only unique (or primary key) field for this table.
- #sql_to_change(given_column_names) ⇒ Object
- #sql_to_create ⇒ Object
- #sql_to_insert(given_column_names) ⇒ Object
Constructor Details
#initialize(name) ⇒ Table
Returns a new instance of Table.
551 552 553 554 555 556 557 |
# 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 |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
550 551 552 |
# File 'lib/sql-ferret.rb', line 550 def name @name end |
#primary_key ⇒ Object (readonly)
FIXME: move to the section for data model
576 577 578 |
# File 'lib/sql-ferret.rb', line 576 def primary_key @primary_key end |
Instance Method Details
#[](name) ⇒ Object
559 560 561 |
# File 'lib/sql-ferret.rb', line 559 def [] name return @fields[name.downcase] end |
#add_field(field) ⇒ Object
- [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.
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
# 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 ⇒ Object
567 568 569 |
# File 'lib/sql-ferret.rb', line 567 def columns return @fields.values.select(&:column?) end |
#empty? ⇒ Boolean
563 564 565 |
# File 'lib/sql-ferret.rb', line 563 def empty? return @fields.empty? end |
#has_columns? ⇒ Boolean
571 572 573 |
# File 'lib/sql-ferret.rb', line 571 def has_columns? return @fields.values.any?(&:column?) end |
#resolve_column_names(names) ⇒ Object
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 |
# 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) ⇒ Object
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.
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 |
# 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) ⇒ Object
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
# 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 ⇒ Object
718 719 720 721 722 723 724 |
# 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) ⇒ Object
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 |
# 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 |