chawk 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.
- checksums.yaml +4 -4
- data/.pryrc +15 -3
- data/CHANGES +8 -1
- data/README.md +86 -61
- data/chawk.gemspec +3 -1
- data/lib/chawk/migration.rb +21 -0
- data/lib/chawk/version.rb +1 -1
- data/lib/chawk.rb +39 -19
- data/lib/models.rb +10 -150
- data/lib/node.rb +313 -0
- data/lib/range.rb +70 -0
- data/test/lib/addr_test.rb +63 -33
- data/test/lib/failed_node_test.rb +2 -2
- data/test/lib/paddr_test.rb +162 -186
- data/test/lib/range_test.rb +61 -0
- data/test/lib/vaddr_test.rb +130 -160
- data/test/schema.rb +23 -0
- data/test/test_helper.rb +9 -2
- metadata +6 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75c272978a418036f10a0f03297b48af7f40b7f4
|
4
|
+
data.tar.gz: 44b65c108649fb2fd8ab58f337c919ad02e7e959
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72f85f23a8d05e8adc1308e389796fb605867d6f9126655744e03c04ae9f9bc298a302418078f1ab3e2bba57c56d3b34e4b747a9c6212912a84fcc10c83fdf90
|
7
|
+
data.tar.gz: 05640ad20ba4b52f3671d7a1ffeb401f4445b9a2edc4c5bafb76794ebdf35241e5b7f36a4508aa840daa43d0279582850fcd551908716e87bd1b80997440db65
|
data/.pryrc
CHANGED
@@ -3,8 +3,20 @@ $:.unshift('lib')
|
|
3
3
|
require 'active_record'
|
4
4
|
require 'hirb'
|
5
5
|
require 'chawk'
|
6
|
+
require 'pp'
|
6
7
|
|
7
8
|
|
8
|
-
|
9
|
-
ActiveRecord::
|
10
|
-
|
9
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
10
|
+
ActiveRecord::Migration.verbose = false
|
11
|
+
require "chawk/migration"
|
12
|
+
CreateChawkBase.migrate :up
|
13
|
+
File.open('./test/schema.rb', "w") do |file|
|
14
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
|
15
|
+
end
|
16
|
+
|
17
|
+
agent = Chawk::Models::Agent.first || Chawk::Models::Agent.create(:name=>"Test User")
|
18
|
+
node1 = Chawk.node(agent,'a:b')
|
19
|
+
node1.points.destroy_all
|
20
|
+
|
21
|
+
ts = Time.now.to_f
|
22
|
+
|
data/CHANGES
CHANGED
@@ -6,4 +6,11 @@ Switched to ActiveRecord, removed DataMapper
|
|
6
6
|
-- 0.1.17 --
|
7
7
|
Points can now be passed as strings representing integers
|
8
8
|
-- 0.1.18 --
|
9
|
-
metadata is stored as json (must be passed as a hash)
|
9
|
+
metadata is stored as json (must be passed as a hash)
|
10
|
+
-- 0.2.0 --
|
11
|
+
Semantic Versioning
|
12
|
+
-- 0.3.0 --
|
13
|
+
Values are now working with Points.
|
14
|
+
Recalculating / self invalidating Ranges added
|
15
|
+
Statistical analysis is functional, if not efficient.
|
16
|
+
Finer grained security model
|
data/README.md
CHANGED
@@ -2,26 +2,17 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
[](http://badge.fury.io/rb/chawk)
|
5
|
-
[![Build Status]
|
6
|
-
[![Dependency Status]
|
7
|
-
[![Code Climate]
|
8
|
-
|
9
|
-
[Build Status]: https://travis-ci.org/queuetue/chawk-gem
|
10
|
-
[travis pull requests]: https://travis-ci.org/queuetue/chawk-gem/pull_requests
|
11
|
-
[Dependency Status]: https://gemnasium.com/queuetue/chawk-gem
|
12
|
-
[Code Climate]: https://codeclimate.com/github/queuetue/chawk-gem
|
13
|
-
|
14
|
-
[BS img]: https://travis-ci.org/queuetue/chawk-gem.png
|
15
|
-
[DS img]: https://gemnasium.com/queuetue/chawk-gem.png
|
16
|
-
[CC img]: https://codeclimate.com/github/queuetue/chawk-gem.png
|
17
|
-
[CS img]: https://coveralls.io/repos/queuetue/chawk/badge.png?branch=master
|
5
|
+
[](https://travis-ci.org/queuetue/chawk-gem)
|
6
|
+
[](https://gemnasium.com/queuetue/chawk-gem)
|
7
|
+
[](https://codeclimate.com/github/queuetue/chawk-gem)
|
8
|
+
[](http://doge.mit-license.org)
|
18
9
|
|
19
10
|
## Description
|
20
11
|
Chawk is a database agnostic time-series database written in Ruby.
|
21
12
|
|
22
|
-
It tracks
|
13
|
+
It tracks points (Integers) and will eventually provide statistical and aggregate tools for numeric data.
|
23
14
|
|
24
|
-
This is the gem that powers the
|
15
|
+
This is the gem that powers the server, [Chawkolate](http://www.github.com/queuetue/chawkolate "Chawkolate at Github").
|
25
16
|
|
26
17
|
Docs at [Queuetue.com](http://queuetue.com/Chawk "queuetue.com")
|
27
18
|
|
@@ -45,76 +36,93 @@ Or install it yourself as:
|
|
45
36
|
Setup
|
46
37
|
|
47
38
|
require 'chawk'
|
48
|
-
|
39
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
40
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
41
|
+
|
42
|
+
The first time using a new database (Like this sqlite memory one that is destroyed at program exit) you should call:
|
49
43
|
|
50
|
-
|
44
|
+
require "chawk/migration"
|
45
|
+
CreateChawkBase.migrate :up
|
46
|
+
File.open('./test/schema.rb', "w") do |file|
|
47
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
|
48
|
+
end
|
51
49
|
|
52
|
-
|
50
|
+
Or, setup activerecord and manage migrations however you usually do. (Rails will handle this for you, using the chawk-rails gem)
|
53
51
|
|
54
|
-
|
52
|
+
Chawk has a permissions model, which provides a framework for implementors to build a robust security model around, but it does not prevent implementors from overriding it.
|
55
53
|
|
56
|
-
|
54
|
+
Chawk's permissions begin with the Agent. All Chawk data operations require an Agent. This can be used as the main actor in your implementation code, or can be a proxy for your own User, etc through the foreign_id property.
|
57
55
|
|
58
|
-
|
56
|
+
agent = Chawk::Models::Agent.where(name:"Steve Austin").first || Chawk::Models::Agent.new(name:"Steve Austin")
|
59
57
|
|
60
|
-
|
58
|
+
All data operations are performed through an Node object, which requires an agent.
|
61
59
|
|
62
|
-
|
60
|
+
node = Chawk.node(agent,"inventory:popcorn")
|
63
61
|
|
64
|
-
|
65
|
-
addr.values.last
|
66
|
-
=> #<Chawk::Models::Value @id=...
|
67
|
-
@observed_at=...
|
68
|
-
@recorded_at=#<DateTime: ...>
|
69
|
-
@meta=nil
|
70
|
-
@value="This is a test."
|
71
|
-
@node_id=...
|
72
|
-
@agent_id=...>
|
62
|
+
Chawk.add assumes you are requesting full permissions, but you can specifically request :read, :write, :admin, or :full, which will allow specific operations and deny others. If a node does not exist when requested, it will be created and the current agen will be given full (read write and admin) permissions.
|
73
63
|
|
74
|
-
|
75
|
-
addr.values.last
|
76
|
-
=> #<Chawk::Models::Value ... @value="THIS">
|
77
|
-
addr.values.last(10)
|
78
|
-
=> [#<Chawk::Models::Value ... @value="This is a test.">,
|
79
|
-
#<Chawk::Models::Value ... @value="AND">,
|
80
|
-
#<Chawk::Models::Value ... @value="SO">,
|
81
|
-
#<Chawk::Models::Value ... @value="IS">,
|
82
|
-
#<Chawk::Models::Value ... @value="THIS">]
|
64
|
+
node = Chawk.node(agent,"inventory:popcorn", :read)
|
83
65
|
|
84
|
-
|
66
|
+
Giving (or taking) permissions from an Node can be done with the set_permissions method:
|
85
67
|
|
86
|
-
|
87
|
-
=> [#<Chawk::Models::Value ... @value="ROCK">,
|
88
|
-
#<Chawk::Models::Value ... @value="AROUND">]
|
68
|
+
node.set_permissions(agent, read, write, admin)
|
89
69
|
|
90
|
-
|
91
|
-
=> [#<Chawk::Models::Value ... @value="THE.">,
|
92
|
-
#<Chawk::Models::Value ... @value="CLOCK">]
|
70
|
+
Setting all three to false removes the Node from the list of the agent's nodes.
|
93
71
|
|
94
|
-
|
72
|
+
Nodes can also be given public read and write permissions, which allow agents without relationships to the Node to manipulate it. The methods set_public_read(bool) and set_public_write(bool) set and remove these public permissions.
|
95
73
|
|
96
|
-
|
97
|
-
|
74
|
+
The Node object stores and protects points. Points are integers and allow mathematical and statistical operations.
|
75
|
+
|
76
|
+
node.add_points [10,9,8,7,6,5]
|
77
|
+
node.points.last
|
98
78
|
=> #<Chawk::Models::Point ... @value=5>
|
99
|
-
|
79
|
+
node.points.last(2)
|
100
80
|
=> [#<Chawk::Models::Point ... @value=6>, #<Chawk::Models::Point ... @value=5>]
|
101
81
|
|
102
82
|
Points can also use the increment and decrement operators
|
103
83
|
|
104
|
-
|
84
|
+
node.points.last
|
105
85
|
=> #<Chawk::Models::Point ... @value=5>
|
106
|
-
|
107
|
-
|
86
|
+
node.points + 10
|
87
|
+
node.pointslast
|
108
88
|
=> #<Chawk::Models::Point ... @value=15>
|
109
89
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
90
|
+
Node can also return ranges from the past using the range method or the last method:
|
91
|
+
|
92
|
+
ts = Time.now
|
93
|
+
node._insert_point(0,ts-1000)
|
94
|
+
node._insert_point(1,ts-1000)
|
95
|
+
node._insert_point(2,ts-1000)
|
96
|
+
node._insert_point(5,ts-800)
|
97
|
+
node._insert_point(8,ts-200)
|
98
|
+
node._insert_point(9,ts-10)
|
99
|
+
node.points_range(ts-1001,ts).length
|
100
|
+
=> 6
|
101
|
+
node.points_range(ts-801,ts).length
|
102
|
+
=>3
|
103
|
+
node.points_range(ts-201,ts).length
|
104
|
+
=> 2
|
105
|
+
node.points_range(ts-11,ts).length
|
116
106
|
=> 1
|
107
|
+
node.points_range(ts-1001,ts-999).length
|
108
|
+
=> 3
|
109
|
+
|
110
|
+
## Chawk::Models::Range
|
111
|
+
|
112
|
+
A Chawk::Models::Range object, (soon to be merged with the Chawk.range command) produces time-limited, quantized data sets prepared for viewing, with resolution to the quarter second (one beat).
|
113
|
+
|
114
|
+
range = Chawk::Models::Range.create(start_ts:1085.0,stop_ts:1140.0,beats:1,parent_node:node1)
|
115
|
+
|
116
|
+
This will return all data from the Node parent_node in the range from timestamp 1085 to 1140, resampled to the quarter beat. (220 data points, no matter how many are actually present in the sample) This will become a stable hidden node (accessable via Node.ranges) and will automatically rebuild itself if data within it's range changes.
|
117
|
+
|
118
|
+
range = Chawk::Models::Range.create(start_ts:1088.0,stop_ts:8100.0,beats:14400,parent_node:node1)
|
117
119
|
|
120
|
+
This will return all data from the Node parent_node in the range from timestamp 1085 to 8100, resampled to the quarter beat. (2 data points, no matter how many are actually present in the sample)
|
121
|
+
|
122
|
+
## Chawk::Models::NodeAggregator
|
123
|
+
The NodeAggregator is a (currently expensive) object for aggregate calculations on a Node. It's intended ot be use on a Range's data_node property, since doing aggregate math on an entire datase can be prohibitively expensive.
|
124
|
+
|
125
|
+
In the future, the NodeAggregator will be replaced with a nonblocking concurrent object, paving the way for something like a distributed MapReduce solution.
|
118
126
|
|
119
127
|
## Contributing
|
120
128
|
|
@@ -124,6 +132,23 @@ As well as max and min
|
|
124
132
|
4. Push to the branch => `git push origin my-new-feature`
|
125
133
|
5. Create new Pull Request
|
126
134
|
|
135
|
+
## Rights
|
136
|
+
|
137
|
+
Limor Fried, also known as Ladayada of adafruit industries has suggested these rights for Internet of Things creators.
|
138
|
+
They are published here to support fair and honest practices for data collection initiatives. [Original Link](http://www.nytimes.com/roomfordebate/2013/09/08/privacy-and-the-internet-of-things/a-bill-of-rights-for-the-internet-of-things)
|
139
|
+
|
140
|
+
* Open is better than closed; this ensures portability between Internet of Things devices.
|
141
|
+
|
142
|
+
* Consumers, not companies, own the data collected by Internet of Things devices.
|
143
|
+
|
144
|
+
* Internet of Things devices that collect public data must share that data.
|
145
|
+
|
146
|
+
* Users have the right to keep their data private.
|
147
|
+
|
148
|
+
* Users can delete or back up data collected by Internet of Things devices.
|
149
|
+
|
150
|
+
Chawk is designed with these ideals in mind.
|
151
|
+
|
127
152
|
## License
|
128
153
|
|
129
154
|
Copyright (c) 2014 Scott Russell (queuetue@gmail.com / queuetue.com)
|
data/chawk.gemspec
CHANGED
@@ -22,10 +22,12 @@ Gem::Specification.new do |spec|
|
|
22
22
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.5"
|
24
24
|
spec.add_development_dependency "rake"
|
25
|
-
spec.add_development_dependency('minitest', '5.3.1')
|
26
25
|
spec.add_development_dependency('rack-test', "0.6.2")
|
27
26
|
spec.add_development_dependency('json', "1.8.1")
|
28
27
|
spec.add_development_dependency('simplecov', "0.8.2")
|
29
28
|
spec.add_development_dependency('pg', "0.17.1")
|
30
29
|
spec.add_development_dependency('sqlite3', "1.3.9")
|
30
|
+
# spec.add_development_dependency('pry')
|
31
|
+
# spec.add_development_dependency('pry-debugger')
|
32
|
+
# spec.add_development_dependency('pry-stack_explorer')
|
31
33
|
end
|
data/lib/chawk/migration.rb
CHANGED
@@ -2,6 +2,27 @@
|
|
2
2
|
|
3
3
|
class CreateChawkBase < ActiveRecord::Migration
|
4
4
|
def up
|
5
|
+
create_table "chawk_ranges", force: true do |t|
|
6
|
+
t.string "subkey"
|
7
|
+
t.integer "parent_node_id"
|
8
|
+
t.integer "data_node_id"
|
9
|
+
t.float "start_ts"
|
10
|
+
t.float "stop_ts"
|
11
|
+
t.integer "beats"
|
12
|
+
t.integer "default"
|
13
|
+
t.timestamp "expires"
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table "chawk_usage_records", force: true do |t|
|
18
|
+
t.integer "agent_id"
|
19
|
+
t.integer "node_id"
|
20
|
+
t.string "description"
|
21
|
+
t.float "time"
|
22
|
+
t.float "space"
|
23
|
+
t.timestamps
|
24
|
+
end
|
25
|
+
|
5
26
|
create_table "chawk_agents", force: true do |t|
|
6
27
|
t.integer "foreign_id"
|
7
28
|
t.string "name", limit: 200
|
data/lib/chawk/version.rb
CHANGED
data/lib/chawk.rb
CHANGED
@@ -4,41 +4,61 @@ require 'models'
|
|
4
4
|
|
5
5
|
# Chawk is a gem for storing and retrieving time seris data.
|
6
6
|
module Chawk
|
7
|
-
def self.check_node_security(agent,node)
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
def self.check_node_relations_security(rel, access)
|
9
|
+
if (rel && (rel.read || rel.admin))
|
10
|
+
case access
|
11
|
+
when :read
|
12
|
+
(rel.read or rel.admin)
|
13
|
+
when :write
|
14
|
+
(rel.write or rel.write)
|
15
|
+
when :admin
|
16
|
+
rel.admin
|
17
|
+
when :full
|
18
|
+
(rel.read && rel.write && rel.admin)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.check_node_public_security(node, access)
|
24
|
+
case access
|
25
|
+
when :read
|
26
|
+
node.public_read == true
|
27
|
+
when :write
|
28
|
+
node.public_write == true
|
11
29
|
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.check_node_security(agent,node,access=:full)
|
12
33
|
|
13
34
|
rel = node.relations.where(agent_id:agent.id).first
|
14
35
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
raise SecurityError,"You do not have permission to access this node. #{agent} #{rel}"
|
19
|
-
end
|
36
|
+
return node if check_node_relations_security(rel,access) || check_node_public_security(node,access)
|
37
|
+
|
38
|
+
raise SecurityError,"You do not have permission to access this node. #{agent} #{rel} #{access}"
|
20
39
|
end
|
21
40
|
|
22
|
-
def self.find_or_create_node(agent,key)
|
41
|
+
def self.find_or_create_node(agent,key,access=:full)
|
23
42
|
#TODO also accept regex-tested string
|
24
43
|
raise(ArgumentError,"Key must be a string.") unless key.is_a?(String)
|
25
44
|
|
26
45
|
node = Chawk::Models::Node.where(key:key).first
|
27
46
|
if node
|
28
|
-
node = check_node_security(agent,node)
|
47
|
+
node = check_node_security(agent,node,access)
|
29
48
|
else
|
30
49
|
node = Chawk::Models::Node.create(key:key) if node.nil?
|
31
|
-
node.
|
32
|
-
return node
|
50
|
+
node.set_permissions(agent,true,true,true)
|
33
51
|
end
|
52
|
+
node.access = access
|
53
|
+
return node
|
34
54
|
end
|
35
55
|
|
36
56
|
# @param agent [Chawk::Agent] the agent whose permission will be used for this request
|
37
|
-
# @param key [String] the string address this
|
38
|
-
# @return [Chawk::
|
39
|
-
# The primary method for retrieving an
|
57
|
+
# @param key [String] the string address this node can be found in the database.
|
58
|
+
# @return [Chawk::Node]
|
59
|
+
# The primary method for retrieving an Node. If a key does not exist, it will be created
|
40
60
|
# and the current agent will be set as an admin for it.
|
41
|
-
def self.
|
61
|
+
def self.node(agent,key,access=:full)
|
42
62
|
|
43
63
|
unless key =~ /^[\w\:\$\!\@\*\[\]\~\(\)]+$/
|
44
64
|
raise ArgumentError, "Key can only contain [A-Za-z0-9_:$!@*[]~()] (#{key})"
|
@@ -52,7 +72,7 @@ module Chawk
|
|
52
72
|
raise ArgumentError, 'key must be a string.'
|
53
73
|
end
|
54
74
|
|
55
|
-
node = find_or_create_node(agent,key)
|
75
|
+
node = find_or_create_node(agent,key,access)
|
56
76
|
|
57
77
|
unless node
|
58
78
|
raise ArgumentError,"No node was returned."
|
@@ -69,8 +89,8 @@ module Chawk
|
|
69
89
|
def self.bulk_add_points(agent, data)
|
70
90
|
data.keys.each do |key|
|
71
91
|
dset = data[key]
|
72
|
-
|
73
|
-
|
92
|
+
dnode = node(agent,key)
|
93
|
+
dnode.add_points dset
|
74
94
|
end
|
75
95
|
end
|
76
96
|
|
data/lib/models.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'active_record'
|
2
|
+
require 'node'
|
3
|
+
require 'range'
|
2
4
|
module Chawk
|
3
5
|
# Models used in Chawk. ActiveRecord classes.
|
4
6
|
module Models
|
@@ -9,6 +11,13 @@ module Chawk
|
|
9
11
|
has_many :tags
|
10
12
|
has_many :agent_tags
|
11
13
|
has_many :relations
|
14
|
+
has_many :nodes, :through=>:relations
|
15
|
+
has_many :read_relations, ->{where("read = ? OR admin = ?", true,true)}, :class_name=>"Chawk::Models::Relation"
|
16
|
+
has_many :read_nodes, :through=>:read_relations, :source=>:node #, ->{where(read:true, admin:true)}
|
17
|
+
has_many :write_relations, ->{where("write = ? OR admin = ?", true,true)}, :class_name=>"Chawk::Models::Relation"
|
18
|
+
has_many :write_nodes, :through=>:write_relations, :source=>:node #, ->{where(read:true, admin:true)}
|
19
|
+
has_many :admin_relations, ->{where(admin:true)}, :class_name=>"Chawk::Models::Relation"
|
20
|
+
has_many :admin_nodes, :through=>:admin_relations, :source=>:node #, ->{where(read:true, admin:true)}
|
12
21
|
end
|
13
22
|
|
14
23
|
# Agent Relation classes, with permission flags.
|
@@ -18,155 +27,6 @@ module Chawk
|
|
18
27
|
belongs_to :node
|
19
28
|
end
|
20
29
|
|
21
|
-
# The Node, where most Chawk:Addr information is persisted..
|
22
|
-
class Node < ActiveRecord::Base
|
23
|
-
attr_accessor :agent
|
24
|
-
after_initialize :init
|
25
|
-
self.table_name_prefix = "chawk_"
|
26
|
-
belongs_to :agent
|
27
|
-
has_many :points
|
28
|
-
has_many :values
|
29
|
-
has_many :relations
|
30
|
-
|
31
|
-
def init
|
32
|
-
@agent = nil
|
33
|
-
end
|
34
|
-
|
35
|
-
def _insert_point(val,ts,options={})
|
36
|
-
values = {value:val,observed_at:ts.to_f}
|
37
|
-
if options[:meta]
|
38
|
-
if options[:meta].is_a?(Hash)
|
39
|
-
values[:meta] = options[:meta].to_json
|
40
|
-
else
|
41
|
-
raise ArgumentError, "Meta must be a JSON-representable Hash. #{options[:meta].inspect}"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
self.points.create(values)
|
45
|
-
end
|
46
|
-
|
47
|
-
def _insert_point_hash(item,ts,options)
|
48
|
-
if item['v'] && item['v'].is_a?(Integer)
|
49
|
-
if item['t']
|
50
|
-
_insert_point item['v'],item['t'], options
|
51
|
-
else
|
52
|
-
_insert_point item['v'],ts, options
|
53
|
-
end
|
54
|
-
else
|
55
|
-
raise ArgumentError, "Hash must have 'v' key set to proper type.. #{item.inspect}"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def _insert_point_array(item,options)
|
60
|
-
if item.length == 2 && item[0].is_a?(Integer)
|
61
|
-
_insert_point item[0],item[1], options
|
62
|
-
else
|
63
|
-
raise ArgumentError, "Array Items must be in [value,timestamp] format. #{item.inspect}"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def _insert_point_string(item,ts,options)
|
68
|
-
if item.length > 0 && item =~ /\A[-+]?[0-9]+/
|
69
|
-
_insert_point item.to_i,ts, options
|
70
|
-
else
|
71
|
-
raise ArgumentError, "String Items must represent Integer. #{item.inspect}"
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def point_recognizer(item, dt, options={})
|
76
|
-
case
|
77
|
-
when item.is_a?(Integer)
|
78
|
-
_insert_point item,dt, options
|
79
|
-
when item.is_a?(Array)
|
80
|
-
_insert_point_array(item, options)
|
81
|
-
when item.is_a?(Hash)
|
82
|
-
_insert_point_hash(item,dt,options)
|
83
|
-
when item.is_a?(String)
|
84
|
-
_insert_point_string(item,dt,options)
|
85
|
-
else
|
86
|
-
raise ArgumentError, "Can't recognize format of data item. #{item.inspect}"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# @param args [Object, Array of Objects]
|
91
|
-
# @param options [Hash] You can also pass in :meta and :timestamp
|
92
|
-
# Add an item or an array of items (one at a time) to the datastore.
|
93
|
-
def add_points(args,options={})
|
94
|
-
options[:observed_at] ? dt = options[:observed_at] : dt = Time.now
|
95
|
-
if args.is_a?(Array)
|
96
|
-
args.each do |arg|
|
97
|
-
point_recognizer(arg, dt, options)
|
98
|
-
end
|
99
|
-
else
|
100
|
-
point_recognizer(args, dt, options)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def increment(value=1, options={})
|
105
|
-
if value.is_a?(Integer)
|
106
|
-
last = self.points.last
|
107
|
-
add_points last.value + value,options
|
108
|
-
else
|
109
|
-
raise ArgumentError, "Value must be an Integer"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def decrement(value=1, options={})
|
114
|
-
if value.is_a?(Integer)
|
115
|
-
increment (-1) * value, options
|
116
|
-
else
|
117
|
-
raise ArgumentError, "Value must be an Integer"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def max()
|
122
|
-
points.maximum('value') || 0
|
123
|
-
end
|
124
|
-
|
125
|
-
def min()
|
126
|
-
points.minimum('value') || 0
|
127
|
-
end
|
128
|
-
|
129
|
-
# Returns items whose observed_at times fit within from a range.
|
130
|
-
# @param dt_from [Time::Time] The start time.
|
131
|
-
# @param dt_to [Time::Time] The end time.
|
132
|
-
# @return [Array of Objects]
|
133
|
-
def points_range(dt_from, dt_to,options={})
|
134
|
-
vals = points.where("observed_at >= :dt_from AND observed_at <= :dt_to",{dt_from:dt_from.to_f,dt_to:dt_to.to_f}, limit:1000,order:"observed_at asc, id asc")
|
135
|
-
return vals
|
136
|
-
end
|
137
|
-
|
138
|
-
# Returns items whose observed_at times fit within from a range ending now.
|
139
|
-
# @param dt_from [Time::Time] The start time.
|
140
|
-
# @return [Array of Objects]
|
141
|
-
def points_since(dt_from)
|
142
|
-
self.points_range(dt_from,Time.now)
|
143
|
-
end
|
144
|
-
|
145
|
-
# Sets public read flag for this address
|
146
|
-
# @param value [Boolean] true if public reading is allowed, false if it is not.
|
147
|
-
def set_public_read(value)
|
148
|
-
value = value ? true : false
|
149
|
-
self.public_read = value
|
150
|
-
save
|
151
|
-
end
|
152
|
-
|
153
|
-
# Sets permissions flag for this address, for a specific agent. The existing Chawk::Relationship will be destroyed and
|
154
|
-
# a new one created as specified. Write access is not yet checked.
|
155
|
-
# @param agent [Chawk::Agent] the agent to give permission.
|
156
|
-
# @param read [Boolean] true/false can the agent read this address.
|
157
|
-
# @param write [Boolean] true/false can the agent write this address. (Read acces is required to write.)
|
158
|
-
# @param admin [Boolean] does the agent have ownership/adnim rights for this address. (Read and write are granted if admin is as well.)
|
159
|
-
def set_permissions(agent,read=false,write=false,admin=false)
|
160
|
-
relations.where(agent_id:agent.id).destroy_all
|
161
|
-
if read || write || admin
|
162
|
-
vals = {agent:agent,read:(read ? true : false),write:(write ? true : false),admin:(admin ? true : false)}
|
163
|
-
relations.create(vals)
|
164
|
-
end
|
165
|
-
nil
|
166
|
-
end
|
167
|
-
|
168
|
-
end
|
169
|
-
|
170
30
|
# The Node, where most Chawk point information is persisted..
|
171
31
|
class Point < ActiveRecord::Base
|
172
32
|
self.table_name_prefix = "chawk_"
|
@@ -180,4 +40,4 @@ module Chawk
|
|
180
40
|
end
|
181
41
|
|
182
42
|
end
|
183
|
-
end
|
43
|
+
end
|