fauna 0.2.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/fauna/set.rb ADDED
@@ -0,0 +1,184 @@
1
+ module Fauna
2
+ class Set
3
+
4
+ attr_reader :ref
5
+
6
+ def initialize(ref)
7
+ @ref = ref
8
+ end
9
+
10
+ def page(pagination = {})
11
+ SetPage.find(ref, {}, pagination)
12
+ end
13
+
14
+ def events(pagination = {})
15
+ EventsPage.find("#{ref}/events", {}, pagination)
16
+ end
17
+
18
+ # query DSL
19
+
20
+ def self.query(&block)
21
+ module_eval(&block)
22
+ end
23
+
24
+ def self.union(*args)
25
+ QuerySet.new('union', *args)
26
+ end
27
+
28
+ def self.intersection(*args)
29
+ QuerySet.new('intersection', *args)
30
+ end
31
+
32
+ def self.difference(*args)
33
+ QuerySet.new('difference', *args)
34
+ end
35
+
36
+ def self.merge(*args)
37
+ QuerySet.new('merge', *args)
38
+ end
39
+
40
+ def self.join(*args)
41
+ QuerySet.new('join', *args)
42
+ end
43
+
44
+ def self.match(*args)
45
+ QuerySet.new('match', *args)
46
+ end
47
+
48
+ # although each is handled via the query DSL, it might make more
49
+ # sense to add it as a modifier on Set instances, similar to events.
50
+
51
+ def self.each(*args)
52
+ EachSet.new(*args)
53
+ end
54
+ end
55
+
56
+ class QuerySet < Set
57
+ def initialize(function, *params)
58
+ @function = function
59
+ @params = params
60
+ end
61
+
62
+ def param_strings
63
+ @param_strings ||= @params.map do |p|
64
+ if p.respond_to? :expr
65
+ p.expr
66
+ elsif p.respond_to? :ref
67
+ p.ref
68
+ else
69
+ p
70
+ end
71
+ end
72
+ end
73
+
74
+ def expr
75
+ @expr ||= "#{@function}(#{param_strings.join ','})"
76
+ end
77
+
78
+ def ref
79
+ "query?q=#{expr}"
80
+ end
81
+
82
+ def page(pagination = {})
83
+ SetPage.find('query', { 'q' => expr }, pagination)
84
+ end
85
+
86
+ def events(pagination = {})
87
+ EventsPage.find("query", { 'q' => "events(#{expr})" }, pagination)
88
+ end
89
+ end
90
+
91
+ class EachSet < QuerySet
92
+ def initialize(*params)
93
+ super('each', *params)
94
+ end
95
+
96
+ def events(pagination = {})
97
+ query = param_strings.first
98
+ subqueries = param_strings.drop(1).join ','
99
+ EventsPage.find("query", { 'q' => "each(events(#{query}),#{subqueries})" }, pagination)
100
+ end
101
+ end
102
+
103
+ class CustomSet < Set
104
+ def add(resource)
105
+ self.class.add(self, resource)
106
+ end
107
+
108
+ def remove(resource)
109
+ self.class.remove(self, resource)
110
+ end
111
+
112
+ def self.add(set, resource)
113
+ set = set.ref if set.respond_to? :ref
114
+ resource = resource.ref if resource.respond_to? :ref
115
+ Fauna::Client.put("#{set}/#{resource}")
116
+ end
117
+
118
+ def self.remove(set, resource)
119
+ set = set.ref if set.respond_to? :ref
120
+ resource = resource.ref if resource.respond_to? :ref
121
+ Fauna::Client.delete("#{set}/#{resource}")
122
+ end
123
+ end
124
+
125
+ class SetPage < Fauna::Resource
126
+ include Enumerable
127
+
128
+ def refs
129
+ @refs ||= struct['resources']
130
+ end
131
+
132
+ def each(&block)
133
+ refs.each(&block)
134
+ end
135
+
136
+ def empty?
137
+ refs.empty?
138
+ end
139
+
140
+ def length; refs.length end
141
+ def size; refs.size end
142
+ end
143
+
144
+ class EventsPage < Fauna::Resource
145
+ include Enumerable
146
+
147
+ def events
148
+ @events ||= struct['events'].map { |e| Event.new(e) }
149
+ end
150
+
151
+ def each(&block)
152
+ events.each(&block)
153
+ end
154
+
155
+ def empty?
156
+ events.empty?
157
+ end
158
+
159
+ def length; events.length end
160
+ def size; events.size end
161
+ end
162
+
163
+ class Event
164
+ def initialize(attrs)
165
+ @attrs = attrs
166
+ end
167
+
168
+ def ts
169
+ Fauna.time_from_usecs(@attrs['ts'])
170
+ end
171
+
172
+ def resource
173
+ @attrs['resource']
174
+ end
175
+
176
+ def set
177
+ @attrs['set']
178
+ end
179
+
180
+ def action
181
+ @attrs['action']
182
+ end
183
+ end
184
+ end
data/lib/fauna/util.rb ADDED
@@ -0,0 +1,19 @@
1
+ module Fauna
2
+ def self.stringify_keys!(hash)
3
+ hash.keys.each do |k|
4
+ hash[k.to_s] = hash.delete k
5
+ end
6
+ end
7
+
8
+ def self.stringify_keys(hash)
9
+ stringify_keys!(hash.dup)
10
+ end
11
+
12
+ def self.time_from_usecs(microseconds)
13
+ Time.at(microseconds/1_000_000, microseconds % 1_000_000)
14
+ end
15
+
16
+ def self.usecs_from_time(time)
17
+ time.to_i * 1000000 + time.usec
18
+ end
19
+ end
data/lib/tasks/fauna.rake CHANGED
@@ -2,10 +2,70 @@
2
2
  task :environment
