prequel 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +19 -0
- data/README.md +0 -0
- data/lib/prequel.rb +38 -0
- data/lib/prequel/composite_tuple.rb +33 -0
- data/lib/prequel/core_extensions.rb +62 -0
- data/lib/prequel/expressions.rb +12 -0
- data/lib/prequel/expressions/aliased_expression.rb +15 -0
- data/lib/prequel/expressions/column.rb +35 -0
- data/lib/prequel/expressions/derived_column.rb +24 -0
- data/lib/prequel/expressions/equal.rb +22 -0
- data/lib/prequel/expressions/expression.rb +10 -0
- data/lib/prequel/expressions/set_function.rb +24 -0
- data/lib/prequel/field.rb +10 -0
- data/lib/prequel/record.rb +50 -0
- data/lib/prequel/relations.rb +11 -0
- data/lib/prequel/relations/inner_join.rb +39 -0
- data/lib/prequel/relations/projection.rb +86 -0
- data/lib/prequel/relations/relation.rb +71 -0
- data/lib/prequel/relations/selection.rb +31 -0
- data/lib/prequel/relations/table.rb +56 -0
- data/lib/prequel/session.rb +12 -0
- data/lib/prequel/sql.rb +13 -0
- data/lib/prequel/sql/derived_query_column.rb +23 -0
- data/lib/prequel/sql/inner_joined_table_ref.rb +23 -0
- data/lib/prequel/sql/named_table_ref.rb +19 -0
- data/lib/prequel/sql/query.rb +110 -0
- data/lib/prequel/sql/query_column.rb +22 -0
- data/lib/prequel/sql/subquery.rb +25 -0
- data/lib/prequel/sql/table_ref.rb +26 -0
- data/lib/prequel/tuple.rb +64 -0
- data/lib/prequel/version.rb +3 -0
- metadata +119 -0
    
        data/LICENSE
    ADDED
    
    | @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            Copyright (C) 2011 by Nathan Sobo
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         | 
| 4 | 
            +
            of this software and associated documentation files (the "Software"), to deal
         | 
| 5 | 
            +
            in the Software without restriction, including without limitation the rights
         | 
| 6 | 
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         | 
| 7 | 
            +
            copies of the Software, and to permit persons to whom the Software is
         | 
| 8 | 
            +
            furnished to do so, subject to the following conditions:
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            The above copyright notice and this permission notice shall be included in
         | 
| 11 | 
            +
            all copies or substantial portions of the Software.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         | 
| 14 | 
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         | 
| 15 | 
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         | 
| 16 | 
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         | 
| 17 | 
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         | 
| 18 | 
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         | 
| 19 | 
            +
            THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | 
            File without changes
         | 
    
        data/lib/prequel.rb
    ADDED
    
    | @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            require 'active_support/all'
         | 
| 2 | 
            +
            require 'sequel'
         | 
| 3 | 
            +
            require 'prequel/version'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Prequel
         | 
| 6 | 
            +
              extend ActiveSupport::Autoload
         | 
| 7 | 
            +
              extend self
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def const_missing(name)
         | 
| 10 | 
            +
                if name == :DB
         | 
| 11 | 
            +
                  const_set(:DB, Sequel::DATABASES.first)
         | 
| 12 | 
            +
                else
         | 
| 13 | 
            +
                  super
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def table(name, &block)
         | 
| 18 | 
            +
                Relations::Table.new(name, &block)
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              def session
         | 
| 22 | 
            +
                Thread.current[:prequel_session] ||= Session.new
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def clear_session
         | 
| 26 | 
            +
                Thread.current[:prequel_session] = nil if Thread.current[:prequel_session]
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              require 'prequel/core_extensions'
         | 
| 30 | 
            +
              autoload :CompositeTuple
         | 
| 31 | 
            +
              autoload :Expressions
         | 
| 32 | 
            +
              autoload :Field
         | 
| 33 | 
            +
              autoload :Record
         | 
| 34 | 
            +
              autoload :Relations
         | 
| 35 | 
            +
              autoload :Session
         | 
| 36 | 
            +
              autoload :Sql
         | 
| 37 | 
            +
              autoload :Tuple
         | 
| 38 | 
            +
            end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              class CompositeTuple
         | 
| 3 | 
            +
                attr_reader :left, :right
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize(left, right)
         | 
| 6 | 
            +
                  @left, @right = left, right
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def [](name)
         | 
| 10 | 
            +
                  get_record(name) || get_field_value(name)
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def get_record(table_name)
         | 
| 14 | 
            +
                  left.get_record(table_name) || right.get_record(table_name)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def get_field_value(name)
         | 
| 18 | 
            +
                  if name =~ /(.+)__(.+)/
         | 
