sql_tree 0.0.3 → 0.1.0

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.
@@ -0,0 +1,22 @@
1
+ module SQLTree::Node
2
+
3
+ class Assignment < Base
4
+
5
+ attr_accessor :field, :expression
6
+
7
+ def initialize(field, expression = nil)
8
+ @field, @expression = field, expression
9
+ end
10
+
11
+ def to_sql
12
+ "#{quote_var(field)} = #{expression.to_sql}"
13
+ end
14
+
15
+ def self.parse(tokens)
16
+ assignment = self.new(SQLTree::Node::Variable.parse(tokens).name)
17
+ tokens.consume(SQLTree::Token::EQ)
18
+ assignment.expression = SQLTree::Node::Expression.parse(tokens)
19
+ assignment
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ module SQLTree::Node
2
+
3
+ class DeleteQuery < Base
4
+
5
+ attr_accessor :table, :where
6
+
7
+ def initialize(table, where = nil)
8
+ @table, @where = table, where
9
+ end
10
+
11
+ def to_sql
12
+ sql = "DELETE FROM #{self.quote_var(table)}"
13
+ sql << " WHERE #{where.to_sql}" if self.where
14
+ sql
15
+ end
16
+
17
+ def self.parse(tokens)
18
+ tokens.consume(SQLTree::Token::DELETE)
19
+ tokens.consume(SQLTree::Token::FROM)
20
+ delete_query = self.new(SQLTree::Node::Variable.parse(tokens).name)
21
+ if tokens.peek == SQLTree::Token::WHERE
22
+ tokens.consume(SQLTree::Token::WHERE)
23
+ delete_query.where = SQLTree::Node::Expression.parse(tokens)
24
+ end
25
+ return delete_query
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,51 @@
1
+ module SQLTree::Node
2
+
3
+ class InsertQuery < Base
4
+
5
+ attr_accessor :table, :fields, :values
6
+
7
+ def initialize(table, fields = nil, values = [])
8
+ @table, @fields, @values = table, fields, values
9
+ end
10
+
11
+ def to_sql
12
+ sql = "INSERT INTO #{self.quote_var(table)} "
13
+ sql << '(' + fields.map { |f| f.to_sql }.join(', ') + ') ' if fields
14
+ sql << 'VALUES (' + values.map { |v| v.to_sql }.join(', ') + ')'
15
+ sql
16
+ end
17
+
18
+ def self.parse_field_list(tokens)
19
+ tokens.consume(SQLTree::Token::LPAREN)
20
+ fields = [SQLTree::Node::Variable.parse(tokens)]
21
+ while tokens.peek == SQLTree::Token::COMMA
22
+ tokens.consume(SQLTree::Token::COMMA)
23
+ fields << SQLTree::Node::Variable.parse(tokens)
24
+ end
25
+ tokens.consume(SQLTree::Token::RPAREN)
26
+ return fields
27
+ end
28
+
29
+ def self.parse_value_list(tokens)
30
+ tokens.consume(SQLTree::Token::VALUES)
31
+ tokens.consume(SQLTree::Token::LPAREN)
32
+ values = [SQLTree::Node::Expression.parse(tokens)]
33
+ while tokens.peek == SQLTree::Token::COMMA
34
+ tokens.consume(SQLTree::Token::COMMA)
35
+ values << SQLTree::Node::Expression.parse(tokens)
36
+ end
37
+ tokens.consume(SQLTree::Token::RPAREN)
38
+ return values
39
+ end
40
+
41
+ def self.parse(tokens)
42
+ tokens.consume(SQLTree::Token::INSERT)
43
+ tokens.consume(SQLTree::Token::INTO)
44
+ insert_query = self.new(SQLTree::Node::Variable.parse(tokens).name)
45
+
46
+ insert_query.fields = self.parse_field_list(tokens) if tokens.peek == SQLTree::Token::LPAREN
47
+ insert_query.values = self.parse_value_list(tokens)
48
+ return insert_query
49
+ end
50
+ end
51
+ end
@@ -13,7 +13,7 @@ module SQLTree::Node
13
13
  raise "At least one SELECT expression is required" if self.select.empty?
14
14
  sql = (self.distinct) ? "SELECT DISTINCT " : "SELECT "
15
15
  sql << select.map { |s| s.to_sql }.join(', ')
