prequel 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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.
File without changes
@@ -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,12 @@
1
+ module Prequel
2
+ module Expressions
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :AliasedExpression
6
+ autoload :Column
7
+ autoload :DerivedColumn
8
+ autoload :Equal
9
+ autoload :Expression
10
+ autoload :SetFunction
11
+ end
12
+ 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,10 @@
1
+ module Prequel
2
+ module Expressions
3
+ class Expression
4
+ def as(alias_name)
5
+ AliasedExpression.new(self, alias_name)
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -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,10 @@
1
+ module Prequel
2
+ class Field
3
+ attr_reader :tuple, :column
4
+ attr_accessor :value
5
+
6
+ def initialize(tuple, column)
7
+ @tuple, @column = tuple, column
8
+ end
9
+ end
10
+ end
@@ -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,11 @@
1
+ module Prequel
2
+ module Relations
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :InnerJoin
6
+ autoload :Projection
7
+ autoload :Relation
8
+ autoload :Selection
9
+ autoload :Table
10
+ end
11
+ 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
@@ -0,0 +1,12 @@
1
+ module Prequel
2
+ class Session
3
+ def initialize
4
+ @identity_map = Hash.new {|h,k| h[k] = {}}
5
+ end
6
+
7
+ delegate :[], :[]=, :to => :identity_map
8
+
9
+ protected
10
+ attr_reader :identity_map
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Prequel
2
+ module Sql
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :DerivedQueryColumn
6
+ autoload :InnerJoinedTableRef
7
+ autoload :NamedTableRef
8
+ autoload :Query
9
+ autoload :QueryColumn
10
+ autoload :Subquery
11
+ autoload :TableRef
12
+ end
13
+ end
@@ -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
+
@@ -0,0 +1,3 @@
1
+ module Prequel
2
+ VERSION = "0.0.1" unless defined?(::Prequel::VERSION)
3
+ end
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
+