sqlstmt 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.
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: