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/CHANGELOG +2 -0
- data/Manifest +0 -31
- data/README.md +18 -150
- data/Rakefile +1 -1
- data/examples/welcome.rb +3 -3
- data/fauna.gemspec +5 -11
- data/lib/fauna.rb +11 -88
- data/lib/fauna/cache.rb +58 -0
- data/lib/fauna/client.rb +14 -67
- data/lib/fauna/connection.rb +21 -27
- data/lib/fauna/provided_classes.rb +39 -0
- data/lib/fauna/rails.rb +28 -8
- data/lib/fauna/resource.rb +34 -121
- data/lib/fauna/set.rb +184 -0
- data/lib/fauna/util.rb +19 -0
- data/lib/tasks/fauna.rake +61 -1
- data/test/class_test.rb +29 -58
- data/test/client_test.rb +18 -18
- data/test/connection_test.rb +8 -8
- data/test/database_test.rb +47 -0
- data/test/readme_test.rb +2 -3
- data/test/set_test.rb +94 -0
- data/test/test_helper.rb +27 -15
- metadata +14 -57
- data/lib/fauna/ddl.rb +0 -157
- data/lib/fauna/event_set.rb +0 -197
- data/lib/fauna/model.rb +0 -73
- data/lib/fauna/model/class.rb +0 -32
- data/lib/fauna/model/user.rb +0 -23
- data/lib/fauna/publisher.rb +0 -8
- data/test/association_test.rb +0 -23
- data/test/event_set_test.rb +0 -92
- data/test/fixtures.rb +0 -70
- data/test/publisher_test.rb +0 -48
- data/test/user_test.rb +0 -80
- data/test/validation_test.rb +0 -28
data/lib/fauna/cache.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Fauna
|
2
|
+
class NoContextError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class Cache
|
6
|
+
attr_reader :connection
|
7
|
+
|
8
|
+
def initialize(connection)
|
9
|
+
raise ArgumentError, "Connection cannot be nil" unless connection
|
10
|
+
@cache = {}
|
11
|
+
@connection = connection
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(ref, query = {}, pagination = {})
|
15
|
+
res = @cache[ref]
|
16
|
+
res = @cache[res] if res.is_a? String # non-canonical refs point to their canonical refs.
|
17
|
+
|
18
|
+
if res.nil?
|
19
|
+
response = @connection.get(ref, query.merge(pagination))
|
20
|
+
update_cache(ref, response)
|
21
|
+
res = response['resource']
|
22
|
+
end
|
23
|
+
|
24
|
+
res
|
25
|
+
end
|
26
|
+
|
27
|
+
def post(ref, data)
|
28
|
+
res = @connection.post(ref, data)
|
29
|
+
update_cache(ref, res)
|
30
|
+
res['resource']
|
31
|
+
end
|
32
|
+
|
33
|
+
def put(ref, data)
|
34
|
+
res = @connection.put(ref, data)
|
35
|
+
if res['resource']
|
36
|
+
update_cache(ref, res)
|
37
|
+
res['resource']
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete(ref, data)
|
42
|
+
@connection.delete(ref, data)
|
43
|
+
@cache.delete(ref)
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def update_cache(ref, res)
|
50
|
+
# FIXME Implement set range caching
|
51
|
+
if (res['resource']['class'] != "resources" && res['resource']['class'] != "events")
|
52
|
+
@cache[ref] = res['resource']['ref'] # store the non-canonical ref as a pointer to the real one.
|
53
|
+
@cache[res['resource']['ref']] = res['resource']
|
54
|
+
end
|
55
|
+
@cache.merge!(res['references'] || {})
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/fauna/client.rb
CHANGED
@@ -1,62 +1,5 @@
|
|
1
1
|
module Fauna
|
2
2
|
class Client
|
3
|
-
|
4
|
-
class NoContextError < StandardError
|
5
|
-
end
|
6
|
-
|
7
|
-
class CachingContext
|
8
|
-
attr_reader :connection
|
9
|
-
|
10
|
-
def initialize(connection)
|
11
|
-
raise ArgumentError, "Connection cannot be nil" unless connection
|
12
|
-
@cache = {}
|
13
|
-
@connection = connection
|
14
|
-
end
|
15
|
-
|
16
|
-
def get(ref, query = nil)
|
17
|
-
if @cache[ref]
|
18
|
-
Resource.alloc(@cache[ref])
|
19
|
-
else
|
20
|
-
res = @connection.get(ref, query)
|
21
|
-
cohere(ref, res)
|
22
|
-
Resource.alloc(res['resource'])
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def post(ref, data)
|
27
|
-
res = @connection.post(ref, filter(data))
|
28
|
-
cohere(ref, res)
|
29
|
-
Resource.alloc(res['resource'])
|
30
|
-
end
|
31
|
-
|
32
|
-
def put(ref, data)
|
33
|
-
res = @connection.put(ref, filter(data))
|
34
|
-
cohere(ref, res)
|
35
|
-
Resource.alloc(res['resource'])
|
36
|
-
end
|
37
|
-
|
38
|
-
def delete(ref, data)
|
39
|
-
@connection.delete(ref, data)
|
40
|
-
@cache.delete(ref)
|
41
|
-
nil
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def filter(data)
|
47
|
-
data.select {|_, v| v }
|
48
|
-
end
|
49
|
-
|
50
|
-
def cohere(ref, res)
|
51
|
-
# FIXME Implement set range caching
|
52
|
-
if (res['resource']['class'] != "sets")
|
53
|
-
@cache[ref] = res['resource'] if ref =~ %r{^users/self}
|
54
|
-
@cache[res['resource']['ref']] = res['resource']
|
55
|
-
@cache.merge!(res['references'] || {})
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
3
|
def self.context(connection)
|
61
4
|
push_context(connection)
|
62
5
|
yield
|
@@ -65,30 +8,34 @@ module Fauna
|
|
65
8
|
end
|
66
9
|
|
67
10
|
def self.push_context(connection)
|
68
|
-
stack.push(
|
11
|
+
stack.push(Fauna::Cache.new(connection))
|
69
12
|
end
|
70
13
|
|
71
14
|
def self.pop_context
|
72
15
|
stack.pop
|
73
16
|
end
|
74
17
|
|
75
|
-
def self.
|
76
|
-
|
18
|
+
def self.reset_context
|
19
|
+
stack = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.get(ref, query = {}, pagination = {})
|
23
|
+
connection.get(ref, query, pagination)
|
77
24
|
end
|
78
25
|
|
79
|
-
def self.post(ref, data =
|
80
|
-
|
26
|
+
def self.post(ref, data = {})
|
27
|
+
connection.post(ref, data)
|
81
28
|
end
|
82
29
|
|
83
|
-
def self.put(ref, data =
|
84
|
-
|
30
|
+
def self.put(ref, data = {})
|
31
|
+
connection.put(ref, data)
|
85
32
|
end
|
86
33
|
|
87
|
-
def self.delete(ref, data =
|
88
|
-
|
34
|
+
def self.delete(ref, data = {})
|
35
|
+
connection.delete(ref, data)
|
89
36
|
end
|
90
37
|
|
91
|
-
def self.
|
38
|
+
def self.connection
|
92
39
|
stack.last or raise NoContextError, "You must be within a Fauna::Client.context block to perform operations."
|
93
40
|
end
|
94
41
|
|
data/lib/fauna/connection.rb
CHANGED
@@ -33,9 +33,12 @@ module Fauna
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
attr_reader :domain, :scheme
|
37
|
+
|
36
38
|
def initialize(params={})
|
37
39
|
@logger = params[:logger] || nil
|
38
|
-
@
|
40
|
+
@domain = params[:domain] || "rest1.fauna.org"
|
41
|
+
@scheme = params[:scheme] || "https"
|
39
42
|
|
40
43
|
if ENV["FAUNA_DEBUG"]
|
41
44
|
@logger = Logger.new(STDERR)
|
@@ -44,38 +47,32 @@ module Fauna
|
|
44
47
|
|
45
48
|
# Check credentials from least to most privileged, in case
|
46
49
|
# multiple were provided
|
47
|
-
@credentials = if params[:
|
48
|
-
CGI.escape(
|
49
|
-
elsif params[:client_key]
|
50
|
-
CGI.escape(params[:client_key])
|
51
|
-
elsif params[:publisher_key]
|
52
|
-
CGI.escape(params[:publisher_key])
|
53
|
-
elsif params[:email] and params[:password]
|
54
|
-
"#{CGI.escape(params[:email])}:#{CGI.escape(params[:password])}"
|
50
|
+
@credentials = if params[:secret]
|
51
|
+
CGI.escape(params[:secret])
|
55
52
|
else
|
56
53
|
raise TypeError
|
57
54
|
end
|
58
55
|
rescue TypeError
|
59
|
-
raise ArgumentError, "
|
56
|
+
raise ArgumentError, "Invalid secret."
|
60
57
|
end
|
61
58
|
|
62
|
-
def get(ref, query =
|
59
|
+
def get(ref, query = {})
|
63
60
|
parse(execute(:get, ref, nil, query))
|
64
61
|
end
|
65
62
|
|
66
|
-
def post(ref, data =
|
63
|
+
def post(ref, data = {})
|
67
64
|
parse(execute(:post, ref, data))
|
68
65
|
end
|
69
66
|
|
70
|
-
def put(ref, data =
|
67
|
+
def put(ref, data = {})
|
71
68
|
parse(execute(:put, ref, data))
|
72
69
|
end
|
73
70
|
|
74
|
-
def patch(ref, data =
|
71
|
+
def patch(ref, data = {})
|
75
72
|
parse(execute(:patch, ref, data))
|
76
73
|
end
|
77
74
|
|
78
|
-
def delete(ref, data =
|
75
|
+
def delete(ref, data = {})
|
79
76
|
execute(:delete, ref, data)
|
80
77
|
nil
|
81
78
|
end
|
@@ -83,12 +80,8 @@ module Fauna
|
|
83
80
|
private
|
84
81
|
|
85
82
|
def parse(response)
|
86
|
-
obj =
|
87
|
-
|
88
|
-
else
|
89
|
-
JSON.parse(response)
|
90
|
-
end
|
91
|
-
obj.merge!("headers" => response.headers.stringify_keys)
|
83
|
+
obj = response.empty? ? {} : JSON.parse(response)
|
84
|
+
obj.merge! "headers" => Fauna.stringify_keys(response.headers)
|
92
85
|
obj
|
93
86
|
end
|
94
87
|
|
@@ -101,7 +94,7 @@ module Fauna
|
|
101
94
|
end
|
102
95
|
|
103
96
|
def query_string_for_logging(query)
|
104
|
-
if query
|
97
|
+
if query && !query.empty?
|
105
98
|
"?" + query.map do |k,v|
|
106
99
|
"#{k}=#{v}"
|
107
100
|
end.join("&")
|
@@ -111,17 +104,18 @@ module Fauna
|
|
111
104
|
def execute(action, ref, data = nil, query = nil)
|
112
105
|
args = { :method => action, :url => url(ref), :headers => {} }
|
113
106
|
|
114
|
-
if query
|
107
|
+
if query && !query.empty?
|
115
108
|
args[:headers].merge! :params => query
|
116
109
|
end
|
117
110
|
|
118
|
-
if data
|
111
|
+
if data && !data.empty?
|
119
112
|
args[:headers].merge! :content_type => :json
|
120
113
|
args.merge! :payload => data.to_json
|
121
114
|
end
|
122
115
|
|
123
116
|
if @logger
|
124
|
-
log(2) { "Fauna #{action.to_s.upcase}
|
117
|
+
log(2) { "Fauna #{action.to_s.upcase} /#{ref}#{query_string_for_logging(query)}" }
|
118
|
+
log(4) { "Credentials: #{@credentials}" } if @debug
|
125
119
|
log(4) { "Request JSON: #{JSON.pretty_generate(data)}" } if @debug && data
|
126
120
|
|
127
121
|
t0, r0 = Process.times, Time.now
|
@@ -131,7 +125,7 @@ module Fauna
|
|
131
125
|
real = r1.to_f - r0.to_f
|
132
126
|
cpu = (t1.utime - t0.utime) + (t1.stime - t0.stime) + (t1.cutime - t0.cutime) + (t1.cstime - t0.cstime)
|
133
127
|
log(4) { ["Response headers: #{JSON.pretty_generate(res.headers)}", "Response JSON: #{res}"] } if @debug
|
134
|
-
log(4) { "Response (#{res.code}): API processing #{res.headers[:
|
128
|
+
log(4) { "Response (#{res.code}): API processing #{res.headers[:x_http_request_processing_time]}ms, network latency #{((real - cpu)*1000).to_i}ms, local processing #{(cpu*1000).to_i}ms" }
|
135
129
|
|
136
130
|
HANDLER.call(res)
|
137
131
|
end
|
@@ -141,7 +135,7 @@ module Fauna
|
|
141
135
|
end
|
142
136
|
|
143
137
|
def url(ref)
|
144
|
-
"
|
138
|
+
"#{@scheme}://#{@credentials}@#{@domain}/#{ref}"
|
145
139
|
end
|
146
140
|
end
|
147
141
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Fauna
|
2
|
+
class NamedResource < Fauna::Resource
|
3
|
+
def name; struct['name'] end
|
4
|
+
|
5
|
+
def ref; super || "#{fauna_class}/#{name}" end
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def post
|
10
|
+
raise Invalid, "Cannot POST to named resource."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Database < Fauna::NamedResource
|
15
|
+
def self.new(*args); super('databases', *args) end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Class < Fauna::NamedResource
|
19
|
+
def self.new(*args); super('classes', *args) end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Key < Fauna::Resource
|
23
|
+
def self.new(*args); super('keys', *args) end
|
24
|
+
|
25
|
+
def database
|
26
|
+
struct['database'] || ref.split('/keys').first
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def post
|
32
|
+
Fauna::Client.post("#{database}/keys", struct)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Token < Fauna::Resource
|
37
|
+
def self.new(*args); super('tokens', *args) end
|
38
|
+
end
|
39
|
+
end
|
data/lib/fauna/rails.rb
CHANGED
@@ -9,9 +9,10 @@ if defined?(Rails)
|
|
9
9
|
|
10
10
|
@silent = false
|
11
11
|
|
12
|
-
CONFIG_FILE = "#{Rails.root}/
|
12
|
+
CONFIG_FILE = "#{Rails.root}/fauna.yml"
|
13
13
|
LOCAL_CONFIG_FILE = "#{ENV["HOME"]}/.fauna.yml"
|
14
14
|
APP_NAME = Rails.application.class.name.split("::").first.underscore
|
15
|
+
FIXTURES_DIR = "#{Rails.root}/test/fixtures/fauna"
|
15
16
|
|
16
17
|
def self.auth!
|
17
18
|
if File.exist? CONFIG_FILE
|
@@ -22,8 +23,8 @@ if defined?(Rails)
|
|
22
23
|
end
|
23
24
|
|
24
25
|
if !@silent
|
25
|
-
if credentials["
|
26
|
-
STDERR.puts ">> Using Fauna
|
26
|
+
if credentials["server_key"]
|
27
|
+
STDERR.puts ">> Using Fauna server key #{credentials["server_key"].inspect} for #{APP_NAME.inspect}."
|
27
28
|
else
|
28
29
|
STDERR.puts ">> Using Fauna account #{credentials["email"].inspect} for #{APP_NAME.inspect}."
|
29
30
|
end
|
@@ -31,18 +32,18 @@ if defined?(Rails)
|
|
31
32
|
STDERR.puts ">> You can change this in config/fauna.yml or ~/.fauna.yml."
|
32
33
|
end
|
33
34
|
|
34
|
-
if credentials["
|
35
|
-
|
35
|
+
if credentials["server_key"]
|
36
|
+
server_key = credentials["server_key"]
|
36
37
|
else
|
37
38
|
self.root_connection = Connection.new(
|
38
39
|
:email => credentials["email"],
|
39
40
|
:password => credentials["password"],
|
40
41
|
:logger => Rails.logger)
|
41
42
|
|
42
|
-
|
43
|
+
server_key = root_connection.post("keys", "role" => "server")["resource"]["key"]
|
43
44
|
end
|
44
45
|
|
45
|
-
self.connection = Connection.new(
|
46
|
+
self.connection = Connection.new(server_key: server_key, logger: Rails.logger)
|
46
47
|
else
|
47
48
|
if !@silent
|
48
49
|
STDERR.puts ">> Fauna account not configured. You can add one in config/fauna.yml."
|
@@ -74,7 +75,6 @@ if defined?(Rails)
|
|
74
75
|
def self.install_reload_callback!
|
75
76
|
if defined? ActionDispatch::Reloader
|
76
77
|
ActionDispatch::Reloader.to_prepare do
|
77
|
-
Fauna.configure_schema!
|
78
78
|
Fauna.install_around_filter!
|
79
79
|
end
|
80
80
|
end
|
@@ -89,10 +89,30 @@ if defined?(Rails)
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
end
|
92
|
+
|
93
|
+
def self.install_test_helper!
|
94
|
+
if defined? ActiveSupport::TestCase
|
95
|
+
ActiveSupport::TestCase.setup do
|
96
|
+
Fauna::Client.push_context(Fauna.connection)
|
97
|
+
end
|
98
|
+
|
99
|
+
ActiveSupport::TestCase.teardown do
|
100
|
+
Fauna::Client.pop_context
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.install_console_helper!
|
106
|
+
Rails.application.class.console do
|
107
|
+
Fauna::Client.push_context(Fauna.connection)
|
108
|
+
end
|
109
|
+
end
|
92
110
|
end
|
93
111
|
|
94
112
|
Fauna.auth!
|
95
113
|
Fauna.install_around_filter!
|
96
114
|
Fauna.install_reload_callback!
|
97
115
|
Fauna.install_inflections!
|
116
|
+
Fauna.install_test_helper!
|
117
|
+
Fauna.install_console_helper!
|
98
118
|
end
|
data/lib/fauna/resource.rb
CHANGED
@@ -1,123 +1,66 @@
|
|
1
1
|
module Fauna
|
2
2
|
class Resource
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
attr_accessor :fauna_class
|
12
|
-
|
13
|
-
def fauna_class
|
14
|
-
@fauna_class or raise MissingMigration, "Class #{name} has not been added to Fauna.schema."
|
3
|
+
def self.resource_subclass(fauna_class)
|
4
|
+
case fauna_class
|
5
|
+
when 'databases' then Fauna::Database
|
6
|
+
when 'classes' then Fauna::Class
|
7
|
+
when 'keys' then Fauna::Key
|
8
|
+
when 'resources' then Fauna::SetPage
|
9
|
+
when 'events' then Fauna::EventsPage
|
10
|
+
else Fauna::Resource
|
15
11
|
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def field(*names)
|
20
|
-
names.each do |name|
|
21
|
-
name = name.to_s
|
22
|
-
fields << name
|
23
|
-
fields.uniq!
|
24
|
-
|
25
|
-
define_method(name) { data[name] }
|
26
|
-
define_method("#{name}=") { |value| data[name] = value }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def event_set(*names)
|
31
|
-
args = names.last.is_a?(Hash) ? names.pop : {}
|
32
|
-
|
33
|
-
names.each do |name|
|
34
|
-
set_name = args[:internal] ? name.to_s : "sets/#{name}"
|
35
|
-
event_sets << set_name
|
36
|
-
event_sets.uniq!
|
37
|
-
|
38
|
-
define_method(name.to_s) { Fauna::CustomEventSet.new("#{ref}/#{set_name}") }
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def reference(*names)
|
43
|
-
names.each do |name|
|
44
|
-
name = name.to_s
|
45
|
-
references << name
|
46
|
-
references.uniq!
|
47
|
-
|
48
|
-
define_method("#{name}_ref") { references[name] }
|
49
|
-
define_method("#{name}_ref=") { |ref| (ref.nil? || ref.empty?) ? references.delete(name) : references[name] = ref }
|
50
|
-
|
51
|
-
define_method(name) { Fauna::Resource.find_by_ref(references[name]) if references[name] }
|
52
|
-
define_method("#{name}=") { |obj| obj.nil? ? references.delete(name) : references[name] = obj.ref }
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# secondary index helper
|
57
|
-
|
58
|
-
def find_by(ref, query)
|
59
|
-
# TODO elimate direct manipulation of the connection
|
60
|
-
response = Fauna::Client.this.connection.get(ref, query)
|
61
|
-
response['resources'].map { |attributes| alloc(attributes) }
|
62
|
-
rescue Fauna::Connection::NotFound
|
63
|
-
[]
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.find_by_ref(ref, query = nil)
|
68
|
-
res = Fauna::Client.get(ref, query)
|
69
|
-
Fauna.class_for_name(res.fauna_class).alloc(res.to_hash)
|
70
12
|
end
|
71
13
|
|
72
|
-
def self.
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
def self.create!(*args)
|
77
|
-
new(*args).tap { |obj| obj.save! }
|
14
|
+
def self.hydrate(struct)
|
15
|
+
obj = resource_subclass(struct['class']).allocate
|
16
|
+
obj.instance_variable_set '@struct', struct
|
17
|
+
obj
|
78
18
|
end
|
79
19
|
|
80
|
-
def self.
|
81
|
-
obj = allocate
|
82
|
-
obj.instance_variable_set
|
20
|
+
def self.new(fauna_class, attrs = {})
|
21
|
+
obj = resource_subclass(fauna_class).allocate
|
22
|
+
obj.instance_variable_set '@struct', { 'ref' => nil, 'ts' => nil, 'deleted' => false, 'class' => fauna_class }
|
23
|
+
obj.send(:assign, attrs)
|
83
24
|
obj
|
84
25
|
end
|
85
26
|
|
86
|
-
def self.
|
87
|
-
|
27
|
+
def self.create(*args)
|
28
|
+
new(*args).tap(&:save)
|
88
29
|
end
|
89
30
|
|
90
|
-
def self.
|
91
|
-
|
31
|
+
def self.find(ref, query = {}, pagination = {})
|
32
|
+
hydrate(Fauna::Client.get(ref, query, pagination))
|
92
33
|
end
|
93
34
|
|
94
35
|
attr_reader :struct
|
95
36
|
|
96
37
|
alias :to_hash :struct
|
97
38
|
|
98
|
-
def initialize(attrs = {})
|
99
|
-
@struct = { 'ref' => nil, 'ts' => nil, 'deleted' => false }
|
100
|
-
assign(attrs)
|
101
|
-
end
|
102
|
-
|
103
39
|
def ts
|
104
|
-
struct['ts'] ?
|
40
|
+
struct['ts'] ? Fauna.time_from_usecs(struct['ts']) : nil
|
105
41
|
end
|
106
42
|
|
107
43
|
def ts=(time)
|
108
|
-
struct['ts'] =
|
44
|
+
struct['ts'] = Fauna.usecs_from_time(time)
|
109
45
|
end
|
110
46
|
|
111
47
|
def ref; struct['ref'] end
|
112
48
|
def fauna_class; struct['class'] end
|
113
49
|
def deleted; struct['deleted'] end
|
114
|
-
def
|
50
|
+
def constraints; struct['constraints'] ||= {} end
|
115
51
|
def data; struct['data'] ||= {} end
|
116
52
|
def references; struct['references'] ||= {} end
|
117
|
-
|
53
|
+
|
54
|
+
def events(pagination = {})
|
55
|
+
EventsPage.find("#{ref}/events", {}, pagination)
|
56
|
+
end
|
57
|
+
|
58
|
+
def set(name)
|
59
|
+
CustomSet.new("#{ref}/sets/#{CGI.escape(name)}")
|
60
|
+
end
|
118
61
|
|
119
62
|
def eql?(other)
|
120
|
-
self.
|
63
|
+
self.fauna_class == other.fauna_class && self.ref == other.ref && self.ref != nil
|
121
64
|
end
|
122
65
|
alias :== :eql?
|
123
66
|
|
@@ -143,34 +86,10 @@ module Fauna
|
|
143
86
|
|
144
87
|
def deleted?; deleted end
|
145
88
|
|
146
|
-
alias :destroyed? :deleted?
|
147
|
-
|
148
89
|
def persisted?; !(new_record? || deleted?) end
|
149
90
|
|
150
|
-
def errors
|
151
|
-
@errors ||= ActiveModel::Errors.new(self)
|
152
|
-
end
|
153
|
-
|
154
91
|
def save
|
155
92
|
@struct = (new_record? ? post : put).to_hash
|
156
|
-
true
|
157
|
-
rescue Fauna::Connection::BadRequest => e
|
158
|
-
e.param_errors.each { |field, message| errors[field] = message }
|
159
|
-
false
|
160
|
-
end
|
161
|
-
|
162
|
-
def save!
|
163
|
-
save || (raise Invalid, errors.full_messages)
|
164
|
-
end
|
165
|
-
|
166
|
-
def update(attributes = {})
|
167
|
-
assign(attributes)
|
168
|
-
save
|
169
|
-
end
|
170
|
-
|
171
|
-
def update!(attributes = {})
|
172
|
-
assign(attributes)
|
173
|
-
save!
|
174
93
|
end
|
175
94
|
|
176
95
|
def delete
|
@@ -178,16 +97,12 @@ module Fauna
|
|
178
97
|
struct['deleted'] = true
|
179
98
|
struct.freeze
|
180
99
|
nil
|
181
|
-
rescue Fauna::Connection::NotAllowed
|
182
|
-
raise Invalid, "This resource can not be destroyed."
|
183
100
|
end
|
184
101
|
|
185
|
-
alias :destroy :delete
|
186
|
-
|
187
102
|
private
|
188
103
|
|
189
104
|
# TODO: make this configurable, and possible to invert to a white list
|
190
|
-
UNASSIGNABLE_ATTRIBUTES = %w(
|
105
|
+
UNASSIGNABLE_ATTRIBUTES = %w(ts deleted fauna_class).inject({}) { |h, attr| h.update attr => true }
|
191
106
|
|
192
107
|
def assign(attributes)
|
193
108
|
attributes.each do |name, val|
|
@@ -197,12 +112,10 @@ module Fauna
|
|
197
112
|
|
198
113
|
def put
|
199
114
|
Fauna::Client.put(ref, struct)
|
200
|
-
rescue Fauna::Connection::NotAllowed
|
201
|
-
raise Invalid, "This resource type can not be updated."
|
202
115
|
end
|
203
116
|
|
204
117
|
def post
|
205
|
-
|
118
|
+
Fauna::Client.post(fauna_class, struct)
|
206
119
|
end
|
207
120
|
|
208
121
|
def getter_method(method)
|