| 19 | 
            +
                    table_name = $1.to_sym
         | 
| 20 | 
            +
                    field_name = $2.to_sym
         | 
| 21 | 
            +
                    get_record(table_name).try(:get_field_value, field_name)
         | 
| 22 | 
            +
                  else
         | 
| 23 | 
            +
                    left.get_field_value(name) || right.get_field_value(name)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def field_values
         | 
| 28 | 
            +
                  [left.field_values, right.field_values]
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                delegate :inspect, :to => :field_values
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module HashExtensions
         | 
| 3 | 
            +
                def to_predicate
         | 
| 4 | 
            +
                  raise NotImplementedError unless size == 1
         | 
| 5 | 
            +
                  keys.first.eq(values.first)
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                Hash.send(:include, self)
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              module SymbolExtensions
         | 
| 12 | 
            +
                def as(alias_name)
         | 
| 13 | 
            +
                  "#{self}___#{alias_name}".to_sym
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def eq(other)
         | 
| 17 | 
            +
                  Expressions::Equal.new(self, other)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def count
         | 
| 21 | 
            +
                  Expressions::SetFunction.new(self, :count)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def resolve_in_relations(relations)
         | 
| 25 | 
            +
                  if self =~ /^(.+)___(.+)$/
         | 
| 26 | 
            +
                    column_name = $1.to_sym
         | 
| 27 | 
            +
                    alias_name = $2.to_sym
         | 
| 28 | 
            +
                    Expressions::AliasedExpression.new(column_name, alias_name).resolve_in_relations(relations)
         | 
| 29 | 
            +
                  else
         | 
| 30 | 
            +
                    relations.each do |relation|
         | 
| 31 | 
            +
                      if column = relation.get_column(self)
         | 
| 32 | 
            +
                        return column
         | 
| 33 | 
            +
                      end
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                    nil
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def to_sql
         | 
| 40 | 
            +
                  inspect
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                Symbol.send(:include, self)
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              module PrimitiveExtensions
         | 
| 47 | 
            +
                def resolve_in_relations(relations)
         | 
| 48 | 
            +
                  self
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def resolve_in_query(query)
         | 
| 52 | 
            +
                  query.add_literal(self)
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                Numeric.send(:include, self)
         | 
| 56 | 
            +
                String.send(:include, self)
         | 
| 57 | 
            +
                TrueClass.send(:include, self)
         | 
| 58 | 
            +
                FalseClass.send(:include, self)
         | 
| 59 | 
            +
                NilClass.send(:include, self)
         | 
| 60 | 
            +
                Time.send(:include, self)
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Expressions
         | 
| 3 | 
            +
                class AliasedExpression
         | 
| 4 | 
            +
                  attr_reader :expression, :alias_name
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(expression, alias_name)
         | 
| 7 | 
            +
                    @expression, @alias_name = expression, alias_name
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def resolve_in_relations(relations)
         | 
| 11 | 
            +
                    AliasedExpression.new(expression.resolve_in_relations(relations), alias_name)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Expressions
         | 
| 3 | 
            +
                class Column
         | 
| 4 | 
            +
                  attr_reader :table, :name, :type
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(table, name, type)
         | 
| 7 | 
            +
                    @table, @name, @type = table, name, type
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def alias_name
         | 
| 11 | 
            +
                    nil
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def eq(other)
         | 
| 15 | 
            +
                    Equal.new(self, other)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def qualified_name
         | 
| 19 | 
            +
                    "#{table.name}__#{name}".to_sym
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def expression
         | 
| 23 | 
            +
                    self
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def origin
         | 
| 27 | 
            +
                    self
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def resolve_in_query(query)
         | 
| 31 | 
            +
                    query.singular_table_refs[table].resolve_column(self)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Expressions
         | 
| 3 | 
            +
                class DerivedColumn
         | 
| 4 | 
            +
                  attr_reader :relation, :expression, :alias_name
         | 
| 5 | 
            +
                  delegate :origin, :to => :expression
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def initialize(relation, expression, alias_name)
         | 
| 8 | 
            +
                    @relation, @expression, @alias_name = relation, expression, alias_name
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def name
         | 
| 12 | 
            +
                    alias_name || expression.name
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def resolve_in_query(query)
         | 
| 16 | 
            +
                    if subquery = query.singular_table_refs[relation]
         | 
| 17 | 
            +
                      subquery.resolve_derived_column(self)
         | 
| 18 | 
            +
                    else
         | 
| 19 | 
            +
                      expression.resolve_in_query(query)
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Expressions
         | 
| 3 | 
            +
                class Equal
         | 
| 4 | 
            +
                  attr_reader :left, :right
         | 
| 5 | 
            +
                  def initialize(left, right)
         | 
