micro_sql 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|