16
- sql << " FROM " << from.map { |f| f.to_sql }.join(', ')
16
+ sql << " FROM " << from.map { |f| f.to_sql }.join(', ') if from
17
17
  sql << " WHERE " << where.to_sql if where
18
18
  sql << " GROUP BY " << group_by.map { |g| g.to_sql }.join(', ') if group_by
19
19
  sql << " ORDER BY " << order_by.map { |o| o.to_sql }.join(', ') if order_by
@@ -0,0 +1,36 @@
1
+ module SQLTree::Node
2
+
3
+ class UpdateQuery < Base
4
+
5
+ attr_accessor :table, :updates, :where
6
+
7
+ def initialize(table, updates = [], where = nil)
8
+ @table, @updates, @where = table, updates, where
9
+ end
10
+
11
+ def to_sql
12
+ sql = "UPDATE #{self.quote_var(table)} SET "
13
+ sql << updates.map { |u| u.to_sql }.join(', ')
14
+ sql << " WHERE " << where.to_sql if self.where
15
+ sql
16
+ end
17
+
18
+ def self.parse(tokens)
19
+ tokens.consume(SQLTree::Token::UPDATE)
20
+ update_query = self.new(SQLTree::Node::Variable.parse(tokens).name)
21
+ tokens.consume(SQLTree::Token::SET)
22
+ update_query.updates = [SQLTree::Node::Assignment.parse(tokens)]
23
+ while tokens.peek == SQLTree::Token::COMMA
24
+ tokens.consume(SQLTree::Token::COMMA)
25
+ update_query.updates << SQLTree::Node::Assignment.parse(tokens)
26
+ end
27
+
28
+ if tokens.peek == SQLTree::Token::WHERE
29
+ tokens.consume(SQLTree::Token::WHERE)
30
+ update_query.where = SQLTree::Node::Expression.parse(tokens)
31
+ end
32
+
33
+ update_query
34
+ end
35
+ end
36
+ end
@@ -13,7 +13,7 @@ module SQLTree::Node
13
13
  end
14
14
 
15
15
  def ==(other)
16
- other.name == self.name
16
+ other.class == self.class && other.name == self.name
17
17
  end
18
18
 
19
19
  def self.parse(tokens)
@@ -57,6 +57,9 @@ class SQLTree::Parser
57
57
  def parse!
58
58
  case self.peek
59
59
  when SQLTree::Token::SELECT then SQLTree::Node::SelectQuery.parse(self)
60
+ when SQLTree::Token::INSERT then SQLTree::Node::InsertQuery.parse(self)
61
+ when SQLTree::Token::DELETE then SQLTree::Node::DeleteQuery.parse(self)
62
+ when SQLTree::Token::UPDATE then SQLTree::Node::UpdateQuery.parse(self)
60
63
  else raise UnexpectedToken.new(self.peek)
61
64
  end
62
65
  end
@@ -112,7 +112,7 @@ class SQLTree::Token
112
112
 
113
113
  # A list of all the SQL reserverd keywords.
114
114
  KEYWORDS = %w{SELECT FROM WHERE GROUP HAVING ORDER DISTINCT LEFT RIGHT INNER FULL OUTER NATURAL JOIN USING
115
- AND OR NOT AS ON IS NULL BY LIKE ILIKE BETWEEN IN ASC DESC}
115
+ AND OR NOT AS ON IS NULL BY LIKE ILIKE BETWEEN IN ASC DESC INSERT INTO VALUES DELETE UPDATE SET}
116
116
 
117
117
  # Create a token for all the reserved keywords in SQL
118
118
  KEYWORDS.each { |kw| const_set(kw, Class.new(SQLTree::Token::Keyword).new(kw)) }
@@ -2,6 +2,10 @@ require "#{File.dirname(__FILE__)}/../spec_helper"
2
2
 
3
3
  describe SQLTree, 'parsing and generating SQL' do
4
4
 
5
+ it "should parse an generate q query without FROM" do
6
+ SQLTree['SELECT 1'].to_sql.should == 'SELECT 1'
7
+ end
8
+
5
9
  it "should parse and generate SQL fo a simple list query" do
6
10
  SQLTree["SELECT * FROM table"].to_sql.should == 'SELECT * FROM "table"'
7
11
  end
@@ -38,4 +42,34 @@ describe SQLTree, 'parsing and generating SQL' do
38
42
  SQLTree['SELECT SUM( field1 ) FROM t GROUP BY field1, MD5( field2 ) HAVING SUM( field1 ) > 10'].to_sql.should ==