| 6 | 
            +
                    @left, @right = left, right
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
                  
         | 
| 9 | 
            +
                  def resolve_in_relations(relations)
         | 
| 10 | 
            +
                    Equal.new(left.resolve_in_relations(relations), right.resolve_in_relations(relations))
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def resolve_in_query(query)
         | 
| 14 | 
            +
                    Equal.new(left.resolve_in_query(query), right.resolve_in_query(query))
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def to_sql
         | 
| 18 | 
            +
                    "#{left.to_sql} = #{right.to_sql}"
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Expressions
         | 
| 3 | 
            +
                class SetFunction < Expression
         | 
| 4 | 
            +
                  attr_reader :expression, :type
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(expression, type)
         | 
| 7 | 
            +
                    @expression, @type = expression, type
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def resolve_in_relations(relations)
         | 
| 11 | 
            +
                    SetFunction.new(expression.resolve_in_relations(relations), type)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def resolve_in_query(query)
         | 
| 15 | 
            +
                    SetFunction.new(expression.resolve_in_query(query), type)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def to_sql
         | 
| 19 | 
            +
                    "#{type}(#{expression.to_sql})"
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| 24 | 
            +
             | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              class Record < Tuple
         | 
| 3 | 
            +
                class << self
         | 
| 4 | 
            +
                  delegate :all, :result_set, :[], :to_sql, :get_column, :first, :find, :where, :join, :project, :to => :relation
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def table
         | 
| 7 | 
            +
                    relation
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def to_relation
         | 
| 11 | 
            +
                    relation
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def inherited(klass)
         | 
| 15 | 
            +
                    table_name = klass.name.demodulize.underscore.pluralize.to_sym
         | 
| 16 | 
            +
                    klass.relation = Relations::Table.new(table_name, klass)
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def def_field_accessor(name)
         | 
| 20 | 
            +
                    def_field_reader(name)
         | 
| 21 | 
            +
                    def_field_writer(name)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def def_field_writer(name)
         | 
| 25 | 
            +
                    define_method("#{name}=") do |value|
         | 
| 26 | 
            +
                      set_field_value(name, value)
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def column(name, type)
         | 
| 31 | 
            +
                    relation.def_column(name, type)
         | 
| 32 | 
            +
                    def_field_accessor(name)
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def new(field_values={})
         | 
| 36 | 
            +
                    Prequel.session[table.name][field_values[:id]] ||= super
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def table
         | 
| 41 | 
            +
                  relation
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                public :set_field_value
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def get_record(table_name)
         | 
| 47 | 
            +
                  self if table_name == table.name
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Relations
         | 
| 3 | 
            +
                class InnerJoin < Relation
         | 
| 4 | 
            +
                  attr_reader :left, :right, :predicate
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(left_operand, right_operand, predicate)
         | 
| 7 | 
            +
                    @left, @right = left_operand.to_relation, right_operand.to_relation
         | 
| 8 | 
            +
                    @predicate = resolve(predicate.to_predicate)
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def get_table(name)
         | 
| 12 | 
            +
                    left.get_table(name) || right.get_table(name)
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def columns
         | 
| 16 | 
            +
                    (left.columns + right.columns).map do |column|
         | 
| 17 | 
            +
                      derive(column)
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def visit(query)
         | 
| 22 | 
            +
                    query.table_ref = table_ref(query)
         | 
| 23 | 
            +
                    query.select_list = columns.map do |derived_column|
         | 
| 24 | 
            +
                      query.resolve_derived_column(derived_column, :qualified)
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def table_ref(query)
         | 
| 29 | 
            +
                    Sql::InnerJoinedTableRef.new(left.table_ref(query), right.singular_table_ref(query), predicate.resolve_in_query(query))
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  protected
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def operands
         | 
| 35 | 
            +
                    [left, right]
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
            end
         | 
| @@ -0,0 +1,86 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Relations
         | 
| 3 | 
            +
                class Projection < Relation
         | 
| 4 | 
            +
                  attr_reader :operand
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(operand, *symbols)
         | 
| 7 | 
            +
                    @operand = operand
         | 
| 8 | 
            +
                    assign_derived_columns(symbols)
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def get_column(name)
         | 
| 12 | 
            +
                    if name.to_s.include?("__")
         | 
| 13 | 
            +
                      super
         | 
| 14 | 
            +
                    else
         | 
| 15 | 
            +
                      derived_columns_by_name[name]
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def columns
         | 
| 20 | 
            +
                    derived_columns.values
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def visit(query)
         | 
| 24 | 
            +
                    operand.visit(query)
         | 
| 25 | 
            +
                    query.select_list = columns.map do |derived_column|
         | 
| 26 | 
            +
                      query.resolve_derived_column(derived_column)
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    if projected_table
         | 