3
3
 
4
4
  namespace :fauna do
5
- desc "Migrate your fauna database to the latest version"
5
+ desc "Migrate your Fauna database to the latest version of your schema"
6
6
  task :migrate => :environment do
7
+ puts "Migrating #{Rails.env} Fauna database schema"
7
8
  Fauna::Client.context(Fauna.connection) do
8
9
  Fauna.migrate_schema!
9
10
  end
10
11
  end
12
+
13
+ desc "Completely reset your Fauna database"
14
+ task :reset => :environment do
15
+ if Rails.env.production?
16
+ puts "Won't reset #{Rails.env} Fauna database"
17
+ else
18
+ Fauna::Client.context(Fauna.root_connection) do
19
+ puts "Resetting #{Rails.env} Fauna database"
20
+ Fauna::Client.delete("everything")
21
+ end
22
+ Fauna.auth!
23
+ end
24
+ end
25
+
26
+ desc "Dump the contents of your Fauna database to 'test/fixtures/fauna'"
27
+ task :dump => :environment do
28
+ puts "Dumping #{Rails.env} Fauna database contents to #{Fauna::FIXTURES_DIR}"
29
+ Fauna::Client.context(Fauna.connection) do
30
+ FileUtils.mkdir_p(Fauna::FIXTURES_DIR)
31
+
32
+ class_configs = Fauna.connection.get("/classes")["references"] || {}
33
+ class_configs["users"] = nil
34
+
35
+ Dir.chdir(Fauna::FIXTURES_DIR) do
36
+ class_configs.each do |ref, value|
37
+ class_name = ref[0..-8]
38
+ FileUtils.mkdir_p(class_name)
39
+
40
+ Dir.chdir(class_name) do
41
+ # FIXME shouldn't round trip JSON
42
+ File.open("config.json", "w") { |f| f.write(value.to_json)} if value
43
+ (Fauna.connection.get(class_name)["references"] || {}).each do |ref, value|
44
+ File.open("#{ref.split("/").last}.json", "w") { |f| f.write(value.to_json) }
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ desc "Load the contents of your Fauna database"
53
+ task :load => :environment do
54
+ puts "Loading #{Rails.env} Fauna database contents from #{Fauna::FIXTURES_DIR}"
55
+ Fauna::Client.context(Fauna.connection) do
56
+ Dir.chdir(Fauna::FIXTURES_DIR) do
57
+ Dir["**/*.json"].map do |filename|
58
+ value = JSON.parse(File.open(filename) { |f| f.read })
59
+ begin
60
+ Fauna.connection.put(value["ref"], value)
61
+ rescue Fauna::Connection::NotFound
62
+ Fauna.connection.post(value["ref"].split("/")[0..-2].join("/"), value)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+
11
69
  end
70
+
71
+ task :test => ["fauna:reset", "fauna:migrate", "fauna:load"]
data/test/class_test.rb CHANGED
@@ -1,111 +1,82 @@
1
1
  require File.expand_path('../test_helper', __FILE__)