39
43
  'SELECT SUM("field1") FROM "t" GROUP BY "field1", MD5("field2") HAVING (SUM("field1") > 10)'
40
44
  end
45
+
46
+ it "should parse and generate an INSERT query with field list" do
47
+ SQLTree['INSERT INTO table ( field1, field2) VALUES (1, 2)'].to_sql.should ==
48
+ 'INSERT INTO "table" ("field1", "field2") VALUES (1, 2)'
49
+ end
50
+
51
+ it "should parse and generate an INSERT query without field list" do
52
+ SQLTree['INSERT INTO table VALUES (1, 2)'].to_sql.should ==
53
+ 'INSERT INTO "table" VALUES (1, 2)'
54
+ end
55
+
56
+ it "should parse and generate an DELETE query without WHERE clause" do
57
+ SQLTree['DELETE FROM table'].to_sql.should ==
58
+ 'DELETE FROM "table"'
59
+ end
60
+
61
+ it "should parse and generate an DELETE query with WHERE clause" do
62
+ SQLTree['DELETE FROM table WHERE 1 = 1'].to_sql.should ==
63
+ 'DELETE FROM "table" WHERE (1 = 1)'
64
+ end
65
+
66
+ it "should parse and generate an UPDATE query without WHERE clause" do
67
+ SQLTree['UPDATE table SET field1 = 1, field2 = 2'].to_sql.should ==
68
+ 'UPDATE "table" SET "field1" = 1, "field2" = 2'
69
+ end
70
+
71
+ it "should parse and generate an UPDATE query with WHERE clause" do
72
+ SQLTree['UPDATE table SET field1 = 123 WHERE id = 17'].to_sql.should ==
73
+ 'UPDATE "table" SET "field1" = 123 WHERE ("id" = 17)'
74
+ end
41
75
  end
@@ -0,0 +1,16 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ describe SQLTree::Node::DeleteQuery do
4
+
5
+ it "should parse a delete query without WHERE clause correctly" do
6
+ delete = SQLTree::Node::DeleteQuery["DELETE FROM table"]
7
+ delete.table.should == 'table'
8
+ delete.where.should be_nil
9
+ end
10
+
11
+ it "should parse a delete query without WHERE clause correctly" do
12
+ delete = SQLTree::Node::DeleteQuery["DELETE FROM table WHERE 1 = 1"]
13
+ delete.table.should == 'table'
14
+ delete.where.should be_kind_of(SQLTree::Node::Expression)
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ describe SQLTree::Node::InsertQuery do
4
+
5
+ it "should parse an insert query without field list correctly" do
6
+ insert = SQLTree::Node::InsertQuery["INSERT INTO table VALUES (1, 'two', 3+4, MD5('$ecret'))"]
7
+ insert.table.should == 'table'
8
+ insert.fields.should be_nil
9
+ insert.values.should have(4).items
10
+ insert.values[0].should == SQLTree::Node::Value.new(1)
11
+ insert.values[1].should == SQLTree::Node::Value.new('two')
12
+ insert.values[2].should be_kind_of(SQLTree::Node::ArithmeticExpression)
13
+ insert.values[3].should be_kind_of(SQLTree::Node::FunctionExpression)
14
+ end
15
+
16
+ it "should parse an insert query with field list" do
17
+ insert = SQLTree::Node::InsertQuery['INSERT INTO table ("field1", "field2") VALUES (1, 2)']
18
+ insert.table.should == 'table'
19
+ insert.fields.should have(2).items
20
+ insert.fields[0].should == SQLTree::Node::Variable.new('field1')
21
+ insert.fields[1].should == SQLTree::Node::Variable.new('field2')
22
+ insert.values.should have(2).items
23
+ end
24
+ end
@@ -1,5 +1,29 @@
1
1
  require "#{File.dirname(__FILE__)}/../spec_helper"
2
2
 