| 30 | 
            +
                      query.tuple_builder = query.singular_table_refs[projected_table]
         | 
| 31 | 
            +
                    else
         | 
| 32 | 
            +
                      query.tuple_builder = self
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def build_tuple(field_values)
         | 
| 37 | 
            +
                    tuple_class.new(field_values)
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  def tuple_class
         | 
| 41 | 
            +
                    @tuple_class ||= Class.new(Tuple).tap do |tuple_class|
         | 
| 42 | 
            +
                      tuple_class.relation = self
         | 
| 43 | 
            +
                      columns.each do |column|
         | 
| 44 | 
            +
                        tuple_class.def_field_reader(column.name)
         | 
| 45 | 
            +
                      end
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  protected
         | 
| 50 | 
            +
                  attr_reader :projected_table
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  def assign_derived_columns(expressions)
         | 
| 53 | 
            +
                    if @projected_table = detect_projected_table(expressions)
         | 
| 54 | 
            +
                      projected_table.columns.map do |column|
         | 
| 55 | 
            +
                        derive(resolve(column.qualified_name.as(column.name)))
         | 
| 56 | 
            +
                      end
         | 
| 57 | 
            +
                    else
         | 
| 58 | 
            +
                      expressions.each do |column_name|
         | 
| 59 | 
            +
                        derive(resolve(column_name))
         | 
| 60 | 
            +
                      end
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                  def detect_projected_table(args)
         | 
| 65 | 
            +
                    return false unless args.size == 1
         | 
| 66 | 
            +
                    arg = args.first
         | 
| 67 | 
            +
                    if arg.instance_of?(Table)
         | 
| 68 | 
            +
                      table_name = arg.name
         | 
| 69 | 
            +
                    elsif arg.instance_of?(Class) && arg.respond_to?(:table)
         | 
| 70 | 
            +
                      table_name = arg.table.name
         | 
| 71 | 
            +
                    elsif arg.instance_of?(Symbol)
         | 
| 72 | 
            +
                      return false if arg =~ /__/
         | 
| 73 | 
            +
                      table_name = arg
         | 
| 74 | 
            +
                    else
         | 
| 75 | 
            +
                      return false
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                    operand.get_table(table_name)
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  def operands
         | 
| 82 | 
            +
                    [operand]
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
              end
         | 
| 86 | 
            +
            end
         | 
| @@ -0,0 +1,71 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Relations
         | 
| 3 | 
            +
                class Relation
         | 
| 4 | 
            +
                  delegate :to_sql, :result_set, :all, :first, :to => :query
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def query
         | 
| 7 | 
            +
                    Sql::Query.new(self).build
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def find(id)
         | 
| 11 | 
            +
                    where(:id => id).first
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def where(predicate)
         | 
| 15 | 
            +
                    Selection.new(self, predicate)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def join(right, predicate)
         | 
| 19 | 
            +
                    InnerJoin.new(self, right, predicate)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def project(*symbols)
         | 
| 23 | 
            +
                    Projection.new(self, *symbols)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def table_ref(query)
         | 
| 27 | 
            +
                    singular_table_ref(query)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def singular_table_ref(query)
         | 
| 31 | 
            +
                    query.add_subquery(self)
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  def to_relation
         | 
| 35 | 
            +
                    self
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def get_column(name)
         | 
| 39 | 
            +
                    resolved = resolve(name)
         | 
| 40 | 
            +
                    derive(resolved) if resolved
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  protected
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  def resolve(expression)
         | 
| 46 | 
            +
                    expression.resolve_in_relations(operands)
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  def derive(resolved_expression)
         | 
| 50 | 
            +
                    if resolved_expression.instance_of?(Expressions::AliasedExpression)
         | 
| 51 | 
            +
                      alias_name = resolved_expression.alias_name
         | 
| 52 | 
            +
                      resolved_expression = resolved_expression.expression
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                      derived_columns[resolved_expression] ||=
         | 
| 56 | 
            +
                      Expressions::DerivedColumn.new(self, resolved_expression, alias_name).tap do |derived_column|
         | 
| 57 | 
            +
                        derived_columns[resolved_expression] = derived_column
         | 
| 58 | 
            +
                        derived_columns_by_name[derived_column.name] = derived_column
         | 
| 59 | 
            +
                      end
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  def derived_columns
         | 
| 63 | 
            +
                    @derived_columns ||= {}
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  def derived_columns_by_name
         | 
| 67 | 
            +
                    @derived_columns_by_name ||= {}
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Relations
         | 
| 3 | 
            +
                class Selection < Relation
         | 
| 4 | 
            +
                  attr_reader :operand, :predicate
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(operand, predicate)
         | 
| 7 | 
            +
                    @operand = operand
         | 
| 8 | 
            +
                    @predicate = resolve(predicate.to_predicate)
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  delegate :get_table, :to => :operand
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def columns
         | 
| 14 | 
            +
                    operand.columns.map do |column|
         | 
| 15 | 
            +
                      derive(column)
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def visit(query)
         | 
| 20 | 
            +
                    operand.visit(query)
         | 
| 21 | 
            +
                    query.add_condition(predicate.resolve_in_query(query))
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  protected
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def operands
         | 
| 27 | 
            +
                    [operand]
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
            end
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Relations
         | 
| 3 | 
            +
                class Table < Relation
         | 
| 4 | 
            +
                  attr_reader :name, :columns_by_name, :tuple_class
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(name, tuple_class=nil, &block)
         | 
| 7 | 
            +
                    @name, @tuple_class = name, tuple_class
         | 
| 8 | 
            +
                    @columns_by_name = {}
         | 
| 9 | 
            +
                    TableDefinitionContext.new(self).instance_eval(&block) if block
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def def_column(name, type)
         | 
| 13 | 
            +
                    columns_by_name[name] = Expressions::Column.new(self, name, type)
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def [](col_name)
         | 
| 17 | 
            +
                    "#{name}__#{col_name}".to_sym
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def get_column(column_name)
         | 
| 21 | 
            +
                    if column_name.match(/(.+)__(.+)/)
         | 
| 22 | 
            +
                      qualifier, column_name = $1.to_sym, $2.to_sym
         | 
| 23 | 
            +
                      return nil unless qualifier == name
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
                    columns_by_name[column_name]
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def get_table(table_name)
         | 
| 29 | 
            +
                    self if name == table_name
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def columns
         | 
| 33 | 
            +
                    columns_by_name.values
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def visit(query)
         | 
| 37 | 
            +
                    query.table_ref = table_ref(query)
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  def singular_table_ref(query)
         | 
| 41 | 
            +
                    query.add_singular_table_ref(self, Sql::TableRef.new(self))
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  class TableDefinitionContext
         | 
| 45 | 
            +
                    attr_reader :table
         | 
| 46 | 
            +
                    def initialize(table)
         | 
| 47 | 
            +
                      @table = table
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    def column(name, type)
         | 
| 51 | 
            +
                      table.def_column(name, type)
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
    
        data/lib/prequel/sql.rb
    ADDED
    
    
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Sql
         | 
| 3 | 
            +
                class DerivedQueryColumn
         | 
| 4 | 
            +
                  attr_reader :subquery, :name, :expression
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(subquery, name, expression)
         | 
| 7 | 
            +
                    @subquery, @name, @expression = subquery, name, expression
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def to_sql
         | 
| 11 | 
            +
                    "#{subquery.name}.#{name}"
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def to_select_clause_sql
         | 
| 15 | 
            +
                    "#{expression.to_sql} as #{name}"
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def qualified_name
         | 
| 19 | 
            +
                    "#{subquery.name}__#{name}"
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Sql
         | 
| 3 | 
            +
                class InnerJoinedTableRef
         | 
| 4 | 
            +
                  attr_reader :left, :right, :predicate
         | 
| 5 | 
            +
                  def initialize(left, right, predicate)
         | 
| 6 | 
            +
                    @left, @right, @predicate = left, right, predicate
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def to_sql
         | 
| 10 | 
            +
                    [left.to_sql,
         | 
| 11 | 
            +
                     'inner join',
         | 
| 12 | 
            +
                     right.to_sql,
         | 
| 13 | 
            +
                     'on',
         | 
| 14 | 
            +
                     predicate.to_sql
         | 
| 15 | 
            +
                    ].join(' ')
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def build_tuple(field_values)
         | 
| 19 | 
            +
                    CompositeTuple.new(left.build_tuple(field_values), right.build_tuple(field_values))
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Sql
         | 
| 3 | 
            +
                module NamedTableRef
         | 
| 4 | 
            +
                  protected
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def extract_field_values(field_values)
         | 
| 7 | 
            +
                    {}.tap do |specific_field_values|
         | 
| 8 | 
            +
                      field_values.each do |field_name, value|
         | 
| 9 | 
            +
                        if field_name =~ /(.+?)__(.+)/
         | 
| 10 | 
            +
                          qualifier, field_name = $1.to_sym, $2.to_sym
         | 
| 11 | 
            +
                          next unless qualifier == name
         | 
| 12 | 
            +
                        end
         | 
| 13 | 
            +
                        specific_field_values[field_name] = value
         | 
| 14 | 
            +
                      end
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,110 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Sql
         | 
| 3 | 
            +
                class Query
         | 
| 4 | 
            +
                  attr_accessor :select_list
         | 
| 5 | 
            +
                  attr_reader :relation, :table_ref, :conditions, :literals, :singular_table_refs, :subquery_count, :query_columns
         | 
| 6 | 
            +
                  attr_writer :tuple_builder
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def initialize(relation)
         | 
| 9 | 
            +
                    @relation = relation
         | 
| 10 | 
            +
                    @conditions = []
         | 
| 11 | 
            +
                    @literals = {}
         | 
| 12 | 
            +
                    @singular_table_refs = { relation => self }
         | 
| 13 | 
            +
                    @subquery_count = 0
         | 
| 14 | 
            +
                    @query_columns = {}
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def all
         | 
| 18 | 
            +
                    result_set.map do |field_values|
         | 
| 19 | 
            +
                      tuple_builder.build_tuple(field_values)
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def first
         | 
| 24 | 
            +
                    r = result_set
         | 
| 25 | 
            +
                    r.empty?? nil : tuple_builder.build_tuple(r.first)
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def result_set
         | 
| 29 | 
            +
                    DB[*to_sql]
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def to_sql
         | 
| 33 | 
            +
                    [sql_string, literals]
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def build
         | 
| 37 | 
            +
                    relation.visit(self)
         | 
| 38 | 
            +
                    self
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  def table_ref=(table_ref)
         | 
| 42 | 
            +
                    raise "A table ref has already been assigned" if @table_ref
         | 
| 43 | 
            +
                    @table_ref = table_ref
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def add_condition(predicate)
         | 
| 47 | 
            +
                    conditions.push(predicate)
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  def add_literal(literal)
         | 
| 51 | 
            +
                    "v#{literals.size + 1}".to_sym.tap do |placeholder|
         | 
| 52 | 
            +
                      literals[placeholder] = literal
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  def add_singular_table_ref(relation, table_ref)
         | 
| 57 | 
            +
                    singular_table_refs[relation] = table_ref
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  def add_subquery(relation)
         | 
| 61 | 
            +
                    @subquery_count += 1
         | 
| 62 | 
            +
                    subquery = Subquery.new(self, relation, "t#{subquery_count}".to_sym)
         | 
| 63 | 
            +
                    add_singular_table_ref(relation, subquery)
         | 
| 64 | 
            +
                    subquery.build
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  def resolve_derived_column(column, qualified=false)
         | 
| 68 | 
            +
                    query_columns[column] ||= begin
         | 
| 69 | 
            +
                      resolved_expression = column.expression.resolve_in_query(self)
         | 
| 70 | 
            +
                      resolved_name = qualified ? resolved_expression.qualified_name : column.name
         | 
| 71 | 
            +
                      Sql::DerivedQueryColumn.new(self, resolved_name, resolved_expression)
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  def tuple_builder
         | 
| 76 | 
            +
                    @tuple_builder || table_ref
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  protected
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  def sql_string
         | 
| 82 | 
            +
                    ["select",
         | 
| 83 | 
            +
                      select_clause_sql,
         | 
| 84 | 
            +
                      "from",
         | 
| 85 | 
            +
                      from_clause_sql,
         | 
| 86 | 
            +
                      where_clause_sql,
         | 
| 87 | 
            +
                    ].compact.join(" ")
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  def select_clause_sql
         | 
| 91 | 
            +
                    if select_list
         | 
| 92 | 
            +
                      select_list.map {|column| column.to_select_clause_sql}.join(', ')
         | 
| 93 | 
            +
                    else
         | 
| 94 | 
            +
                      '*'
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                  def from_clause_sql
         | 
| 99 | 
            +
                    table_ref.to_sql
         | 
| 100 | 
            +
                  end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  def where_clause_sql
         | 
| 103 | 
            +
                    return nil if conditions.empty?
         | 
| 104 | 
            +
                    'where ' + conditions.map do |condition|
         | 
| 105 | 
            +
                      condition.to_sql
         | 
| 106 | 
            +
                    end.join(' and ')
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
              end
         | 
| 110 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Sql
         | 
| 3 | 
            +
                class QueryColumn
         | 
| 4 | 
            +
                  attr_reader :table_ref, :name
         | 
| 5 | 
            +
                  def initialize(table_ref, name)
         | 
| 6 | 
            +
                    @table_ref, @name = table_ref, name
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def to_sql
         | 
| 10 | 
            +
                    "#{table_ref.name}.#{name}"
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def to_select_clause_sql
         | 
| 14 | 
            +
                    to_sql
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def qualified_name
         | 
| 18 | 
            +
                    "#{table_ref.name}__#{name}"
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Sql
         | 
| 3 | 
            +
                class Subquery < Query
         | 
| 4 | 
            +
                  include NamedTableRef
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  attr_reader :parent, :relation, :name
         | 
| 7 | 
            +
                  delegate :columns, :to => :relation
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def initialize(parent, relation, name)
         | 
| 10 | 
            +
                    @parent, @name = parent, name
         | 
| 11 | 
            +
                    super(relation)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  delegate :add_literal, :add_singular_table_ref, :add_subquery, :singular_table_refs, :to => :parent
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def to_sql
         | 
| 17 | 
            +
                    ['(', sql_string, ') as ', name].join
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def build_tuple(field_values)
         | 
| 21 | 
            +
                    tuple_builder.build_tuple(extract_field_values(field_values))
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              module Sql
         | 
| 3 | 
            +
                class TableRef
         | 
| 4 | 
            +
                  include NamedTableRef
         | 
| 5 | 
            +
                  attr_reader :relation, :query_columns
         | 
| 6 | 
            +
                  delegate :name, :columns, :tuple_class, :to => :relation
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def initialize(relation)
         | 
| 9 | 
            +
                    @relation = relation
         | 
| 10 | 
            +
                    @query_columns = {}
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def to_sql
         | 
| 14 | 
            +
                    name
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def resolve_column(column)
         | 
| 18 | 
            +
                    query_columns[column] ||= Sql::QueryColumn.new(self, column.name)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def build_tuple(field_values)
         | 
| 22 | 
            +
                    tuple_class.new(extract_field_values(field_values))
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,64 @@ | |
| 1 | 
            +
            module Prequel
         | 
| 2 | 
            +
              class Tuple
         | 
| 3 | 
            +
                class_attribute :relation
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                class << self
         | 
| 6 | 
            +
                  delegate :columns, :to => :relation
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def def_field_reader(name)
         | 
| 9 | 
            +
                    define_method(name) do
         | 
| 10 | 
            +
                      get_field_value(name)
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def initialize(values = {})
         | 
| 16 | 
            +
                  initialize_fields
         | 
| 17 | 
            +
                  soft_update_fields(values)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                delegate :columns, :to => :relation
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def soft_update_fields(values)
         | 
| 23 | 
            +
                  values.each do |name, value|
         | 
| 24 | 
            +
                    set_field_value(name, value)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def get_field_value(name)
         | 
| 29 | 
            +
                  fields_by_name[name].try(:value)
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def field_values
         | 
| 33 | 
            +
                  fields_by_name.inject({}) do |h, (name, field)|
         | 
| 34 | 
            +
                    h[name] = field.value
         | 
| 35 | 
            +
                    h
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def get_record(name)
         | 
| 40 | 
            +
                  nil
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                delegate :inspect, :to => :field_values
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                protected
         | 
| 46 | 
            +
                attr_reader :fields_by_name
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def initialize_fields
         | 
| 49 | 
            +
                  @fields_by_name = {}
         | 
| 50 | 
            +
                  columns.each do |column|
         | 
| 51 | 
            +
                    fields_by_name[column.name] = Field.new(self, column)
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def set_field_value(name, value)
         | 
| 56 | 
            +
                  field = fields_by_name[name]
         | 
| 57 | 
            +
                  unless field
         | 
| 58 | 
            +
                    raise "No field found #{name.inspect}"
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                  field.value = value
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
            end
         | 
| 64 | 
            +
             | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,119 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            +
            name: prequel
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              prerelease: 
         | 
| 5 | 
            +
              version: 0.0.1
         | 
| 6 | 
            +
            platform: ruby
         | 
| 7 | 
            +
            authors: 
         | 
| 8 | 
            +
            - Nathan Sobo
         | 
| 9 | 
            +
            autorequire: 
         | 
| 10 | 
            +
            bindir: bin
         | 
| 11 | 
            +
            cert_chain: []
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            date: 2011-03-03 00:00:00 -08:00
         | 
| 14 | 
            +
            default_executable: 
         | 
| 15 | 
            +
            dependencies: 
         | 
| 16 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 17 | 
            +
              name: activesupport
         | 
| 18 | 
            +
              prerelease: false
         | 
| 19 | 
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 20 | 
            +
                none: false
         | 
| 21 | 
            +
                requirements: 
         | 
| 22 | 
            +
                - - ">="
         | 
| 23 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 24 | 
            +
                    version: 3.0.4
         | 
| 25 | 
            +
              type: :runtime
         | 
| 26 | 
            +
              version_requirements: *id001
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 28 | 
            +
              name: sequel
         | 
| 29 | 
            +
              prerelease: false
         | 
| 30 | 
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         | 
| 31 | 
            +
                none: false
         | 
| 32 | 
            +
                requirements: 
         | 
| 33 | 
            +
                - - ">="
         | 
| 34 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 35 | 
            +
                    version: 3.20.0
         | 
