micro_sql 0.2.0 → 0.3.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/Gemfile +6 -3
- data/Gemfile.lock +25 -7
- data/VERSION +1 -1
- data/lib/micro_sql.rb +115 -17
- data/lib/micro_sql/key_value_table.rb +46 -0
- data/lib/micro_sql/pg_adapter.rb +112 -23
- data/lib/micro_sql/sqlite_adapter.rb +18 -8
- data/lib/micro_sql/table.rb +17 -6
- data/micro_sql.gemspec +19 -10
- data/script/watchr +28 -0
- data/test/helper.rb +9 -1
- data/test/test_micro_sql.rb +4 -2
- data/test/test_micro_sql_pg.rb +139 -0
- data/test/test_micro_sql_sqlite3.rb +173 -0
- metadata +43 -18
- data/lib/micro_sql/settings.rb +0 -56
data/Gemfile
CHANGED
@@ -3,12 +3,15 @@ source "http://rubygems.org"
|
|
3
3
|
# Example:
|
4
4
|
# gem "activesupport", ">= 2.3.5"
|
5
5
|
|
6
|
+
gem "pg"
|
7
|
+
gem "sqlite3"
|
8
|
+
|
6
9
|
# Add dependencies to develop your gem here.
|
7
10
|
# Include everything needed to run rake, tests, features, etc.
|
8
11
|
group :development do
|
9
|
-
gem "shoulda", ">= 0"
|
10
|
-
gem "rdoc", "~> 3.12"
|
11
12
|
gem "bundler"
|
12
13
|
gem "jeweler"
|
13
|
-
|
14
|
+
gem 'simplecov', :require => false
|
15
|
+
gem "ruby-debug19"
|
14
16
|
end
|
17
|
+
|
data/Gemfile.lock
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
+
archive-tar-minitar (0.5.2)
|
5
|
+
columnize (0.3.6)
|
4
6
|
git (1.2.5)
|
5
7
|
jeweler (1.8.3)
|
6
8
|
bundler (~> 1.0)
|
@@ -8,14 +10,28 @@ GEM
|
|
8
10
|
rake
|
9
11
|
rdoc
|
10
12
|
json (1.6.6)
|
13
|
+
linecache19 (0.5.12)
|
14
|
+
ruby_core_source (>= 0.1.4)
|
15
|
+
multi_json (1.2.0)
|
16
|
+
pg (0.13.2)
|
11
17
|
rake (0.9.2.2)
|
12
18
|
rdoc (3.12)
|
13
19
|
json (~> 1.4)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
ruby-debug-base19 (0.11.25)
|
21
|
+
columnize (>= 0.3.1)
|
22
|
+
linecache19 (>= 0.5.11)
|
23
|
+
ruby_core_source (>= 0.1.4)
|
24
|
+
ruby-debug19 (0.11.6)
|
25
|
+
columnize (>= 0.3.1)
|
26
|
+
linecache19 (>= 0.5.11)
|
27
|
+
ruby-debug-base19 (>= 0.11.19)
|
28
|
+
ruby_core_source (0.1.5)
|
29
|
+
archive-tar-minitar (>= 0.5.2)
|
30
|
+
simplecov (0.6.1)
|
31
|
+
multi_json (~> 1.0)
|
32
|
+
simplecov-html (~> 0.5.3)
|
33
|
+
simplecov-html (0.5.3)
|
34
|
+
sqlite3 (1.3.5)
|
19
35
|
|
20
36
|
PLATFORMS
|
21
37
|
ruby
|
@@ -23,5 +39,7 @@ PLATFORMS
|
|
23
39
|
DEPENDENCIES
|
24
40
|
bundler
|
25
41
|
jeweler
|
26
|
-
|
27
|
-
|
42
|
+
pg
|
43
|
+
ruby-debug19
|
44
|
+
simplecov
|
45
|
+
sqlite3
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/micro_sql.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "uri"
|
2
|
+
require "logger"
|
2
3
|
|
3
4
|
class MicroSql
|
4
5
|
end
|
@@ -6,9 +7,16 @@ end
|
|
6
7
|
require_relative "micro_sql/pg_adapter"
|
7
8
|
require_relative "micro_sql/sqlite_adapter"
|
8
9
|
require_relative "micro_sql/table"
|
9
|
-
require_relative "micro_sql/
|
10
|
+
require_relative "micro_sql/key_value_table"
|
10
11
|
|
11
12
|
class MicroSql
|
13
|
+
class Error < RuntimeError; end
|
14
|
+
|
15
|
+
(class << self; self; end).class_eval do
|
16
|
+
attr :logger, true
|
17
|
+
end
|
18
|
+
|
19
|
+
self.logger = Logger.new(STDERR)
|
12
20
|
|
13
21
|
(class << self; self; end).class_eval do
|
14
22
|
private :new
|
@@ -26,15 +34,10 @@ class MicroSql
|
|
26
34
|
end
|
27
35
|
|
28
36
|
def ask(sql, *args)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
r = r.first
|
33
|
-
return r unless r.is_a?(Array)
|
34
|
-
return r unless r.length == 1
|
35
|
-
r.first
|
37
|
+
results = execute :ask, sql, *args
|
38
|
+
format_results_for_ask(results)
|
36
39
|
end
|
37
|
-
|
40
|
+
|
38
41
|
def exec!(sql, *args)
|
39
42
|
execute :no_prepare, sql, *args
|
40
43
|
end
|
@@ -43,27 +46,122 @@ class MicroSql
|
|
43
46
|
execute :prepare, sql, *args
|
44
47
|
end
|
45
48
|
|
49
|
+
private
|
50
|
+
|
51
|
+
def format_results_for_ask(results)
|
52
|
+
return results unless results.is_a?(Array)
|
53
|
+
|
54
|
+
results = results.first
|
55
|
+
|
56
|
+
return results unless results.is_a?(Array)
|
57
|
+
return results if results.length != 1
|
58
|
+
|
59
|
+
results.first
|
60
|
+
end
|
61
|
+
|
62
|
+
public
|
63
|
+
|
46
64
|
def transaction(&block)
|
47
|
-
|
65
|
+
r = nil
|
66
|
+
@impl.transaction do
|
67
|
+
r = yield
|
68
|
+
end
|
69
|
+
r
|
70
|
+
rescue RollbackException
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def rollback!
|
75
|
+
raise RollbackException
|
76
|
+
end
|
77
|
+
|
78
|
+
public
|
79
|
+
|
80
|
+
def insert(table, *values)
|
81
|
+
hashes, arrays = values.partition do |value| value.is_a?(Hash) end
|
82
|
+
|
83
|
+
id1 = insert_array_values(table, arrays)
|
84
|
+
id2 = insert_hash_values(table, hashes)
|
85
|
+
|
86
|
+
id1 || id2
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def insert_array_values(table, values)
|
92
|
+
width = values.map(&:length).max
|
93
|
+
return if width == 0 || width == nil
|
94
|
+
|
95
|
+
sql = insert_sql(table, width, nil)
|
96
|
+
values.inject(0) do |r, value|
|
97
|
+
exec sql, *value
|
98
|
+
end
|
48
99
|
end
|
49
100
|
|
50
|
-
def
|
51
|
-
|
101
|
+
def insert_hash_values(table, values)
|
102
|
+
keys = values.map(&:keys).flatten.uniq
|
103
|
+
return if keys.empty?
|
104
|
+
|
105
|
+
sql = insert_sql(table, keys.length, keys)
|
106
|
+
values.inject(0) do |r, rec|
|
107
|
+
exec sql, *rec.values_at(*keys)
|
108
|
+
end
|
52
109
|
end
|
53
110
|
|
111
|
+
def insert_sql(table, width, keys = nil)
|
112
|
+
sql = "INSERT INTO #{table}"
|
113
|
+
sql += "(#{keys.join(",")})" if keys
|
114
|
+
sql += " VALUES(" + ([ "?" ] * width).join(",") + ")"
|
115
|
+
end
|
116
|
+
|
117
|
+
public
|
118
|
+
|
119
|
+
def tables
|
120
|
+
raise "Implementation missing: #{self.class}#tables"
|
121
|
+
end
|
122
|
+
|
123
|
+
def table(sql_or_name)
|
124
|
+
@tables ||= {}
|
125
|
+
|
126
|
+
return table_from_name(sql_or_name) if sql_or_name !~ /\s/
|
127
|
+
|
128
|
+
table = Table.new(self, sql_or_name)
|
129
|
+
@tables[table.table_name] = table
|
130
|
+
end
|
131
|
+
|
54
132
|
private
|
55
133
|
|
134
|
+
def table_from_name(name)
|
135
|
+
@tables[name] ||= Table.new(self, name)
|
136
|
+
rescue RuntimeError
|
137
|
+
end
|
138
|
+
|
139
|
+
public
|
140
|
+
|
141
|
+
def key_value_table(name)
|
142
|
+
@key_value_tables ||= Hash.new { |hash, key|
|
143
|
+
hash[key] = MicroSql::KeyValueTable.new(self, key)
|
144
|
+
}
|
145
|
+
|
146
|
+
@key_value_tables[name]
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
class RollbackException < RuntimeError; end
|
152
|
+
|
56
153
|
def prepared_queries
|
57
154
|
@prepared_queries ||= {}
|
58
155
|
end
|
59
156
|
|
157
|
+
def unprepare(key)
|
158
|
+
@prepared_queries.delete key
|
159
|
+
end
|
160
|
+
|
60
161
|
def prepare(sql)
|
61
|
-
key = sql
|
62
|
-
prepared_queries.fetch(key)
|
162
|
+
key = sql
|
163
|
+
prepared_queries.fetch(key)
|
63
164
|
rescue KeyError
|
64
165
|
prepared_queries[key] = prepare_query(key, sql)
|
65
166
|
end
|
66
167
|
end
|
67
|
-
|
68
|
-
# url = "pg://sqdb:sqdb@localhost:5433/sqdb"
|
69
|
-
# MicroSql.create(url)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# -- The settings table; has support for ttl etc. ---------------------------
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
class MicroSql::KeyValueTable < MicroSql::Table
|
6
|
+
def initialize(db, table_name = "settings")
|
7
|
+
super db, "CREATE TABLE #{table_name}(uid TEXT PRIMARY KEY, value TEXT, ttl BIGINT)"
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](key)
|
11
|
+
value, ttl = db.ask("SELECT value, ttl FROM #{table_name} WHERE uid=?", key)
|
12
|
+
decode(value) if !ttl || ttl < Time.now.to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def cached(key, ttl = nil, &block)
|
16
|
+
self[key] || update(key, yield, ttl)
|
17
|
+
end
|
18
|
+
|
19
|
+
def update(key, value, ttl = nil)
|
20
|
+
if value
|
21
|
+
encoded = encode(value)
|
22
|
+
ttl += Time.now.to_i if ttl
|
23
|
+
affected = @db.ask("UPDATE #{table_name} SET value=?, ttl=? WHERE uid=?", encoded, ttl, key)
|
24
|
+
if affected == 0
|
25
|
+
@db.ask("INSERT INTO #{table_name}(value, ttl, uid) VALUES(?,?,?)", encoded, ttl, key)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
@db.ask("DELETE FROM #{table_name} WHERE uid=?", key)
|
29
|
+
end
|
30
|
+
|
31
|
+
value
|
32
|
+
end
|
33
|
+
|
34
|
+
alias :[]= :update
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def decode(io)
|
39
|
+
return unless io
|
40
|
+
JSON.parse("[#{io}]").first
|
41
|
+
end
|
42
|
+
|
43
|
+
def encode(value)
|
44
|
+
value && value.to_json
|
45
|
+
end
|
46
|
+
end
|
data/lib/micro_sql/pg_adapter.rb
CHANGED
@@ -9,57 +9,146 @@ class MicroSql::PgAdapter < MicroSql
|
|
9
9
|
:user => uri.user,
|
10
10
|
:password => uri.password,
|
11
11
|
:dbname => uri.path[1..-1]
|
12
|
+
|
13
|
+
@impl.set_notice_receiver { |result| MicroSql.logger.info(result.error_message) }
|
12
14
|
end
|
13
15
|
|
14
16
|
def tables
|
15
17
|
exec("SELECT tablename FROM pg_tables WHERE tablename NOT LIKE 'pg_%' AND tablename NOT LIKE 'sql_%'").map(&:first)
|
16
18
|
end
|
17
19
|
|
20
|
+
def primary_keys(table)
|
21
|
+
sql = <<-SQL
|
22
|
+
SELECT pg_attribute.attname
|
23
|
+
FROM pg_index, pg_class, pg_attribute
|
24
|
+
WHERE
|
25
|
+
pg_class.oid = ?::regclass AND
|
26
|
+
indrelid = pg_class.oid AND
|
27
|
+
pg_attribute.attrelid = pg_class.oid AND
|
28
|
+
pg_attribute.attnum = any(pg_index.indkey) AND
|
29
|
+
indisprimary
|
30
|
+
SQL
|
31
|
+
|
32
|
+
exec(sql, table).map(&:first)
|
33
|
+
end
|
34
|
+
|
35
|
+
def primary_key(table)
|
36
|
+
keys = primary_keys(table)
|
37
|
+
raise(Error, "No support for primary key (in table #{table})") if keys.length > 1
|
38
|
+
keys.first || raise(Error, "No primary key in table #{table}")
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def insert_sql(table_name, *args)
|
44
|
+
"#{super} RETURNING #{table(table_name).primary_key}"
|
45
|
+
end
|
46
|
+
|
47
|
+
public
|
48
|
+
|
18
49
|
def execute_batch(sql)
|
19
|
-
sql.split(";").each {
|
50
|
+
sql.split(";").each { |part|
|
51
|
+
exec!(part)
|
52
|
+
}
|
20
53
|
end
|
21
54
|
|
22
55
|
private
|
23
56
|
|
24
57
|
def execute(flag, sql, *args)
|
25
|
-
|
26
|
-
|
27
|
-
|
58
|
+
execute_(flag, sql, *args)
|
59
|
+
rescue PG::Error
|
60
|
+
raise Error, $!.message
|
61
|
+
end
|
62
|
+
|
63
|
+
def execute_(flag, sql, *args)
|
64
|
+
adjusted_sql = replace_placeholders(sql)
|
65
|
+
|
66
|
+
result = if adjusted_sql && (flag == :prepare || flag == :ask) && prepared_statement = prepare(adjusted_sql)
|
67
|
+
@impl.exec_prepared(prepared_statement, args)
|
28
68
|
else
|
29
|
-
@impl.exec(sql, args)
|
69
|
+
@impl.exec(adjusted_sql || sql, args)
|
30
70
|
end
|
31
71
|
|
32
|
-
|
72
|
+
case sql
|
73
|
+
when /^\s*UPDATE\b/
|
33
74
|
return result.cmd_tuples
|
75
|
+
when /^\s*DELETE\b/
|
76
|
+
return result.cmd_tuples
|
77
|
+
when /^\s*INSERT\b/
|
78
|
+
# postgresql has a different way of returning newly inserted ids; e.g.
|
79
|
+
# "INSERT ... RETURNING id"
|
80
|
+
# The returned id value is returned to the pg driver the same as
|
81
|
+
# a SELECT would be. We therefore evaluate only the first record.
|
82
|
+
flag = :insert
|
83
|
+
records = result.values
|
84
|
+
else
|
85
|
+
records = result.values
|
86
|
+
records = records[0,1] if flag == :ask
|
34
87
|
end
|
35
88
|
|
36
|
-
|
37
|
-
|
38
|
-
|
89
|
+
result = convert_records result, records
|
90
|
+
|
91
|
+
flag == :insert ? format_results_for_ask(result) : result
|
92
|
+
end
|
93
|
+
|
94
|
+
module Conversion
|
95
|
+
extend self
|
96
|
+
|
97
|
+
def nop; end
|
98
|
+
|
99
|
+
def string(s); s; end
|
100
|
+
def unknown(s); s; end
|
101
|
+
def integer(s); s.to_i; end
|
102
|
+
end
|
103
|
+
|
104
|
+
def conversion_for(ftype, fmod)
|
105
|
+
sym = case ftype
|
106
|
+
when 16 then :boolean
|
107
|
+
when 17 then :bytea
|
108
|
+
when 19 then :nop
|
109
|
+
when 20, 21, 22, 23, 26 then :integer
|
110
|
+
when 25 then :nop # "text"
|
111
|
+
when 700, 701 then :float
|
112
|
+
when 790, 1700 then :big_decimal
|
113
|
+
when 1083, 1266 then :string_to_time
|
39
114
|
end
|
115
|
+
|
116
|
+
return sym if sym && Conversion.respond_to?(sym)
|
117
|
+
raise "Unsupported conversion #{sym.inspect}" if sym
|
118
|
+
|
119
|
+
typename = @impl.exec( "SELECT format_type($1,$2)", [ftype, fmod] ).getvalue( 0, 0 )
|
120
|
+
|
121
|
+
return :nop if typename == "unknown"
|
122
|
+
raise "Unsupported format_type #{typename.inspect} (ftype, fmod: #{ftype}, #{fmod})"
|
123
|
+
end
|
124
|
+
|
125
|
+
def convert_records(result, records)
|
126
|
+
# Get the type of the result columns
|
127
|
+
converters = (0 ... result.num_fields).map do |i|
|
128
|
+
conversion = conversion_for result.ftype(i), result.fmod(i)
|
129
|
+
[ conversion, i ] unless conversion == :nop
|
130
|
+
end.compact
|
40
131
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
when "text", "name" then :nop
|
45
|
-
when "integer", "bigint" then rec[idx] = rec[idx] && rec[idx].to_i
|
46
|
-
else raise "Unknown column type #{type}: #{rec[idx].inspect}"
|
47
|
-
end
|
132
|
+
records.map do |record|
|
133
|
+
converters.each do |type, idx|
|
134
|
+
record[idx] = Conversion.send type, record[idx]
|
48
135
|
end
|
49
|
-
|
50
|
-
rec
|
136
|
+
record
|
51
137
|
end
|
52
138
|
end
|
53
|
-
|
54
|
-
def
|
139
|
+
|
140
|
+
def replace_placeholders(sql)
|
55
141
|
idx = 0
|
56
142
|
query = sql.gsub("?") do
|
57
143
|
idx += 1
|
58
144
|
"$#{idx}"
|
59
145
|
end
|
60
|
-
|
61
|
-
|
62
|
-
|
146
|
+
|
147
|
+
idx == 0 ? nil : query
|
148
|
+
end
|
149
|
+
|
150
|
+
def prepare_query(key, sql)
|
151
|
+
@impl.prepare(key, sql)
|
63
152
|
key
|
64
153
|
end
|
65
154
|
end
|
@@ -4,7 +4,7 @@ class MicroSql::SqliteAdapter < MicroSql
|
|
4
4
|
def initialize(url)
|
5
5
|
uri = URI.parse(url)
|
6
6
|
@impl = SQLite3::Database.new(uri.path)
|
7
|
-
exec "PRAGMA synchronous = OFF"
|
7
|
+
exec! "PRAGMA synchronous = OFF"
|
8
8
|
end
|
9
9
|
|
10
10
|
def execute_batch(sql)
|
@@ -15,17 +15,27 @@ class MicroSql::SqliteAdapter < MicroSql
|
|
15
15
|
exec("SELECT name FROM sqlite_master WHERE type=?", "table").map(&:first)
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
private
|
19
|
+
|
20
|
+
def execute(prepare, sql, *args)
|
21
|
+
prepared_query = prepare(sql)
|
22
|
+
execute_prepared_query sql, prepared_query, *args
|
23
|
+
ensure
|
24
|
+
unprepare(sql) if prepare == :no_prepare
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute_prepared_query(sql, query, *args)
|
28
|
+
results = query.execute!(*args)
|
20
29
|
case sql
|
21
|
-
when /^\s*INSERT/i
|
22
|
-
when /^\s*
|
23
|
-
|
30
|
+
when /^\s*INSERT/i then @impl.last_insert_row_id
|
31
|
+
when /^\s*UPDATE/i then @impl.changes
|
32
|
+
when /^\s*DELETE/i then @impl.changes
|
33
|
+
else results
|
24
34
|
end
|
35
|
+
rescue SQLite3::ConstraintException
|
36
|
+
raise Error, $!.message
|
25
37
|
end
|
26
38
|
|
27
|
-
private
|
28
|
-
|
29
39
|
def prepare_query(key, sql)
|
30
40
|
@impl.prepare(sql)
|
31
41
|
end
|
data/lib/micro_sql/table.rb
CHANGED
@@ -5,15 +5,26 @@ class MicroSql::Table
|
|
5
5
|
|
6
6
|
def initialize(db, sql)
|
7
7
|
@db = db
|
8
|
-
|
8
|
+
|
9
|
+
if sql !~ /\s/
|
10
|
+
# no space: sql must be the table_name
|
11
|
+
@table_name = sql
|
12
|
+
raise "No such table: '#{@table_name}'" unless exists?
|
13
|
+
elsif sql =~ /\s*CREATE TABLE\s+([^\( ]+)/
|
9
14
|
@table_name = $1
|
15
|
+
raise ArgumentError, "Cannot determine table_name from SQL: #{sql}" unless table_name
|
16
|
+
build(sql) unless exists?
|
10
17
|
end
|
11
|
-
|
12
|
-
raise ArgumentError, "Cannot determine table_name from SQL: #{sql}" unless table_name
|
13
|
-
|
14
|
-
build(sql) unless exists?
|
15
18
|
end
|
16
19
|
|
20
|
+
def insert(*values)
|
21
|
+
db.insert table_name, *values
|
22
|
+
end
|
23
|
+
|
24
|
+
def primary_key
|
25
|
+
@primary_key ||= db.primary_key(table_name)
|
26
|
+
end
|
27
|
+
|
17
28
|
private
|
18
29
|
|
19
30
|
def exists?
|
@@ -21,7 +32,7 @@ class MicroSql::Table
|
|
21
32
|
end
|
22
33
|
|
23
34
|
def build(sql)
|
24
|
-
|
35
|
+
MicroSql.logger.info "Create table #{table_name}"
|
25
36
|
db.execute_batch(sql)
|
26
37
|
end
|
27
38
|
end
|
data/micro_sql.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "micro_sql"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["radiospiel"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-04-02"
|
13
13
|
s.description = "You only need a single method to talk to your database..."
|
14
14
|
s.email = "eno@open-lab.org"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,13 +25,16 @@ Gem::Specification.new do |s|
|
|
25
25
|
"Rakefile",
|
26
26
|
"VERSION",
|
27
27
|
"lib/micro_sql.rb",
|
28
|
+
"lib/micro_sql/key_value_table.rb",
|
28
29
|
"lib/micro_sql/pg_adapter.rb",
|
29
|
-
"lib/micro_sql/settings.rb",
|
30
30
|
"lib/micro_sql/sqlite_adapter.rb",
|
31
31
|
"lib/micro_sql/table.rb",
|
32
32
|
"micro_sql.gemspec",
|
33
|
+
"script/watchr",
|
33
34
|
"test/helper.rb",
|
34
|
-
"test/test_micro_sql.rb"
|
35
|
+
"test/test_micro_sql.rb",
|
36
|
+
"test/test_micro_sql_pg.rb",
|
37
|
+
"test/test_micro_sql_sqlite3.rb"
|
35
38
|
]
|
36
39
|
s.homepage = "http://github.com/radiospiel/micro_sql"
|
37
40
|
s.licenses = ["MIT"]
|
@@ -43,21 +46,27 @@ Gem::Specification.new do |s|
|
|
43
46
|
s.specification_version = 3
|
44
47
|
|
45
48
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
46
|
-
s.
|
47
|
-
s.
|
49
|
+
s.add_runtime_dependency(%q<pg>, [">= 0"])
|
50
|
+
s.add_runtime_dependency(%q<sqlite3>, [">= 0"])
|
48
51
|
s.add_development_dependency(%q<bundler>, [">= 0"])
|
49
52
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
|
50
55
|
else
|
51
|
-
s.add_dependency(%q<
|
52
|
-
s.add_dependency(%q<
|
56
|
+
s.add_dependency(%q<pg>, [">= 0"])
|
57
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
53
58
|
s.add_dependency(%q<bundler>, [">= 0"])
|
54
59
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
60
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
61
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
55
62
|
end
|
56
63
|
else
|
57
|
-
s.add_dependency(%q<
|
58
|
-
s.add_dependency(%q<
|
64
|
+
s.add_dependency(%q<pg>, [">= 0"])
|
65
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
59
66
|
s.add_dependency(%q<bundler>, [">= 0"])
|
60
67
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
68
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
69
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
61
70
|
end
|
62
71
|
end
|
63
72
|
|
data/script/watchr
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rb-fsevent'
|
3
|
+
|
4
|
+
if ARGV.length < 2
|
5
|
+
STDERR.puts "watchr dir ruby-parameter(s)..."
|
6
|
+
abort
|
7
|
+
end
|
8
|
+
|
9
|
+
paths = ARGV.shift.split(",")
|
10
|
+
$args = ARGV.dup
|
11
|
+
|
12
|
+
|
13
|
+
def do_ruby
|
14
|
+
STDERR.puts $args.join(" ")
|
15
|
+
STDERR.puts "=" * 80
|
16
|
+
|
17
|
+
system(*$args)
|
18
|
+
end
|
19
|
+
|
20
|
+
puts "Initial run"
|
21
|
+
do_ruby
|
22
|
+
|
23
|
+
fsevent = FSEvent.new
|
24
|
+
fsevent.watch paths do |directories|
|
25
|
+
puts "Detected change inside: #{directories.inspect}"
|
26
|
+
do_ruby
|
27
|
+
end
|
28
|
+
fsevent.run
|
data/test/helper.rb
CHANGED
@@ -7,12 +7,20 @@ rescue Bundler::BundlerError => e
|
|
7
7
|
$stderr.puts "Run `bundle install` to install missing gems"
|
8
8
|
exit e.status_code
|
9
9
|
end
|
10
|
+
|
11
|
+
require 'ruby-debug'
|
12
|
+
require 'simplecov'
|
10
13
|
require 'test/unit'
|
11
|
-
|
14
|
+
SimpleCov.start do
|
15
|
+
add_filter "test/helper.rb"
|
16
|
+
end
|
12
17
|
|
13
18
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
19
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
20
|
require 'micro_sql'
|
16
21
|
|
22
|
+
MicroSql.logger.level = Logger::WARN
|
23
|
+
|
17
24
|
class Test::Unit::TestCase
|
18
25
|
end
|
26
|
+
|
data/test/test_micro_sql.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
class TestMicroSql < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
4
|
+
def test_assert_creation_with_unsupported_url
|
5
|
+
assert_raise(NameError) {
|
6
|
+
MicroSql.create "xy://abc"
|
7
|
+
}
|
6
8
|
end
|
7
9
|
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
load "#{File.dirname(__FILE__)}/helper.rb"
|
2
|
+
|
3
|
+
class TestMicroSqlPg < Test::Unit::TestCase
|
4
|
+
PG_URL = "pg://micro_sql:micro_sql@localhost/micro_sql_test"
|
5
|
+
|
6
|
+
def db
|
7
|
+
@db ||= MicroSql.create(PG_URL).tap do |db|
|
8
|
+
db.tables.each { |table_name| db.exec("DROP TABLE #{table_name}") }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_assert_create_tables
|
13
|
+
db.execute_batch <<-SQL
|
14
|
+
CREATE TABLE t1(idx INTEGER PRIMARY KEY, b TEXT);
|
15
|
+
CREATE TABLE t2(a INTEGER, b TEXT);
|
16
|
+
SQL
|
17
|
+
|
18
|
+
assert_equal %w(t1 t2), db.tables.sort
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_ask_and_exec
|
22
|
+
db.execute_batch <<-SQL
|
23
|
+
DROP SEQUENCE IF EXISTS t1_idx_seq;
|
24
|
+
CREATE SEQUENCE t1_idx_seq;
|
25
|
+
CREATE TABLE t1(idx INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('t1_idx_seq'), b TEXT);
|
26
|
+
ALTER SEQUENCE t1_idx_seq OWNED BY t1.idx
|
27
|
+
SQL
|
28
|
+
|
29
|
+
# -- insert
|
30
|
+
r = db.ask("INSERT INTO t1 (idx,b) VALUES(12, '') RETURNING idx")
|
31
|
+
assert_equal 12, r
|
32
|
+
assert_equal 13, db.exec("INSERT INTO t1 (idx,b) VALUES(13, '') RETURNING idx")
|
33
|
+
|
34
|
+
assert_raise(MicroSql::Error) {
|
35
|
+
assert_equal 1, db.exec("INSERT INTO t1 (idx,b) VALUES(13, '') RETURNING idx")
|
36
|
+
}
|
37
|
+
assert_raise(MicroSql::Error) {
|
38
|
+
assert_equal 1, db.ask("INSERT INTO t1 (idx,b) VALUES(13, '') RETURNING idx")
|
39
|
+
}
|
40
|
+
|
41
|
+
# -- update
|
42
|
+
|
43
|
+
assert_equal 1, db.ask("UPDATE t1 SET b = 'b' WHERE idx=12")
|
44
|
+
assert_equal 2, db.ask("UPDATE t1 SET b = 'c'")
|
45
|
+
assert_equal 0, db.ask("UPDATE t1 SET b = 'b' WHERE idx=12345")
|
46
|
+
|
47
|
+
# assert_equal 1, db.exec("INSERT INTO t1 (idx,b) VALUES(13, '')")
|
48
|
+
# assert_equal(13, r)
|
49
|
+
#
|
50
|
+
|
51
|
+
# -- delete
|
52
|
+
assert_equal 1, db.ask("DELETE FROM t1 WHERE idx=12")
|
53
|
+
assert_equal 0, db.exec("DELETE FROM t1 WHERE idx=12")
|
54
|
+
assert_equal 1, db.exec("DELETE FROM t1 WHERE idx=13")
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_type_conversion
|
58
|
+
assert_equal(1, db.ask("SELECT 1"))
|
59
|
+
assert_equal('1', db.ask("SELECT '1'"))
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_row_conversion
|
63
|
+
assert_equal(1, db.ask("SELECT 1"))
|
64
|
+
assert_equal([1, 2], db.ask("SELECT 1, 2"))
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_arguments
|
68
|
+
db.ask "CREATE TABLE t1(idx INTEGER PRIMARY KEY, b TEXT)"
|
69
|
+
assert_equal nil, db.ask("SELECT idx FROM t1 WHERE idx=?", 12)
|
70
|
+
|
71
|
+
db.ask("INSERT INTO t1 (idx,b) VALUES(12, 'twelve')")
|
72
|
+
db.ask("INSERT INTO t1 (idx,b) VALUES(13, 'thirteen')")
|
73
|
+
db.ask("INSERT INTO t1 (idx,b) VALUES(0, NULL)")
|
74
|
+
|
75
|
+
assert_equal 3, db.ask("SELECT COUNT(*) FROM t1")
|
76
|
+
assert_equal 12, db.ask("SELECT idx FROM t1 WHERE idx=12")
|
77
|
+
assert_equal 12, db.ask("SELECT idx FROM t1 WHERE idx=?", 12)
|
78
|
+
assert_equal 12, db.ask("SELECT idx FROM t1 WHERE b=?", "twelve")
|
79
|
+
assert_equal 12, db.ask("SELECT idx FROM t1 WHERE b=? AND idx=?", "twelve", 12)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_transaction
|
83
|
+
db.ask "CREATE TABLE t1(idx INTEGER PRIMARY KEY, b TEXT)"
|
84
|
+
|
85
|
+
count = db.transaction do
|
86
|
+
db.ask("INSERT INTO t1 (idx,b) VALUES(12, 'twelve')")
|
87
|
+
db.ask("SELECT COUNT(*) FROM t1")
|
88
|
+
end
|
89
|
+
assert_equal 1, count
|
90
|
+
|
91
|
+
assert_equal 1, db.ask("SELECT COUNT(*) FROM t1")
|
92
|
+
|
93
|
+
db.transaction do
|
94
|
+
db.ask("INSERT INTO t1 (idx,b) VALUES(13, 'twelve')")
|
95
|
+
assert_equal 2, db.ask("SELECT COUNT(*) FROM t1")
|
96
|
+
db.rollback!
|
97
|
+
end
|
98
|
+
|
99
|
+
assert_equal 1, db.ask("SELECT COUNT(*) FROM t1")
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_insert
|
103
|
+
assert_equal([], db.tables)
|
104
|
+
t1 = db.table "CREATE TABLE t1(idx INTEGER PRIMARY KEY, b TEXT)"
|
105
|
+
|
106
|
+
assert_equal(["t1"], db.tables)
|
107
|
+
assert_equal("t1", t1.table_name)
|
108
|
+
|
109
|
+
assert_equal nil, db.table("t2")
|
110
|
+
|
111
|
+
t1.insert [1, "1"], [2, "2"]
|
112
|
+
assert_equal [[1], [2]], db.exec("SELECT idx FROM t1")
|
113
|
+
|
114
|
+
assert_equal(3, t1.insert([3, "3"]))
|
115
|
+
|
116
|
+
assert_equal(4, t1.insert(:idx => 4))
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_kv_table
|
120
|
+
kv = db.key_value_table("kv")
|
121
|
+
assert_equal [ "kv" ], db.tables
|
122
|
+
|
123
|
+
kv["x"] = "y"
|
124
|
+
assert_equal 1, db.ask("SELECT COUNT(*) FROM kv")
|
125
|
+
assert_equal "y", kv["x"]
|
126
|
+
|
127
|
+
kv["x"] = nil
|
128
|
+
assert_equal 0, db.ask("SELECT COUNT(*) FROM kv")
|
129
|
+
assert_equal nil, kv["x"]
|
130
|
+
|
131
|
+
count = 0
|
132
|
+
|
133
|
+
r = kv.cached "x" do "y" end
|
134
|
+
assert_equal(r, "y")
|
135
|
+
|
136
|
+
r = kv.cached "x" do raise "Yo"; "y" end
|
137
|
+
assert_equal(r, "y")
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
class TestMicroSqlite3 < Test::Unit::TestCase
|
6
|
+
attr :tmpdir
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@tmpdir = Dir.mktmpdir
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
FileUtils.rm_rf(@tmpdir) if @tmpdir
|
14
|
+
end
|
15
|
+
|
16
|
+
def db
|
17
|
+
@db ||= MicroSql.create "#{tmpdir}/test.sqlite3"
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_assert_creation_of_db_file_from_url
|
21
|
+
path = "#{tmpdir}/db.sqlite3"
|
22
|
+
assert !File.exists?(path)
|
23
|
+
|
24
|
+
url = "sqlite://#{path}"
|
25
|
+
db = MicroSql.create url
|
26
|
+
assert File.exists?(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_assert_creation_of_db_file_from_path
|
30
|
+
path = "#{tmpdir}/db.sqlite3"
|
31
|
+
assert !File.exists?(path)
|
32
|
+
|
33
|
+
db = MicroSql.create path
|
34
|
+
assert File.exists?(path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_assert_create_tables
|
38
|
+
db.execute_batch <<-SQL
|
39
|
+
CREATE TABLE t1(idx INTEGER PRIMARY KEY, b INTEGER);
|
40
|
+
CREATE TABLE t2(a INTEGER, b INTEGER);
|
41
|
+
SQL
|
42
|
+
|
43
|
+
assert_equal %w(t1 t2), db.tables.sort
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_ask_and_exec
|
47
|
+
db.ask "CREATE TABLE t1(idx INTEGER PRIMARY KEY, b INTEGER)"
|
48
|
+
|
49
|
+
# -- insert
|
50
|
+
assert_equal 12, db.ask("INSERT INTO t1 (idx,b) VALUES(12, '')")
|
51
|
+
assert_equal 13, db.exec("INSERT INTO t1 (idx,b) VALUES(13, '')")
|
52
|
+
|
53
|
+
assert_raise(MicroSql::Error) {
|
54
|
+
assert_equal 1, db.exec("INSERT INTO t1 (idx,b) VALUES(13, '')")
|
55
|
+
}
|
56
|
+
assert_raise(MicroSql::Error) {
|
57
|
+
assert_equal 1, db.ask("INSERT INTO t1 (idx,b) VALUES(13, '')")
|
58
|
+
}
|
59
|
+
|
60
|
+
# -- update
|
61
|
+
|
62
|
+
assert_equal 1, db.ask("UPDATE t1 SET b = 'b' WHERE idx=12")
|
63
|
+
assert_equal 2, db.ask("UPDATE t1 SET b = 'c'")
|
64
|
+
assert_equal 0, db.ask("UPDATE t1 SET b = 'b' WHERE idx=12345")
|
65
|
+
|
66
|
+
# assert_equal 1, db.exec("INSERT INTO t1 (idx,b) VALUES(13, '')")
|
67
|
+
# assert_equal(13, r)
|
68
|
+
#
|
69
|
+
|
70
|
+
# -- delete
|
71
|
+
assert_equal 1, db.ask("DELETE FROM t1 WHERE idx=12")
|
72
|
+
assert_equal 0, db.exec("DELETE FROM t1 WHERE idx=12")
|
73
|
+
assert_equal 1, db.exec("DELETE FROM t1 WHERE idx=13")
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_preparation
|
77
|
+
assert_equal(0, db.send(:prepared_queries).length)
|
78
|
+
|
79
|
+
db.exec("SELECT 1")
|
80
|
+
assert_equal(1, db.send(:prepared_queries).length)
|
81
|
+
|
82
|
+
db.ask("SELECT 2")
|
83
|
+
assert_equal(2, db.send(:prepared_queries).length)
|
84
|
+
|
85
|
+
db.ask("SELECT 2")
|
86
|
+
assert_equal(2, db.send(:prepared_queries).length)
|
87
|
+
|
88
|
+
db.exec!("SELECT 3")
|
89
|
+
assert_equal(2, db.send(:prepared_queries).length)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_type_conversion
|
93
|
+
assert_equal(1, db.ask("SELECT 1"))
|
94
|
+
assert_equal('1', db.ask("SELECT '1'"))
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_row_conversion
|
98
|
+
assert_equal(1, db.ask("SELECT 1"))
|
99
|
+
assert_equal([1, 2], db.ask("SELECT 1, 2"))
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_arguments
|
103
|
+
db.ask "CREATE TABLE t1(idx INTEGER PRIMARY KEY, b INTEGER)"
|
104
|
+
db.ask("INSERT INTO t1 (idx,b) VALUES(12, 'twelve')")
|
105
|
+
db.ask("INSERT INTO t1 (idx,b) VALUES(13, 'thirteen')")
|
106
|
+
db.ask("INSERT INTO t1 (idx,b) VALUES(0, NULL)")
|
107
|
+
|
108
|
+
assert_equal 3, db.ask("SELECT COUNT(*) FROM t1")
|
109
|
+
assert_equal 12, db.ask("SELECT idx FROM t1 WHERE idx=?", 12)
|
110
|
+
assert_equal 12, db.ask("SELECT idx FROM t1 WHERE b=?", "twelve")
|
111
|
+
assert_equal 12, db.ask("SELECT idx FROM t1 WHERE b=? AND idx=?", "twelve", 12)
|
112
|
+
assert_equal 0, db.ask("SELECT idx FROM t1 WHERE b IS ?", nil)
|
113
|
+
assert_equal nil, db.ask("SELECT idx FROM t1 WHERE b=?", nil) # b=NULL is never true but always NULL
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_transaction
|
117
|
+
db.ask "CREATE TABLE t1(idx INTEGER PRIMARY KEY, b INTEGER)"
|
118
|
+
|
119
|
+
count = db.transaction do
|
120
|
+
db.ask("INSERT INTO t1 (idx,b) VALUES(12, 'twelve')")
|
121
|
+
db.ask("SELECT COUNT(*) FROM t1")
|
122
|
+
end
|
123
|
+
assert_equal 1, count
|
124
|
+
|
125
|
+
assert_equal 1, db.ask("SELECT COUNT(*) FROM t1")
|
126
|
+
|
127
|
+
db.transaction do
|
128
|
+
db.ask("INSERT INTO t1 (idx,b) VALUES(13, 'twelve')")
|
129
|
+
assert_equal 2, db.ask("SELECT COUNT(*) FROM t1")
|
130
|
+
db.rollback!
|
131
|
+
end
|
132
|
+
|
133
|
+
assert_equal 1, db.ask("SELECT COUNT(*) FROM t1")
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_insert
|
137
|
+
assert_equal([], db.tables)
|
138
|
+
t1 = db.table "CREATE TABLE t1(idx INTEGER PRIMARY KEY, b TEXT)"
|
139
|
+
|
140
|
+
assert_equal(["t1"], db.tables)
|
141
|
+
assert_equal("t1", t1.table_name)
|
142
|
+
|
143
|
+
assert_equal nil, db.table("t2")
|
144
|
+
|
145
|
+
t1.insert [1, "1"], [2, "2"]
|
146
|
+
assert_equal [[1], [2]], db.exec("SELECT idx FROM t1")
|
147
|
+
|
148
|
+
assert_equal(3, t1.insert([3, "3"]))
|
149
|
+
|
150
|
+
assert_equal(4, t1.insert(:idx => 4))
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_kv_table
|
154
|
+
kv = db.key_value_table("kv")
|
155
|
+
assert_equal [ "kv" ], db.tables
|
156
|
+
|
157
|
+
kv["x"] = "y"
|
158
|
+
assert_equal 1, db.ask("SELECT COUNT(*) FROM kv")
|
159
|
+
assert_equal "y", kv["x"]
|
160
|
+
|
161
|
+
kv["x"] = nil
|
162
|
+
assert_equal 0, db.ask("SELECT COUNT(*) FROM kv")
|
163
|
+
assert_equal nil, kv["x"]
|
164
|
+
|
165
|
+
count = 0
|
166
|
+
|
167
|
+
r = kv.cached "x" do "y" end
|
168
|
+
assert_equal(r, "y")
|
169
|
+
|
170
|
+
r = kv.cached "x" do raise "Yo"; "y" end
|
171
|
+
assert_equal(r, "y")
|
172
|
+
end
|
173
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: micro_sql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,33 +9,33 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-04-02 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement: &
|
15
|
+
name: pg
|
16
|
+
requirement: &70130046726220 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: '0'
|
22
|
-
type: :
|
22
|
+
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70130046726220
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
27
|
-
requirement: &
|
26
|
+
name: sqlite3
|
27
|
+
requirement: &70130046701360 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
|
-
- -
|
30
|
+
- - ! '>='
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
33
|
-
type: :
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70130046701360
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: bundler
|
38
|
-
requirement: &
|
38
|
+
requirement: &70130046688900 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,32 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70130046688900
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: jeweler
|
49
|
-
requirement: &
|
49
|
+
requirement: &70130046663760 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70130046663760
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: simplecov
|
60
|
+
requirement: &70130046580920 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70130046580920
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ruby-debug19
|
71
|
+
requirement: &70130046570120 !ruby/object:Gem::Requirement
|
50
72
|
none: false
|
51
73
|
requirements:
|
52
74
|
- - ! '>='
|
@@ -54,7 +76,7 @@ dependencies:
|
|
54
76
|
version: '0'
|
55
77
|
type: :development
|
56
78
|
prerelease: false
|
57
|
-
version_requirements: *
|
79
|
+
version_requirements: *70130046570120
|
58
80
|
description: You only need a single method to talk to your database...
|
59
81
|
email: eno@open-lab.org
|
60
82
|
executables: []
|
@@ -71,13 +93,16 @@ files:
|
|
71
93
|
- Rakefile
|
72
94
|
- VERSION
|
73
95
|
- lib/micro_sql.rb
|
96
|
+
- lib/micro_sql/key_value_table.rb
|
74
97
|
- lib/micro_sql/pg_adapter.rb
|
75
|
-
- lib/micro_sql/settings.rb
|
76
98
|
- lib/micro_sql/sqlite_adapter.rb
|
77
99
|
- lib/micro_sql/table.rb
|
78
100
|
- micro_sql.gemspec
|
101
|
+
- script/watchr
|
79
102
|
- test/helper.rb
|
80
103
|
- test/test_micro_sql.rb
|
104
|
+
- test/test_micro_sql_pg.rb
|
105
|
+
- test/test_micro_sql_sqlite3.rb
|
81
106
|
homepage: http://github.com/radiospiel/micro_sql
|
82
107
|
licenses:
|
83
108
|
- MIT
|
@@ -93,7 +118,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
118
|
version: '0'
|
94
119
|
segments:
|
95
120
|
- 0
|
96
|
-
hash:
|
121
|
+
hash: -292595813074764874
|
97
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
123
|
none: false
|
99
124
|
requirements:
|
data/lib/micro_sql/settings.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
# -- The settings table; has support for ttl etc. ---------------------------
|
2
|
-
|
3
|
-
require "json"
|
4
|
-
|
5
|
-
class MicroSql::SettingsTable < MicroSql::Table
|
6
|
-
def initialize(db)
|
7
|
-
super db, "CREATE TABLE settings(uid TEXT PRIMARY KEY, value TEXT, ttl BIGINT)"
|
8
|
-
end
|
9
|
-
|
10
|
-
def [](key)
|
11
|
-
value, ttl = db.ask("SELECT value, ttl FROM settings WHERE uid=?", key)
|
12
|
-
decode(value) if !ttl || ttl < Time.now.to_i
|
13
|
-
end
|
14
|
-
|
15
|
-
def cached(key, ttl, &block)
|
16
|
-
update(key, yield, ttl)
|
17
|
-
end
|
18
|
-
|
19
|
-
def update(key, value, ttl = nil)
|
20
|
-
if value
|
21
|
-
encoded = encode(value)
|
22
|
-
ttl += Time.now.to_i if ttl
|
23
|
-
affected = @db.ask("UPDATE settings SET value=?, ttl=? WHERE uid=?", encoded, ttl, key)
|
24
|
-
if affected == 0
|
25
|
-
@db.ask("INSERT INTO settings(value, ttl, uid) VALUES(?,?,?)", encoded, ttl, key)
|
26
|
-
end
|
27
|
-
else
|
28
|
-
@db.ask("DELETE FROM settings WHERE uid=?", key)
|
29
|
-
end
|
30
|
-
|
31
|
-
value
|
32
|
-
end
|
33
|
-
|
34
|
-
alias :[]= :update
|
35
|
-
|
36
|
-
def decode(io)
|
37
|
-
return unless io
|
38
|
-
JSON.parse("[#{io}]").first
|
39
|
-
end
|
40
|
-
|
41
|
-
def encode(value)
|
42
|
-
value && value.to_json
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
require "forwardable"
|
47
|
-
|
48
|
-
class MicroSql::Settings
|
49
|
-
def initialize(url)
|
50
|
-
@db = MicroSql.create(url)
|
51
|
-
@settings_table = MicroSql::SettingsTable.new @db
|
52
|
-
end
|
53
|
-
|
54
|
-
extend Forwardable
|
55
|
-
delegate [ :[], :cached, :update, :[]= ] => :@settings_table
|
56
|
-
end
|