3
+ describe SQLTree::Node::SelectQuery do
4
+
5
+ it "should parse a query without FROM, WHERE, ORDER, GROUP or HAVING clause" do
6
+ tree = SQLTree::Node::SelectQuery['SELECT 1']
7
+ tree.select.first.expression.value.should == 1
8
+ tree.from.should be_nil
9
+ tree.where.should be_nil
10
+ tree.group_by.should be_nil
11
+ tree.having.should be_nil
12
+ tree.order_by.should be_nil
13
+ end
14
+
15
+ it "should parse a query with all clauses" do
16
+ tree = SQLTree::Node::SelectQuery['SELECT 1 AS static, field FROM table1 AS t1, table2 LEFT JOIN table3 t3 ON (t1.id = t2.id)
17
+ WHERE t1.field = 1234 GROUP BY t2.group_field HAVING SUM(t2.group_field) > 100 ORDER BY t.timestamp DESC']
18
+
19
+ tree.select.length.should == 2
20
+ tree.from.length.should == 2
21
+ tree.where.should be_kind_of(SQLTree::Node::ComparisonExpression)
22
+ tree.group_by.first.should be_kind_of(SQLTree::Node::Field)
23
+ tree.having.should be_kind_of(SQLTree::Node::ComparisonExpression)
24
+ end
25
+ end
26
+
3
27
  describe SQLTree::Node::Source do
4
28
 
5
29
  it "should parse the table name correctly" do
@@ -0,0 +1,22 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ describe SQLTree::Node::UpdateQuery do
4
+
5
+ it "should parse a delete query without WHERE clause correctly" do
6
+ update = SQLTree::Node::UpdateQuery["UPDATE table SET field1 = 1, field2 = 5 - 3"]
7
+ update.table.should == 'table'
8
+ update.updates.should have(2).items
9
+ update.updates[0].field.should == 'field1'
10
+ update.updates[0].expression.should == SQLTree::Node::Value.new(1)
11
+ update.updates[1].field.should == 'field2'
12
+ update.updates[1].expression.should be_kind_of(SQLTree::Node::ArithmeticExpression)
13
+ update.where.should be_nil
14
+ end
15
+
16
+ it "should parse a delete query without WHERE clause correctly" do
17
+ update = SQLTree::Node::UpdateQuery["UPDATE table SET field = 1 WHERE id = 17"]
18
+ update.table.should == 'table'
19
+ update.updates.should have(1).item
20
+ update.where.should be_kind_of(SQLTree::Node::Expression)
21
+ end
22
+ end
data/sql_tree.gemspec CHANGED
@@ -3,7 +3,7 @@ Gem::Specification.new do |s|
3
3
 
4
4
  # Do not modify the version and date values by hand, because this will
5
5
  # automatically by them gem release script.
6
- s.version = "0.0.3"
6
+ s.version = "0.1.0"
7
7
  s.date = "2009-10-09"
8
8
 
9
9
  s.summary = "A pure Ruby library to represent SQL queries with a syntax tree for inspection and modification."
@@ -22,6 +22,6 @@ Gem::Specification.new do |s|
22
22
 
23
23
  # Do not modify the files and test_files values by hand, because this will
24
24
  # automatically by them gem release script.
25
- s.files = %w(spec/unit/select_query_spec.rb spec/spec_helper.rb lib/sql_tree/tokenizer.rb lib/sql_tree/node/variable.rb lib/sql_tree/node/join.rb .gitignore lib/sql_tree/node/ordering.rb LICENSE spec/lib/matchers.rb spec/integration/full_queries_spec.rb lib/sql_tree/parser.rb sql_tree.gemspec spec/unit/tokenizer_spec.rb spec/unit/expression_node_spec.rb lib/sql_tree/node/select_expression.rb spec/unit/leaf_node_spec.rb lib/sql_tree/token.rb lib/sql_tree/node/table_reference.rb lib/sql_tree/node/source.rb lib/sql_tree/node/field.rb Rakefile tasks/github-gem.rake lib/sql_tree/node/select_query.rb lib/sql_tree/node.rb README.rdoc spec/integration/api_spec.rb lib/sql_tree/node/value.rb lib/sql_tree/node/expression.rb lib/sql_tree.rb)
26
- s.test_files = %w(spec/unit/select_query_spec.rb spec/integration/full_queries_spec.rb spec/unit/tokenizer_spec.rb spec/unit/expression_node_spec.rb spec/unit/leaf_node_spec.rb spec/integration/api_spec.rb)
25
+ s.files = %w(spec/unit/select_query_spec.rb spec/unit/insert_query_spec.rb spec/spec_helper.rb lib/sql_tree/tokenizer.rb lib/sql_tree/node/variable.rb lib/sql_tree/node/join.rb .gitignore lib/sql_tree/node/ordering.rb LICENSE spec/lib/matchers.rb lib/sql_tree/parser.rb sql_tree.gemspec spec/unit/tokenizer_spec.rb spec/unit/expression_node_spec.rb spec/unit/delete_query_spec.rb lib/sql_tree/node/select_expression.rb lib/sql_tree/node/assignment.rb spec/unit/leaf_node_spec.rb lib/sql_tree/token.rb lib/sql_tree/node/table_reference.rb lib/sql_tree/node/source.rb lib/sql_tree/node/insert_query.rb lib/sql_tree/node/field.rb Rakefile tasks/github-gem.rake spec/unit/update_query_spec.rb spec/integration/parse_and_generate_spec.rb lib/sql_tree/node/select_query.rb lib/sql_tree/node.rb README.rdoc spec/integration/api_spec.rb lib/sql_tree/node/value.rb lib/sql_tree/node/expression.rb lib/sql_tree/node/delete_query.rb lib/sql_tree.rb lib/sql_tree/node/update_query.rb)
26
+ s.test_files = %w(spec/unit/select_query_spec.rb spec/unit/insert_query_spec.rb spec/unit/tokenizer_spec.rb spec/unit/expression_node_spec.rb spec/unit/delete_query_spec.rb spec/unit/leaf_node_spec.rb spec/unit/update_query_spec.rb spec/integration/parse_and_generate_spec.rb spec/integration/api_spec.rb)
27
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sql_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willem van Bergen
@@ -23,6 +23,7 @@ extra_rdoc_files:
23
23
  - README.rdoc
24
24
  files:
25
25
  - spec/unit/select_query_spec.rb
26
+ - spec/unit/insert_query_spec.rb
26
27
  - spec/spec_helper.rb
27
28
  - lib/sql_tree/tokenizer.rb
28
29
  - lib/sql_tree/node/variable.rb
@@ -31,26 +32,32 @@ files:
31
32
  - lib/sql_tree/node/ordering.rb
32
33
  - LICENSE
33
34
  - spec/lib/matchers.rb
34
- - spec/integration/full_queries_spec.rb
35
35
  - lib/sql_tree/parser.rb
36
36
  - sql_tree.gemspec
37
37
  - spec/unit/tokenizer_spec.rb
38
38
  - spec/unit/expression_node_spec.rb
39
+ - spec/unit/delete_query_spec.rb
39
40
  - lib/sql_tree/node/select_expression.rb
41
+ - lib/sql_tree/node/assignment.rb
40
42
  - spec/unit/leaf_node_spec.rb
41
43
  - lib/sql_tree/token.rb
42
44
  - lib/sql_tree/node/table_reference.rb
43
45
  - lib/sql_tree/node/source.rb
46
+ - lib/sql_tree/node/insert_query.rb
44
47
  - lib/sql_tree/node/field.rb
45
48
  - Rakefile
46
49
  - tasks/github-gem.rake
50
+ - spec/unit/update_query_spec.rb
51
+ - spec/integration/parse_and_generate_spec.rb
47
52
  - lib/sql_tree/node/select_query.rb
48
53
  - lib/sql_tree/node.rb
49
54
  - README.rdoc
50
55
  - spec/integration/api_spec.rb
51
56
  - lib/sql_tree/node/value.rb
52
57
  - lib/sql_tree/node/expression.rb
58
+ - lib/sql_tree/node/delete_query.rb
53
59
  - lib/sql_tree.rb
60
+ - lib/sql_tree/node/update_query.rb
54
61
  has_rdoc: true
55
62
  homepage: http://wiki.github.com/wvanbergen/sql_tree
56
63
  licenses: []
@@ -86,8 +93,11 @@ specification_version: 3
86
93
  summary: A pure Ruby library to represent SQL queries with a syntax tree for inspection and modification.
87
94
  test_files:
88
95
  - spec/unit/select_query_spec.rb
89
- - spec/integration/full_queries_spec.rb
96
+ - spec/unit/insert_query_spec.rb
90
97
  - spec/unit/tokenizer_spec.rb
91
98
  - spec/unit/expression_node_spec.rb
99
+ - spec/unit/delete_query_spec.rb
92
100
  - spec/unit/leaf_node_spec.rb
101
+ - spec/unit/update_query_spec.rb
102
+ - spec/integration/parse_and_generate_spec.rb
93
103
  - spec/integration/api_spec.rb