| 36 | 
            +
              type: :runtime
         | 
| 37 | 
            +
              version_requirements: *id002
         | 
| 38 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 39 | 
            +
              name: rspec
         | 
| 40 | 
            +
              prerelease: false
         | 
| 41 | 
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         | 
| 42 | 
            +
                none: false
         | 
| 43 | 
            +
                requirements: 
         | 
| 44 | 
            +
                - - ">="
         | 
| 45 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 46 | 
            +
                    version: "0"
         | 
| 47 | 
            +
              type: :development
         | 
| 48 | 
            +
              version_requirements: *id003
         | 
| 49 | 
            +
            description: Prequel is the database library I've always wanted.
         | 
| 50 | 
            +
            email: 
         | 
| 51 | 
            +
            - nathansobo@gmail.com
         | 
| 52 | 
            +
            executables: []
         | 
| 53 | 
            +
             | 
| 54 | 
            +
            extensions: []
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            extra_rdoc_files: []
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            files: 
         | 
| 59 | 
            +
            - lib/prequel/composite_tuple.rb
         | 
| 60 | 
            +
            - lib/prequel/core_extensions.rb
         | 
| 61 | 
            +
            - lib/prequel/expressions/aliased_expression.rb
         | 
| 62 | 
            +
            - lib/prequel/expressions/column.rb
         | 
| 63 | 
            +
            - lib/prequel/expressions/derived_column.rb
         | 
| 64 | 
            +
            - lib/prequel/expressions/equal.rb
         | 
| 65 | 
            +
            - lib/prequel/expressions/expression.rb
         | 
| 66 | 
            +
            - lib/prequel/expressions/set_function.rb
         | 
| 67 | 
            +
            - lib/prequel/expressions.rb
         | 
| 68 | 
            +
            - lib/prequel/field.rb
         | 
| 69 | 
            +
            - lib/prequel/record.rb
         | 
| 70 | 
            +
            - lib/prequel/relations/inner_join.rb
         | 
| 71 | 
            +
            - lib/prequel/relations/projection.rb
         | 
| 72 | 
            +
            - lib/prequel/relations/relation.rb
         | 
| 73 | 
            +
            - lib/prequel/relations/selection.rb
         | 
| 74 | 
            +
            - lib/prequel/relations/table.rb
         | 
| 75 | 
            +
            - lib/prequel/relations.rb
         | 
| 76 | 
            +
            - lib/prequel/session.rb
         | 
| 77 | 
            +
            - lib/prequel/sql/derived_query_column.rb
         | 
| 78 | 
            +
            - lib/prequel/sql/inner_joined_table_ref.rb
         | 
| 79 | 
            +
            - lib/prequel/sql/named_table_ref.rb
         | 
| 80 | 
            +
            - lib/prequel/sql/query.rb
         | 
| 81 | 
            +
            - lib/prequel/sql/query_column.rb
         | 
| 82 | 
            +
            - lib/prequel/sql/subquery.rb
         | 
| 83 | 
            +
            - lib/prequel/sql/table_ref.rb
         | 
| 84 | 
            +
            - lib/prequel/sql.rb
         | 
| 85 | 
            +
            - lib/prequel/tuple.rb
         | 
| 86 | 
            +
            - lib/prequel/version.rb
         | 
| 87 | 
            +
            - lib/prequel.rb
         | 
| 88 | 
            +
            - LICENSE
         | 
| 89 | 
            +
            - README.md
         | 
| 90 | 
            +
            has_rdoc: true
         | 
| 91 | 
            +
            homepage: http://github.com/nathansobo/prequel
         | 
| 92 | 
            +
            licenses: []
         | 
| 93 | 
            +
             | 
| 94 | 
            +
            post_install_message: 
         | 
| 95 | 
            +
            rdoc_options: []
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            require_paths: 
         | 
| 98 | 
            +
            - lib
         | 
| 99 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 100 | 
            +
              none: false
         | 
| 101 | 
            +
              requirements: 
         | 
| 102 | 
            +
              - - ">="
         | 
| 103 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 104 | 
            +
                  version: "0"
         | 
| 105 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 106 | 
            +
              none: false
         | 
| 107 | 
            +
              requirements: 
         | 
| 108 | 
            +
              - - ">="
         | 
| 109 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 110 | 
            +
                  version: "0"
         | 
| 111 | 
            +
            requirements: []
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            rubyforge_project: 
         | 
| 114 | 
            +
            rubygems_version: 1.5.2
         | 
| 115 | 
            +
            signing_key: 
         | 
| 116 | 
            +
            specification_version: 3
         | 
| 117 | 
            +
            summary: A ground-up relational algebraic ORM.
         | 
| 118 | 
            +
            test_files: []
         | 
| 119 | 
            +
             |