seaquel 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f51aa6cb26dbabeed5e62e1544877377b44090bc
4
+ data.tar.gz: 982a28e72454c041dd21129416c7def66b95ff32
5
+ SHA512:
6
+ metadata.gz: d50b0346f4288a0974d2b0364b3f6596cde261fbcb126662a3aaf9f92fcd5c0255d688c5707afcf2b0d6d4639861427172aac652c20ed5347667175904c97290
7
+ data.tar.gz: cb41ddc3e7e14f77ab0f0774660fc66a414c5c6c4a4f02e7d42ad205a5ac1a5c6e32d08f48a88ea2c2a8189d6eaa1e9e12d338365a11ed6870791962ac1cef2f
@@ -0,0 +1,5 @@
1
+
2
+ # SELECT
3
+
4
+ SELECT * FROM table WHERE 1=2
5
+ SELECT 1, 2, 3
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+
2
+ Copyright (c) 2015 Kaspar Schiess
3
+
4
+ Permission is hereby granted, free of charge, to any person
5
+ obtaining a copy of this software and associated documentation
6
+ files (the "Software"), to deal in the Software without
7
+ restriction, including without limitation the rights to use,
8
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the
10
+ Software is furnished to do so, subject to the following
11
+ conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
+ OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,25 @@
1
+ A simple SQL generation DSL.
2
+
3
+ SYNOPSIS
4
+
5
+ include Seaquel
6
+ select.from(table('foobar')).where(column('name').equal('baz')).to_sql
7
+ # => %Q(SELECT * FROM "foobar" WHERE "name"='baz')
8
+
9
+ DESCRIPTION
10
+
11
+ Allows generating SQL from a Ruby DSL. Geared towards the rich possibilities of
12
+ PostgreSQL, this library can generate standard SQL as well.
13
+
14
+ Please also have a look at flounder, Seaquels friendly companion - located one
15
+ layer higher up our SQL stack, it automates much of the work you'll be doing
16
+ when you use Seaquel.
17
+
18
+ STATUS
19
+
20
+ Early alpha
21
+
22
+ WHY
23
+
24
+ Because nothing really worked at the time we wrote this. Really. We looked.
25
+
@@ -0,0 +1,13 @@
1
+
2
+ module Seaquel
3
+ end
4
+
5
+ require 'seaquel/quoter'
6
+ require 'seaquel/ast'
7
+
8
+ require 'seaquel/statement'
9
+ require 'seaquel/statement_gatherer'
10
+ require 'seaquel/generator'
11
+
12
+ require 'seaquel/module'
13
+
@@ -0,0 +1,19 @@
1
+
2
+ module Seaquel::AST
3
+ end
4
+
5
+ require 'seaquel/ast/node'
6
+ require 'seaquel/ast/bin_op'
7
+ require 'seaquel/ast/join_op'
8
+ require 'seaquel/ast/assign'
9
+ require 'seaquel/ast/alias'
10
+ require 'seaquel/ast/list'
11
+ require 'seaquel/ast/column_list'
12
+ require 'seaquel/ast/column'
13
+ require 'seaquel/ast/table'
14
+ require 'seaquel/ast/literal'
15
+ require 'seaquel/ast/immediate'
16
+ require 'seaquel/ast/binding'
17
+ require 'seaquel/ast/funcall'
18
+ require 'seaquel/ast/table_alias'
19
+ require 'seaquel/ast/order'
@@ -0,0 +1,15 @@
1
+
2
+ module Seaquel::AST
3
+ class Alias
4
+ attr_reader :name, :expression
5
+
6
+ def initialize name, expression
7
+ @name = name
8
+ @expression = expression
9
+ end
10
+
11
+ def visit visitor
12
+ visitor.visit_alias(name, expression)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ module Seaquel::AST
2
+ # Assignment of right to left.
3
+ # This class can be visited.
4
+ #
5
+ class Assign
6
+ attr_reader :left, :right
7
+
8
+ def initialize left, right
9
+ @left, @right = left, right
10
+ end
11
+
12
+ def visit visitor
13
+ visitor.visit_assign(left, right)
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,21 @@
1
+
2
+ module Seaquel::AST
3
+ # A binary statement as in left=right.
4
+ # This class can be visited.
5
+ #
6
+ class BinOp
7
+ attr_reader :op, :left, :right
8
+
9
+ def initialize op, left, right
10
+ @op, @left, @right = op, left, right
11
+ end
12
+
13
+ def visit visitor
14
+ visitor.visit_binop(op, left, right)
15
+ end
16
+
17
+ def inspect
18
+ "(" + ['bin_op', op.inspect, left.inspect, right.inspect].join(' ') + ")"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+
2
+ require_relative 'expression'
3
+
4
+ module Seaquel::AST
5
+ class Binding < Expression
6
+ attr_reader :pos
7
+
8
+ def initialize pos
9
+ @pos = pos
10
+ end
11
+
12
+ def visit visitor
13
+ visitor.visit_binding pos.to_s
14
+ end
15
+
16
+ def inspect
17
+ "(bind #{pos})"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,50 @@
1
+
2
+ require_relative 'expression'
3
+
4
+ module Seaquel::AST
5
+ class Column < Expression
6
+ attr_reader :name
7
+ attr_reader :table
8
+
9
+ def initialize name, table=nil
10
+ @name = name
11
+ @table = table
12
+ end
13
+
14
+ # Set the column to value.
15
+ #
16
+ def to value
17
+ Assign.new(self, value)
18
+ end
19
+
20
+ # Visits the column as part of sql generation.
21
+ #
22
+ def visit visitor
23
+ visitor.visit_column self
24
+ end
25
+
26
+ # Returns an SQL column reference, including the table name.
27
+ #
28
+ def as_full_reference quoter
29
+ parts = []
30
+
31
+ if table
32
+ parts << table.as_column_prefix(quoter)
33
+ end
34
+
35
+ parts << as_column_reference(quoter)
36
+
37
+ parts.join('.')
38
+ end
39
+
40
+ # Returns an SQL column reference, excluding table name.
41
+ #
42
+ def as_column_reference quoter
43
+ quoter.column(name)
44
+ end
45
+
46
+ def inspect
47
+ "(column #{name})"
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,11 @@
1
+
2
+ module Seaquel::AST
3
+ # Special case of a column list that needs to be formatted without table
4
+ # references.
5
+ #
6
+ class ColumnList < List
7
+ def visit visitor
8
+ visitor.visit_column_list(list)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,35 @@
1
+
2
+ module Seaquel::AST
3
+ # Base class for all expression-type AST nodes.
4
+ #
5
+ class Expression
6
+ def self.binop op
7
+ define_method(op) do |exp|
8
+ BinOp.new(op, self, exp)
9
+ end
10
+ end
11
+
12
+ binop :eq
13
+ binop :noteq
14
+
15
+ binop :lt
16
+ binop :lteq
17
+
18
+ binop :gt
19
+ binop :gteq
20
+
21
+ binop :is
22
+ binop :isnot
23
+
24
+ def as name
25
+ Alias.new(name, self)
26
+ end
27
+
28
+ def asc
29
+ Order.new(:asc, self)
30
+ end
31
+ def desc
32
+ Order.new(:desc, self)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,17 @@
1
+
2
+ require_relative 'expression'
3
+
4
+ module Seaquel::AST
5
+ class Funcall < Expression
6
+ attr_reader :name, :args
7
+
8
+ def initialize name, args
9
+ @name = name
10
+ @args = args
11
+ end
12
+
13
+ def visit visitor
14
+ visitor.visit_funcall(name, args)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+
2
+ require_relative 'expression'
3
+
4
+ module Seaquel::AST
5
+ class Immediate < Expression
6
+ attr_reader :val
7
+
8
+ def initialize ruby_val
9
+ @val = ruby_val
10
+ end
11
+
12
+ def visit visitor
13
+ visitor.visit_immediate val.to_s
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ module Seaquel::AST
2
+ # A binary operation that can be used to join things together, like 'AND' or
3
+ # 'OR'.
4
+ #
5
+ class JoinOp
6
+ attr_reader :op
7
+ attr_reader :elements
8
+
9
+ def initialize op, elements=[]
10
+ @op, @elements = op, elements
11
+ end
12
+
13
+ def concat element
14
+ elements << element
15
+ end
16
+
17
+ def empty?
18
+ elements.empty?
19
+ end
20
+
21
+ def visit visitor
22
+ visitor.visit_joinop(op, elements)
23
+ end
24
+
25
+ def inspect
26
+ [:join_op, op, *elements].inspect
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+
2
+ require 'forwardable'
3
+
4
+ module Seaquel::AST
5
+ class List
6
+ extend Forwardable
7
+
8
+ attr_reader :list
9
+
10
+ def initialize initial=[]
11
+ @list = initial
12
+ end
13
+
14
+ # Behaves array-like in many respects
15
+ def_delegators :@list, :empty?, :concat, :size, :<<, :map, :replace
16
+
17
+ def visit visitor
18
+ visitor.visit_list(list)
19
+ end
20
+
21
+ def inspect
22
+ '[' + list.map { |e| e.inspect }.join(', ') + ']'
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+
2
+ require_relative 'expression'
3
+
4
+ module Seaquel::AST
5
+ class Literal < Expression
6
+ attr_reader :text
7
+
8
+ def initialize text
9
+ @text = text
10
+ end
11
+
12
+ def visit visitor
13
+ visitor.visit_literal(text)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,109 @@
1
+ module Seaquel::AST
2
+ # A general purpose node containing a node type and a list of arguments.
3
+ # The node stores a link to its parent or nil if no such parent exists.
4
+ # This class can be visited.
5
+ #
6
+ class Node
7
+ attr_reader :type
8
+ attr_reader :parent
9
+ attr_reader :args
10
+
11
+ def initialize *args
12
+ if args.first.kind_of?(Symbol)
13
+ @type, *@args = args
14
+ else
15
+ @parent, @type, *@args = args
16
+ end
17
+ end
18
+
19
+ # Replaces previous projection list with this one.
20
+ #
21
+ # @param list [Array<Column>]
22
+ # @return [Node] node for chaining
23
+ #
24
+ def project *fields
25
+ node(:project, fields)
26
+ end
27
+
28
+ def from *tables
29
+ node(:from, *tables)
30
+ end
31
+
32
+ def where *exps
33
+ node(:where, JoinOp.new(:and, exps))
34
+ end
35
+
36
+ def set *assign_list
37
+ node(:set, assign_list)
38
+ end
39
+
40
+ def join *tables
41
+ node(:join, tables)
42
+ end
43
+ def on *exps
44
+ node(:on, exps)
45
+ end
46
+
47
+ def limit n
48
+ node(:limit, n)
49
+ end
50
+ def offset n
51
+ node(:offset, n)
52
+ end
53
+
54
+ # Replaces previous ORDER BY specification with this one.
55
+ #
56
+ # @param list [Array<Column>]
57
+ # @return [Node] node for chaining
58
+ #
59
+ def order_by *list
60
+ node(:order_by, list)
61
+ end
62
+
63
+ # INSERT INTO ... (FIELDS) VALUES (...)
64
+ def fields *list
65
+ node(:fields, list)
66
+ end
67
+
68
+ # Adds a values list to an INSERT statement. You have to pass all the columns
69
+ # at once; repeating this method call will create an INSERT statement that
70
+ # inserts multiple rows at once (a Postgres extension).
71
+ #
72
+ # Example:
73
+ # include Seaquel
74
+ # insert.into(table('foo')).values(immediate(1), immediate(2))
75
+ # # => INSERT INTO "foo" VALUES (1, 2)
76
+ #
77
+ # @param list [Array<AST::Expression>] values to insert
78
+ # @return [AST::Node] query you are building
79
+ #
80
+ def values *list
81
+ node(:values, list)
82
+ end
83
+
84
+ def into table
85
+ node(:into, table)
86
+ end
87
+
88
+ def node *args
89
+ self.class.new(self, *args)
90
+ end
91
+
92
+ def visit visitor
93
+ method_name = "visit_#{type}"
94
+ if visitor.respond_to?(:visit_node)
95
+ visitor.visit_node(self)
96
+ else
97
+ visitor.send(method_name, parent, *args)
98
+ end
99
+ end
100
+
101
+ def to_sql
102
+ ::Seaquel::Generator.new(self).compact_sql
103
+ end
104
+
105
+ def inspect
106
+ [type, args, parent].inspect
107
+ end
108
+ end
109
+ end