sqlstmt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Makani Mason, Kem Mason
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,5 @@
1
+ module SqlStmt
2
+
3
+ class Error < StandardError; end
4
+
5
+ end
@@ -0,0 +1,29 @@
1
+ require 'sqlstmt/query'
2
+
3
+ module SqlStmt
4
+
5
+ class InsertSelect < FieldValueQuery
6
+ def initialize
7
+ super
8
+ @into_table = nil
9
+ end
10
+
11
+ def into(table)
12
+ @into_table = table
13
+ self
14
+ end
15
+
16
+ private
17
+ def verify_minimum_requirements
18
+ super
19
+ raise SqlStmt::Error, "unable to build sql - must first call :into" if @into_table.nil?
20
+ end
21
+
22
+ def build_stmt
23
+ into_str = @fields.join(',')
24
+ select_str = @values.join(',')
25
+ "INSERT INTO #@into_table (#{into_str}) SELECT #{select_str} FROM #{build_table_list}#{build_where_clause}"
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,89 @@
1
+ require 'doh/core_ext/class/force_deep_copy'
2
+ require 'sqlstmt/error'
3
+ require 'sqlstmt/to_sql'
4
+
5
+ module SqlStmt
6
+
7
+ class Query
8
+ force_deep_copy :fields, :tables, :wheres
9
+
10
+ def initialize
11
+ @fields = []
12
+ @tables = []
13
+ @wheres = []
14
+ @use_wheres = true
15
+ end
16
+
17
+ def table(table)
18
+ @tables.push(table)
19
+ self
20
+ end
21
+
22
+ def where(*sql)
23
+ @wheres.concat(sql)
24
+ self
25
+ end
26
+
27
+ def no_where
28
+ @use_wheres = false
29
+ self
30
+ end
31
+
32
+ def to_s
33
+ verify_minimum_requirements
34
+ build_stmt
35
+ end
36
+
37
+ def group_by(clause)
38
+ @group_by = clause
39
+ self
40
+ end
41
+
42
+ def order_by(clause)
43
+ @order_by = clause
44
+ self
45
+ end
46
+
47
+ def limit(clause)
48
+ @limit = clause
49
+ self
50
+ end
51
+
52
+ private
53
+ def verify_minimum_requirements
54
+ raise SqlStmt::Error, "unable to build sql - must first call :field" if @fields.empty?
55
+ raise SqlStmt::Error, "unable to build sql - must first call :table" if @tables.empty?
56
+ raise SqlStmt::Error, "unable to build sql - must first call :where or :no_where" if @use_wheres && @wheres.empty?
57
+ raise SqlStmt::Error, "unable to build sql - :where and :no_where must not be called on same builder instance" if !@use_wheres && !@wheres.empty?
58
+ end
59
+
60
+ def build_table_list
61
+ @tables.join(',')
62
+ end
63
+
64
+ def build_where_clause
65
+ if @wheres.empty? then '' else " WHERE #{@wheres.join(' AND ')}" end
66
+ end
67
+ end
68
+
69
+ class FieldValueQuery < Query
70
+ force_deep_copy :values
71
+
72
+ def initialize
73
+ super
74
+ @values = []
75
+ end
76
+
77
+ def field(field, value)
78
+ raise "trying to include field #{field} again" if @fields.include?(field)
79
+ @fields.push(field)
80
+ @values.push(if value.is_a?(String) then value else value.to_sql end)
81
+ self
82
+ end
83
+
84
+ def fieldq(field, value)
85
+ field(field, value.to_sql)
86
+ end
87
+ end
88
+
89
+ end
@@ -0,0 +1,71 @@
1
+ require 'sqlstmt/query'
2
+
3
+ module SqlStmt
4
+
5
+ class Select < Query
6
+ force_deep_copy :joins
7
+
8
+ def initialize
9
+ super
10
+ @joins = []
11
+ @group_by = nil
12
+ @order_by = nil
13
+ @limit = nil
14
+ end
15
+
16
+ def field(*field_exprs)
17
+ @fields.concat(field_exprs)
18
+ self
19
+ end
20
+
21
+ def join(table, expr)
22
+ @joins.push("JOIN #{table} ON #{expr}")
23
+ self
24
+ end
25
+
26
+ def join_using(table, *fields)
27
+ @joins.push("JOIN #{table} USING (#{fields.join(',')})")
28
+ self
29
+ end
30
+
31
+ def left_join(table, expr)
32
+ @joins.push("LEFT JOIN #{table} ON #{expr}")
33
+ self
34
+ end
35
+
36
+ def left_join_using(table, *fields)
37
+ @joins.push("LEFT JOIN #{table} USING (#{fields.join(',')})")
38
+ self
39
+ end
40
+
41
+ def group_by(clause)
42
+ @group_by = clause
43
+ self
44
+ end
45
+
46
+ def order_by(clause)
47
+ @order_by = clause
48
+ self
49
+ end
50
+
51
+ def limit(clause)
52
+ @limit = clause
53
+ self
54
+ end
55
+
56
+ private
57
+ def simple_clause(keywords, value)
58
+ if value then " #{keywords} #{value}" else '' end
59
+ end
60
+
61
+ def build_stmt
62
+ select_str = @fields.join(',')
63
+ join_clause = if @joins.empty? then '' else " #{@joins.join(' ')}" end
64
+ group_clause = simple_clause('GROUP BY', @group_by)
65
+ order_clause = simple_clause('ORDER BY', @order_by)
66
+ limit_clause = simple_clause('LIMIT', @limit)
67
+ "SELECT #{select_str} FROM #{build_table_list}#{join_clause}#{build_where_clause}#{group_clause}#{order_clause}#{limit_clause}"
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,65 @@
1
+ require 'bigdecimal'
2
+ require 'date'
3
+
4
+ class String
5
+ unless method_defined?(:to_sql)
6
+ def to_sql
7
+ str = gsub('\\', '\\\\').gsub('\'', '\\\'').gsub("'", "\\'")
8
+ "'#{str}'"
9
+ end
10
+ end
11
+ end
12
+
13
+ class NilClass
14
+ def to_sql
15
+ 'NULL'
16
+ end
17
+ end
18
+
19
+ class Numeric
20
+ def to_sql
21
+ to_s
22
+ end
23
+ end
24
+
25
+ class Date
26
+ def to_sql
27
+ "'#{strftime('%Y-%m-%d')}'"
28
+ end
29
+ end
30
+
31
+ class DateTime
32
+ def to_sql
33
+ "'#{strftime('%Y-%m-%d %H:%M:%S')}'"
34
+ end
35
+ end
36
+
37
+ class Time
38
+ def to_sql
39
+ "'#{strftime('%Y-%m-%d %H:%M:%S')}'"
40
+ end
41
+ end
42
+
43
+ class TrueClass
44
+ def to_sql
45
+ '1'
46
+ end
47
+ end
48
+
49
+ class FalseClass
50
+ def to_sql
51
+ '0'
52
+ end
53
+ end
54
+
55
+ class BigDecimal
56
+ def to_sql
57
+ to_s('F')
58
+ end
59
+ end
60
+
61
+ class Array
62
+ def to_sql
63
+ '(' + collect { |elem| elem.to_sql }.join(',') + ')'
64
+ end
65
+ end
@@ -0,0 +1,20 @@
1
+ require 'sqlstmt/query'
2
+
3
+ module SqlStmt
4
+
5
+ class Update < FieldValueQuery
6
+ private
7
+ def build_set_clause
8
+ set_exprs = []
9
+ @fields.each_with_index do |field, index|
10
+ set_exprs.push("#{field} = #{@values[index]}")
11
+ end
12
+ set_exprs.join(', ')
13
+ end
14
+
15
+ def build_stmt
16
+ "UPDATE #{build_table_list} SET #{build_set_clause}#{build_where_clause}"
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,55 @@
1
+ require 'sqlstmt/insert_select'
2
+
3
+ module SqlStmt
4
+
5
+ class TC_insert_select < DohTest::TestGroup
6
+ def test_minimum_requirements
7
+ assert_raises(SqlStmt::Error) { InsertSelect.new.into('target').to_s }
8
+ assert_raises(SqlStmt::Error) { InsertSelect.new.into('target').no_where.to_s }
9
+ assert_raises(SqlStmt::Error) { InsertSelect.new.into('target').no_where.field('blah', 'blee').to_s }
10
+ end
11
+
12
+ def test_simple
13
+ assert_equal('INSERT INTO target (blah) SELECT blee FROM source', InsertSelect.new.into('target').table('source').field('blah', 'blee').no_where.to_s)
14
+ assert_equal('INSERT INTO target (blah) SELECT blee FROM source WHERE source_id = 1', InsertSelect.new.into('target').table('source').field('blah', 'blee').where('source_id = 1').to_s)
15
+ end
16
+
17
+ def test_dup
18
+ shared_builder = SqlStmt::InsertSelect.new.into('target')
19
+ first_builder = shared_builder
20
+ other_builder = shared_builder.dup
21
+
22
+ first_builder.where('status="bad"')
23
+ first_builder.field('created_at', 'NOW()')
24
+ first_builder.table('some_tbl s')
25
+
26
+ other_builder.no_where
27
+ other_builder.field('info', 'o.info')
28
+ other_builder.field('created_at', 'then')
29
+ other_builder.table('other_tbl o')
30
+
31
+ assert_equal('INSERT INTO target (created_at) SELECT NOW() FROM some_tbl s WHERE status="bad"', first_builder.to_s)
32
+ assert_equal('INSERT INTO target (info,created_at) SELECT o.info,then FROM other_tbl o', other_builder.to_s)
33
+ end
34
+
35
+ def test_complex
36
+ shared_builder = SqlStmt::InsertSelect.new.into('target')
37
+ shared_builder.table('shared_tbl')
38
+ shared_builder.field('created_at', 'NOW()').field('duration', 5).fieldq('is_bad', 'b')
39
+
40
+ first_builder = shared_builder
41
+ other_builder = shared_builder.dup
42
+
43
+ first_builder.where("status='bad'")
44
+
45
+ other_builder.table('other_tbl o')
46
+ other_builder.field('info', 'o.info')
47
+ other_builder.field('data', 'o.data')
48
+ other_builder.where('s.id=o.shared_id', "status='good'")
49
+
50
+ assert_equal("INSERT INTO target (created_at,duration,is_bad) SELECT NOW(),5,'b' FROM shared_tbl WHERE status='bad'", first_builder.to_s)
51
+ assert_equal("INSERT INTO target (created_at,duration,is_bad,info,data) SELECT NOW(),5,'b',o.info,o.data FROM shared_tbl,other_tbl o WHERE s.id=o.shared_id AND status='good'", other_builder.to_s)
52
+ end
53
+ end
54
+
55
+ end
data/test/select.dt.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'sqlstmt/select'
2
+
3
+ module SqlStmt
4
+
5
+ class Test_Select < DohTest::TestGroup
6
+ def notest_minimum_requirements
7
+ assert_raises(SqlStmt::Error) { Select.new('target').to_s }
8
+ assert_raises(SqlStmt::Error) { Select.new('target').no_where.to_s }
9
+ end
10
+
11
+ def test_stuff
12
+ assert_equal('SELECT blah FROM source', Select.new.table('source').field('blah').no_where.to_s)
13
+ assert_equal('SELECT blah FROM source WHERE source_id = 1', Select.new.table('source').field('blah').where('source_id = 1').to_s)
14
+ assert_equal('SELECT blah FROM source s', Select.new.table('source s').field('blah').no_where.to_s)
15
+ assert_equal('SELECT blah FROM source s JOIN other o ON s.blah_id = o.blah_id', Select.new.table('source s').join('other o', 's.blah_id = o.blah_id').field('blah').no_where.to_s)
16
+ assert_equal('SELECT blah FROM source s JOIN other o USING (blah_id)', Select.new.table('source s').join_using('other o', 'blah_id').field('blah').no_where.to_s)
17
+ assert_equal('SELECT blah FROM source s LEFT JOIN other o ON s.blah_id = o.blah_id', Select.new.table('source s').left_join('other o', 's.blah_id = o.blah_id').field('blah').no_where.to_s)
18
+ assert_equal('SELECT blah FROM source s LEFT JOIN other o USING (blah_id)', Select.new.table('source s').left_join_using('other o', 'blah_id').field('blah').no_where.to_s)
19
+ assert_equal('SELECT blah,blee FROM source', Select.new.table('source').field('blah','blee').no_where.to_s)
20
+ end
21
+ end
22
+
23
+ end
data/test/to_sql.dt.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'sqlstmt/to_sql'
2
+
3
+ module SqlStmt
4
+
5
+ class Test_to_sql < DohTest::TestGroup
6
+ def test_stuff
7
+ assert_equal("'blah'", 'blah'.to_sql)
8
+ assert_equal('NULL', nil.to_sql)
9
+ assert_equal('3', 3.to_sql)
10
+ assert_equal("'2008-09-24'", Date.new(2008,9,24).to_sql)
11
+ assert_equal("'2008-09-24 09:30:04'", DateTime.new(2008,9,24,9,30,4).to_sql)
12
+ assert_equal('1', true.to_sql)
13
+ assert_equal('0', false.to_sql)
14
+ assert_equal('10.0', BigDecimal.new('10').to_sql)
15
+ assert_equal("('a','b','c')", ['a', 'b', 'c'].to_sql)
16
+ end
17
+ end
18
+
19
+ end
20
+
data/test/update.dt.rb ADDED
@@ -0,0 +1,55 @@
1
+ require 'sqlstmt/update'
2
+
3
+ module SqlStmt
4
+
5
+ class TC_update < DohTest::TestGroup
6
+ def test_minimum_requirements
7
+ assert_raises(SqlStmt::Error) { Update.new.table('target').to_s }
8
+ assert_raises(SqlStmt::Error) { Update.new.table('target').no_where.to_s }
9
+ end
10
+
11
+ def test_simple
12
+ assert_equal('UPDATE target SET blah = blee', Update.new.table('target').field('blah', 'blee').no_where.to_s)
13
+ assert_equal('UPDATE target SET blah = blee WHERE target_id = 1', Update.new.table('target').field('blah', 'blee').where('target_id = 1').to_s)
14
+ end
15
+
16
+ def test_dup
17
+ shared_builder = SqlStmt::Update.new.table('target')
18
+ first_builder = shared_builder
19
+ other_builder = shared_builder.dup
20
+
21
+ first_builder.where('status="bad"')
22
+ first_builder.field('created_at', 'NOW()')
23
+ first_builder.table('some_tbl s')
24
+
25
+ other_builder.no_where
26
+ other_builder.field('info', 'o.info')
27
+ other_builder.field('created_at', 'then')
28
+ other_builder.table('other_tbl o')
29
+
30
+ assert_equal('UPDATE target,some_tbl s SET created_at = NOW() WHERE status="bad"', first_builder.to_s)
31
+ assert_equal('UPDATE target,other_tbl o SET info = o.info, created_at = then', other_builder.to_s)
32
+ end
33
+
34
+ def test_complex
35
+ shared_builder = SqlStmt::Update.new.table('target')
36
+ shared_builder.table('shared_tbl')
37
+ shared_builder.field('created_at', 'NOW()').field('duration', 5).field('is_bad', 1)
38
+
39
+ first_builder = shared_builder
40
+ other_builder = shared_builder.dup
41
+
42
+ first_builder.where('status="bad"')
43
+
44
+ other_builder.table('other_tbl o')
45
+ other_builder.field('info', 'o.info')
46
+ other_builder.field('data', 'o.data')
47
+ other_builder.where('s.id=o.shared_id')
48
+ other_builder.where('status="good"')
49
+
50
+ assert_equal('UPDATE target,shared_tbl SET created_at = NOW(), duration = 5, is_bad = 1 WHERE status="bad"', first_builder.to_s)
51
+ assert_equal('UPDATE target,shared_tbl,other_tbl o SET created_at = NOW(), duration = 5, is_bad = 1, info = o.info, data = o.data WHERE s.id=o.shared_id AND status="good"', other_builder.to_s)
52
+ end
53
+ end
54
+
55
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sqlstmt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Makani Mason
9
+ - Kem Mason
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-02-27 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: dohutil
17
+ requirement: &70289917880740 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 0.1.5
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *70289917880740
26
+ description: mysql centric (for now) object helpers for building SQL statements
27
+ email:
28
+ - devinfo@atpsoft.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files:
32
+ - MIT-LICENSE
33
+ files:
34
+ - lib/sqlstmt/error.rb
35
+ - lib/sqlstmt/insert_select.rb
36
+ - lib/sqlstmt/query.rb
37
+ - lib/sqlstmt/select.rb
38
+ - lib/sqlstmt/to_sql.rb
39
+ - lib/sqlstmt/update.rb
40
+ - test/insert_select.dt.rb
41
+ - test/select.dt.rb
42
+ - test/to_sql.dt.rb
43
+ - test/update.dt.rb
44
+ - MIT-LICENSE
45
+ homepage: https://github.com/atpsoft/sqlstmt
46
+ licenses:
47
+ - MIT
48
+ post_install_message:
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: 1.9.2
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 1.8.15
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: helper for building SQL statements
70
+ test_files:
71
+ - test/insert_select.dt.rb
72
+ - test/select.dt.rb
73
+ - test/to_sql.dt.rb
74
+ - test/update.dt.rb
75
+ has_rdoc: