metric_system 0.1.2 → 0.1.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d1483853542b6eb79dc9c7a0e349591d2ee14d52
4
- data.tar.gz: 9f50ee6bc48e72b83002aaf165576ce586414873
3
+ metadata.gz: 3c313b1e1c7d585f73c1210c3fb3bc610268d804
4
+ data.tar.gz: 26cf80941ed294412d5afb60e79b883ae13e2fa8
5
5
  SHA512:
6
- metadata.gz: 422740c79d19c46fce188e3b33d6cdbf45fc34c79ab37cda1560dfeae0aed607411b6678d0a6085ba6e0569249ec50ac91967fa8bb5bce38bdb048195cfa60b4
7
- data.tar.gz: 03deb35f0a2baa9a5842de40355cd8118120a49ec371e900491d458455bab093acbac6bfecc2dd1a34829bbb5122ce47294593ff7c40e3d120959d732bd34475
6
+ metadata.gz: 1c2b87a70402f5f6090c33f39228c0762777abedbd9f0d27caee1092442a6943a782576a45a48e84b6aec0ce54b4db7080abb9dbbf1a0759575274f0262f847c
7
+ data.tar.gz: a8e41c77e9810bed3d53e7bbd6c3e30c167d1ffac75c09d41d7955e6b737534cf2f1d0e618d667e5fd979d0398002caf80fc9730c3a94fa6249cb504aa3ec317
@@ -23,7 +23,7 @@ module MetricSystem
23
23
  end
24
24
 
25
25
  extend Forwardable
26
- delegate [:aggregate, :select, :print, :run, :ask, :register] => :"@target"
26
+ delegate [:aggregate, :select, :print, :run, :ask] => :"@target"
27
27
  delegate [:transaction] => :"@target"
28
28
  delegate [:add_event] => :"@target"
29
29
  delegate [:quit_server!] => :"@target"
@@ -1,12 +1,15 @@
1
1
  class MetricSystem::Database
2
- def initialize(path)
2
+ def initialize(path, readonly = false)
3
3
  require_relative "./sqlite3_extensions"
4
4
  open path
5
+
6
+ exec "PRAGMA query_only = 1" if readonly # This might or might not work.
7
+ @db.readonly = !!readonly
5
8
  end
6
9
 
7
10
  extend Forwardable
8
11
 
9
- delegate [:exec, :select, :transaction, :rollback, :print, :run, :ask, :register] => :"@db"
12
+ delegate [:exec, :select, :transaction, :rollback, :print, :run, :ask, :register, :readonly?] => :"@db"
10
13
 
11
14
  PERIODS = [
12
15
  [ :year, 31536000, "strftime('%Y-01-01', starts_at, 'unixepoch')" ],
@@ -103,7 +106,7 @@ class MetricSystem::Database
103
106
  aggregate_for_period :period => period, :source => :counters, :dest => :aggregated_counters, :aggregate => "sum"
104
107
  end
105
108
 
106
- @db.exec "DELETE FROM counters"
109
+ exec "DELETE FROM counters"
107
110
  end
108
111
 
109
112
  transaction do
@@ -111,7 +114,7 @@ class MetricSystem::Database
111
114
  aggregate_for_period :period => period, :source => :gauges, :dest => :aggregated_gauges, :aggregate => "CAST(sum AS FLOAT) / count"
112
115
  end
113
116
 
114
- @db.exec "DELETE FROM gauges"
117
+ exec "DELETE FROM gauges"
115
118
  end
116
119
  end
117
120
 
@@ -128,7 +131,7 @@ class MetricSystem::Database
128
131
  # sql expression to calculate value from sum and count of event values
129
132
  aggregate = source == :gauges ? "CAST(sum AS FLOAT) / count" : "sum"
130
133
 
131
- @db.exec <<-SQL
134
+ exec <<-SQL
132
135
  CREATE TEMPORARY TABLE batch AS
133
136
  SELECT name, starts_at, SUM(sum) AS sum, SUM(count) AS count FROM
134
137
  (
@@ -157,7 +160,7 @@ class MetricSystem::Database
157
160
  FROM batch;
158
161
  SQL
159
162
 
160
- @db.exec <<-SQL
163
+ exec <<-SQL
161
164
  DROP TABLE batch;
162
165
  SQL
163
166
  end
@@ -1,3 +1,3 @@
1
1
  module MetricSystem
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -1,27 +1,43 @@
1
1
  require 'sinatra/base'
2
2
  require 'to_js'
3
-
4
- module GoogleCharts
5
- extend self
6
-
7
- def convert(results)
8
- results.description.to_js
9
- end
10
-
11
- private
12
-
13
- end
3
+ require 'metric_system/database'
14
4
 
15
5
  class MetricSystem::Web < Sinatra::Base
16
6
  set :environment, :development
17
7
  set :raise_errors, true
18
8
  set :views, "#{File.dirname(__FILE__)}/web"
19
9
  set :dump_errors, true
10
+ set :database, nil
11
+
12
+ def self.register_query(name, query)
13
+ registry[name] = query
14
+ end
15
+
16
+ def self.registry
17
+ @registry ||= {}
18
+ end
19
+
20
+ # return a database for the current thread
21
+ def self.connection
22
+ Thread.current[:"MetricSystem::Web.database"] ||= MetricSystem::Database.new(self.database, :readonly)
23
+ end
24
+
25
+ def self.select(query, *args)
26
+ expect! query => [ String, Symbol ]
27
+
28
+ if query.is_a?(Symbol)
29
+ expect! query => registry.keys
30
+ query = registry.fetch(query)
31
+ end
32
+
33
+ result = connection.select query, *args #period: "month"
34
+ result.data_table.to_js
35
+ end
20
36
 
21
37
  helpers do
22
38
  def select(query, *args)
23
39
  @result_cache ||= {}
24
- @result_cache[query] ||= MetricSystem.database.select(query, *args).data_table.to_js
40
+ @result_cache[[query, args]] ||= self.class.select(query, *args, params)
25
41
  end
26
42
  end
27
43
 
@@ -116,22 +116,18 @@
116
116
  <div>
117
117
  <h3>Table</h3>
118
118
  <div class="google-visualization">
119
- <%=
120
- select "SELECT date(starts_at), value FROM aggregates WHERE period='day'"
121
- %>
119
+ <%= select "SELECT date(starts_at), value FROM aggregates WHERE period=:period" %>
122
120
  </div>
123
121
  </div>
124
122
  <div>
125
123
  <h3>Pie Chart</h3>
126
- <div class="google-visualization" data-src="/value_by_day_name.js" data-chart="pie">
124
+ <div class="google-visualization" data-src="/value_by_day_name.js?period=month" data-chart="pie">
127
125
  </div>
128
126
  </div>
129
127
  <div>
130
128
  <h3>Area Chart</h3>
131
129
  <div class="google-visualization" data-chart="area">
132
- <%=
133
- select "SELECT date(starts_at), value FROM aggregates WHERE period='day'"
134
- %>
130
+ <%= select "SELECT date(starts_at), value FROM aggregates WHERE period=:period" %>
135
131
  </div>
136
132
  </div>
137
133
  <div>
@@ -1,6 +1,16 @@
1
1
  class SQLite3::Database
2
+ def readonly?
3
+ @readonly
4
+ end
5
+
6
+ def readonly=(readonly)
7
+ @readonly = readonly
8
+ end
9
+
2
10
  # execute multiple SQL statements at once.
3
11
  def exec(sql, *args)
12
+ raise "Cannot run nondestructive query: #{sql}" if readonly?
13
+
4
14
  args = prepare_arguments(args)
5
15
 
6
16
  while sql =~ /\S/ do
@@ -22,15 +32,14 @@ class SQLite3::Database
22
32
  private
23
33
 
24
34
  def query(sql)
25
- expect! sql => [ String, Symbol ]
26
-
27
- if sql.is_a?(Symbol)
28
- expect! sql => registry.keys
29
- sql = registry.fetch(sql)
30
- end
35
+ expect! sql => String
31
36
 
32
37
  @queries ||= {}
33
- @queries[sql] ||= SQLite3::Query.new sql, prepare(sql)
38
+ query = @queries[sql] ||= begin
39
+ query = SQLite3::Query.new sql, prepare(sql)
40
+ raise "Cannot run nondestructive query: #{sql}" if readonly? && query.destructive?
41
+ query
42
+ end
34
43
  end
35
44
 
36
45
  def prepare_arguments(args)
@@ -72,14 +81,4 @@ class SQLite3::Database
72
81
  end
73
82
  puts "=" * log_sql.length
74
83
  end
75
-
76
- # -- query registry
77
-
78
- def registry
79
- @registry ||= {}
80
- end
81
-
82
- def register(name, query)
83
- registry[name] = query
84
- end
85
84
  end
@@ -1,12 +1,43 @@
1
+ class SQLite3::MissingParameters < RuntimeError
2
+ end
3
+
1
4
  class SQLite3::Query
5
+
6
+ # all parameters in the query, as Symbols.
7
+ attr :parameters
8
+
2
9
  def initialize(sql, statement)
3
10
  expect! statement => SQLite3::Statement
4
11
 
5
12
  @sql, @statement = sql, statement
13
+ @parameters = @sql.scan(/:([a-z]+)/).map(&:first).map(&:to_sym)
14
+ end
15
+
16
+ def destructive?
17
+ @sql !~ /\A\S*SELECT/i
6
18
  end
7
19
 
8
20
  def run(*args)
9
- # STDERR.puts "Q: #{@sql} #{args.map(&:inspect).join(", ")}"
21
+ if parameters.length > 0
22
+ named_args = {}
23
+
24
+ if args.last.is_a?(Hash)
25
+ args.pop.each do |name, value|
26
+ named_args[name.to_sym] = value
27
+ end
28
+ end
29
+
30
+ missing = parameters - named_args.keys
31
+ unless missing.empty?
32
+ raise SQLite3::MissingParameters, "Missing parameter(s): #{missing.inspect}"
33
+ end
34
+
35
+ named_args = named_args.select do |name, value|
36
+ parameters.include?(name)
37
+ end
38
+ args << named_args
39
+ end
40
+
10
41
  @statement.execute *args
11
42
  end
12
43
 
@@ -44,6 +75,8 @@ class SQLite3::Query
44
75
  { cols: cols, rows: rows }
45
76
  end
46
77
 
78
+ private
79
+
47
80
  def convert_record(record, cols)
48
81
  values = cols.map do |col|
49
82
  id, type = col.values_at(:id, :type)
@@ -30,7 +30,7 @@ benchmark "Building metric_system" do
30
30
  MetricSystem.transaction do
31
31
  1.upto(TICKS_PER_DAY) do |step|
32
32
  time = midnight + distance * step
33
- STDERR.print "."
33
+ # STDERR.print "."
34
34
  MetricSystem.count "clicks", 1, time
35
35
  end
36
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metric_system
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-12 00:00:00.000000000 Z
11
+ date: 2014-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: expectation