2
2
 
3
- class ClassTest < ActiveModel::TestCase
4
- include ActiveModel::Lint::Tests
3
+ class InstanceTest < MiniTest::Unit::TestCase
5
4
 
6
5
  def setup
7
6
  super
8
- @model = Pig.new
9
- end
10
-
11
- def test_class_name
12
- assert_equal 'classes/pigs', Pig.fauna_class
13
- assert_equal 'classes/pigs/config', Pig.config_ref
14
- end
15
-
16
- def test_class_save
17
- Pig.update_data! do |data|
18
- data["class_visited"] = true
19
- end
20
- assert Pig.data["class_visited"]
7
+ @model = Fauna::Resource.new('classes/pigs')
21
8
  end
22
9
 
23
10
  def test_create
24
- pig = Pig.create(:visited => false)
25
- assert_equal false, pig.visited
11
+ pig = Fauna::Resource.create 'classes/pigs', :data => { :visited => true }
12
+ assert_equal true, pig.data['visited']
26
13
  assert pig.persisted?
27
14
  assert pig.ref
28
15
  end
29
16
 
30
17
  def test_all
31
- pig = Pig.create
32
- assert Pig.all.resources.include?(pig)
18
+ pig = Fauna::Resource.create 'classes/pigs'
19
+ assert Fauna::Set.new('classes/pigs/instances').page.include?(pig.ref)
33
20
  end
34
21
 
35
22
  def test_save
36
- pig = Pig.new
23
+ pig = Fauna::Resource.new 'classes/pigs'
37
24
  pig.save
38
25
  assert pig.persisted?
39
26
  end
40
27
 
41
28
  def test_update
42
- pig = Pig.new(:visited => false)
29
+ pig = Fauna::Resource.new 'classes/pigs', :data => { :visited => false }
43
30
  pig.save
44
- pig.update(:visited => true)
45
- assert pig.visited
46
- end
47
-
48
- def test_changes
49
- pig = Pig.new(:visited => true)
31
+ pig.data['visited'] = true
50
32
  pig.save
51
- pig.update(:visited => false)
52
- assert_equal pig.changes.page.events.length, 2
53
- end
54
33
 
55
- def test_find_by_ref
56
- pig = Pig.create
57
- pig1 = Pig.find_by_ref(pig.ref)
58
- assert_equal pig.ref, pig1.ref
59
- assert pig1.persisted?
34
+ assert pig.data['visited']
35
+ assert_equal pig.events.length, 2
60
36
  end
61
37
 
62
- def test_find_by_unique_id
63
- pig = Pig.create(:unique_id => "the pig")
64
- pig1 = Pig.find_by_unique_id("the pig")
38
+ def test_find
39
+ pig = Fauna::Resource.create 'classes/pigs'
40
+ pig1 = Fauna::Resource.find(pig.ref)
65
41
  assert_equal pig.ref, pig1.ref
66
42
  assert pig1.persisted?
67
43
  end
68
44
 
69
- def test_find
70
- pig = Pig.create
71
-
72
- pig1 = Pig.find(pig.id)
45
+ def test_find_by_constraint
46
+ pig = Fauna::Resource.create 'classes/pigs', :constraints => { :name => "the pig" }
47
+ pig1 = Fauna::Resource.find('classes/pigs/constraints/name/the%20pig')
73
48
  assert_equal pig.ref, pig1.ref
74
49
  assert pig1.persisted?
75
-
76
- pig2 = Pig.find_by_id(pig.id)
77
- assert_equal pig.ref, pig2.ref
78
- assert pig2.persisted?
79
50
  end
80
51
 
81
- def test_destroy
82
- pig = Pig.create
83
- pig.destroy
84
- assert pig.destroyed?
52
+ def test_delete
53
+ pig = Fauna::Resource.create 'classes/pigs'
54
+ pig.delete
55
+ assert pig.deleted?
85
56
  end
86
57
 
87
58
  def test_ts
88
- pig = Pig.create
59
+ pig = Fauna::Resource.create 'classes/pigs'
89
60
  assert_instance_of(Time, pig.ts)
90
61
 
91
- pig = Pig.new
62
+ pig = Fauna::Resource.new 'classes/pigs'
92
63
  assert_nil pig.ts
93
64
  end
94
65
 
95
66
  def test_ts_assignment
96
67
  time = Time.at(0)
97
- pig = Pig.create
68
+ pig = Fauna::Resource.create 'classes/pigs'
98
69
  pig.ts = time
99
70
 
100
- Fauna::Client.context(@publisher_connection) do
101
- pig2 = Pig.find(pig.id)
102
- assert_not_equal time, pig2.ts
71
+ Fauna::Client.context(@server_connection) do
72
+ pig2 = Fauna::Resource.find(pig.ref)
73
+ assert(time != pig2.ts)
103
74
  end
104
75
 
105
76
  pig.save
106
77
 
107
- Fauna::Client.context(@publisher_connection) do
108
- pig3 = Pig.find(pig.id)
78
+ Fauna::Client.context(@server_connection) do
79
+ pig3 = Fauna::Resource.find(pig.ref)
109
80
  # Waiting on server support for timestamp overrides
110
81
  # assert_equal time, pig3.ts
111
82
  end
data/test/client_test.rb CHANGED
@@ -6,17 +6,17 @@ class ClientTest < MiniTest::Unit::TestCase
6
6
  @attributes = { "name" => "Princess Eilonwy", "email" => email, "password" => password }
7
7
  end
8
8
 
9
- def test_publisher_context
10
- Fauna::Client.context(@publisher_connection) do
9
+ def test_database_context
10
+ Fauna::Client.context(@server_connection) do
11
11
  user = Fauna::Client.post("users", @attributes)
12
- user = Fauna::Client.get(user.ref)
13
- Fauna::Client.delete(user.ref)
12
+ user = Fauna::Client.get(user['ref'])
13
+ Fauna::Client.delete(user['ref'])
14
14
  end
15
15
  end
16
16
 
17
17
  def test_client_context
18
18
  Fauna::Client.context(@client_connection) do
19
- user = Fauna::Client.post("users", @attributes)
19
+ user = Fauna::Resource.create("users", @attributes)
20
20
  Fauna::Client.context(@client_connection) do
21
21
  assert_raises(Fauna::Connection::Unauthorized) do
22
22
  Fauna::Client.get(user.ref)
@@ -26,7 +26,7 @@ class ClientTest < MiniTest::Unit::TestCase
26
26
  end
27
27
 
28
28
  def test_token_context
29
- Fauna::Client.context(@publisher_connection) do
29
+ Fauna::Client.context(@server_connection) do
30
30
  Fauna::Client.post("users", @attributes)
31
31
  end
32
32
 
@@ -34,28 +34,28 @@ class ClientTest < MiniTest::Unit::TestCase
34
34
  @token = Fauna::Client.post("tokens", @attributes)
35
35
  end
36
36
 
37
- Fauna::Client.context(Fauna::Connection.new(:token => @token.token)) do
38
- user = Fauna::Client.get(@token.user)
39
- Fauna::Client.delete(user.ref)
37
+ Fauna::Client.context(Fauna::Connection.new(:secret => @token['secret'], :domain => @server_connection.domain, :scheme => @server_connection.scheme)) do
38
+ user = Fauna::Client.get(@token['user'])
39
+ Fauna::Client.delete(user['ref'])
40
40
  end
41
41
  end
42
42
 
43
43
  def test_caching_1
44
- Fauna::Client.context(@publisher_connection) do
45
- @user = Fauna::Client.post("users", @attributes)
46
- @publisher_connection.expects(:get).never
47
- Fauna::Client.get(@user.ref)
44
+ Fauna::Client.context(@server_connection) do
45
+ user = Fauna::Client.post("users", @attributes)
46
+ @server_connection.expects(:get).never
47
+ Fauna::Client.get(user['ref'])
48
48
  end
49
49
  end
50
50
 
51
51
  def test_caching_2
52
52
  Fauna::Client.context(@client_connection) do
53
- @user = Fauna::Client.post("users", @attributes)
53
+ user = Fauna::Client.post("users", @attributes)
54
54
 
55
- Fauna::Client.context(@publisher_connection) do
56
- Fauna::Client.get(@user.ref)
57
- @publisher_connection.expects(:get).never
58
- Fauna::Client.get(@user.ref)
55
+ Fauna::Client.context(@server_connection) do
56
+ Fauna::Client.get(user['ref'])
57
+ @server_connection.expects(:get).never
58
+ Fauna::Client.get(user['ref'])
59
59
  end
60
60
  end
61
61
  end