arcadedb 0.3.1 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +57 -0
- data/CHANGELOG.md +19 -0
- data/Gemfile +25 -0
- data/Gemfile.lock +186 -0
- data/Guardfile +30 -0
- data/LICENSE +21 -0
- data/README.md +242 -0
- data/Rakefile +11 -0
- data/arcade.yml +23 -0
- data/arcadedb.gemspec +32 -0
- data/bin/+ +106 -0
- data/bin/console +126 -0
- data/examples/books.rb +139 -0
- data/examples/relation_1__1.rb +149 -0
- data/examples/relation_1__n.rb +56 -0
- data/examples/relation_n_n.rb +194 -0
- data/lib/arcade/api/operations.rb +257 -0
- data/lib/arcade/api/primitives.rb +98 -0
- data/lib/arcade/base.rb +454 -0
- data/lib/arcade/database.rb +367 -0
- data/lib/arcade/errors.rb +71 -0
- data/lib/arcade/logging.rb +38 -0
- data/lib/arcade/version.rb +3 -0
- data/lib/arcade.rb +36 -0
- data/lib/config.rb +72 -0
- data/lib/init.rb +50 -0
- data/lib/match.rb +216 -0
- data/lib/model/basicdocument.rb +7 -0
- data/lib/model/basicedge.rb +6 -0
- data/lib/model/basicvertex.rb +6 -0
- data/lib/model/document.rb +10 -0
- data/lib/model/edge.rb +47 -0
- data/lib/model/vertex.rb +238 -0
- data/lib/models.rb +6 -0
- data/lib/query.rb +384 -0
- data/lib/support/class.rb +13 -0
- data/lib/support/conversions.rb +295 -0
- data/lib/support/model.rb +87 -0
- data/lib/support/object.rb +20 -0
- data/lib/support/sql.rb +74 -0
- data/lib/support/string.rb +116 -0
- data/rails/arcade.rb +20 -0
- data/rails/config.yml +10 -0
- data/rails/connect.yml +17 -0
- data/rails.md +147 -0
- metadata +64 -5
@@ -0,0 +1,367 @@
|
|
1
|
+
module Arcade
|
2
|
+
##
|
3
|
+
# Implements the Database-Adapter
|
4
|
+
#
|
5
|
+
# currently, only attributes of type String are supported
|
6
|
+
#
|
7
|
+
# {Database-instance}.database points to the connected Aradedb-database
|
8
|
+
# DB.hi
|
9
|
+
#
|
10
|
+
##
|
11
|
+
class Database
|
12
|
+
include Logging
|
13
|
+
extend Dry::Core::ClassAttributes
|
14
|
+
include Support::Model # provides allocate_model
|
15
|
+
|
16
|
+
defines :namespace
|
17
|
+
defines :environment
|
18
|
+
|
19
|
+
def initialize environment=:development
|
20
|
+
self.class.configure_logger( Config.logger )
|
21
|
+
@connection = connect environment
|
22
|
+
if self.class.environment.nil? # class attribute is set on the first call
|
23
|
+
# further instances of Database share the same environment
|
24
|
+
self.class.environment environment
|
25
|
+
end
|
26
|
+
self.class.namespace Object.const_get( Config.namespace )
|
27
|
+
end
|
28
|
+
|
29
|
+
def database
|
30
|
+
@database ||= Config.database[self.class.environment]
|
31
|
+
end
|
32
|
+
|
33
|
+
# ------------ types ------------...
|
34
|
+
# returns an Array of type-attributes
|
35
|
+
# [{:name=>"Account", :type=>"document"},
|
36
|
+
# {:name=>"test", :type=>"vertex"},
|
37
|
+
# {:name=>"test1", :type=>"vertex"},
|
38
|
+
# {:parentTypes=>["test1"], :name=>"test2", :type=>"vertex"}]
|
39
|
+
#
|
40
|
+
def types refresh=false
|
41
|
+
# uses API
|
42
|
+
if $types.nil? || refresh
|
43
|
+
$types = Api.query(database, "select from schema:types" )
|
44
|
+
.map{ |x| x.transform_keys &:to_sym } # symbolize keys
|
45
|
+
.map{ |y| y.delete_if{|_,b,| b.empty? } } # eliminate empty entries
|
46
|
+
end
|
47
|
+
$types
|
48
|
+
## upom startup, this is the first access to the database-server
|
49
|
+
rescue NoMethodError => e
|
50
|
+
logger.fatal "Could not read Database Types. \n Is the database running?"
|
51
|
+
Kernel.exit
|
52
|
+
end
|
53
|
+
|
54
|
+
def indexes
|
55
|
+
DB.types.find{|x| x.key? :indexes }[:indexes]
|
56
|
+
end
|
57
|
+
|
58
|
+
# ------------ hierarchy -------------
|
59
|
+
# returns an Array of types
|
60
|
+
#
|
61
|
+
# each entry is an Array
|
62
|
+
# => [["test"], ["test1", "test2"]] (using the example above)
|
63
|
+
#
|
64
|
+
# Parameter: type -- one of 'vertex', 'document', 'edge'
|
65
|
+
def hierarchy type: 'vertex'
|
66
|
+
# uses API
|
67
|
+
# gets all types depending on the parent-type
|
68
|
+
pt = ->( s ) { types.find_all{ |x| x[:parentTypes] &.include?(s) }.map{ |v| v[:name] } }
|
69
|
+
# takes an array of base-types. gets recursivly all childs
|
70
|
+
child_types = -> (base_types) do
|
71
|
+
base_types.map do | bt |
|
72
|
+
if pt[ bt ].empty?
|
73
|
+
[ bt ]
|
74
|
+
else
|
75
|
+
[bt, child_types[ pt[ bt ] ] ].flatten
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# gets child-types for all base-types
|
81
|
+
child_types[ types.find_all{ |x| !x[:parentTypes] && x[:type] == type.to_s }.map{ |v| v[:name] } ]
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# ------------ create type -----------
|
87
|
+
# returns an Array
|
88
|
+
# Example: > create_type :vertex, :my_vertex
|
89
|
+
# => [{"typeName"=>"my_vertex", "operation"=>"create vertex type"}]
|
90
|
+
#
|
91
|
+
# takes additional arguments: extends: '<a supertype>' (for inheritance)
|
92
|
+
# bucket: <a list of bucket-id's >
|
93
|
+
# buckets: <how many bukets to assign>
|
94
|
+
#
|
95
|
+
# additional arguments are just added to the command
|
96
|
+
#
|
97
|
+
# its aliased as `create_class`
|
98
|
+
#
|
99
|
+
def create_type kind, type, **args
|
100
|
+
|
101
|
+
exe = -> do
|
102
|
+
case kind.to_s.downcase
|
103
|
+
when /^v/
|
104
|
+
"create vertex type #{type} "
|
105
|
+
when /^d/
|
106
|
+
"create document type #{type} "
|
107
|
+
when /^e/
|
108
|
+
"create edge type #{type} "
|
109
|
+
end.concat( args.map{|x,y| "#{x} #{y} "}.join)
|
110
|
+
end
|
111
|
+
db= Api.execute database, &exe
|
112
|
+
types( true ) # update cached schema
|
113
|
+
db
|
114
|
+
|
115
|
+
rescue HTTPX::HTTPError => e
|
116
|
+
# puts "ERROR: #{e.message.to_s}"
|
117
|
+
if e.status == 500 && e.message.to_s =~ /already exists/
|
118
|
+
Arcade::Database.logger.warn "Database type #{type} already present"
|
119
|
+
else
|
120
|
+
raise
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
alias create_class create_type
|
125
|
+
|
126
|
+
# ------------ drop type -----------
|
127
|
+
# delete any record prior to the attempt to drop a type.
|
128
|
+
# The `unsafe` option is nit implemented.
|
129
|
+
def drop_type type
|
130
|
+
Api.execute database, "drop type #{type} if exists"
|
131
|
+
end
|
132
|
+
|
133
|
+
# ------------ create -----------
|
134
|
+
# returns an rid of the successfully created vertex or document
|
135
|
+
#
|
136
|
+
# Parameter: name of the vertex or document type
|
137
|
+
# Hash of attributes
|
138
|
+
#
|
139
|
+
# Example: > DB.create :my_vertex, a: 14, name: "Hugo"
|
140
|
+
# => "#177:0"
|
141
|
+
#
|
142
|
+
def create type, **params
|
143
|
+
# uses API
|
144
|
+
Api.create_document database, type, **params
|
145
|
+
end
|
146
|
+
|
147
|
+
def insert **params
|
148
|
+
|
149
|
+
content_params = params.except( :type, :bucket, :index, :from, :return )
|
150
|
+
target_params = params.slice( :type, :bucket, :index )
|
151
|
+
if target_params.empty?
|
152
|
+
logger.error "Could not insert: target mising (type:, bucket:, index:)"
|
153
|
+
elsif content_params.empty?
|
154
|
+
logger.error "Nothing to Insert"
|
155
|
+
else
|
156
|
+
content = "CONTENT #{ content_params.to_json }"
|
157
|
+
target = target_params.map{|y,z| y==:type ? z : "#{y.to_s} #{ z } "}.join
|
158
|
+
Api.execute( database, "INSERT INTO #{target} #{content} ") &.first.allocate_model(false)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# ------------------------------ get ------------------------------------------------------ #
|
163
|
+
# Get fetches the record associated with the rid given as parameter.
|
164
|
+
#
|
165
|
+
# The rid is accepted as
|
166
|
+
# DB.get "#123:123", DB.get "123:123" or DB.get 123, 123
|
167
|
+
#
|
168
|
+
# Links are autoloaded (can be suppressed by the optional Block (false))
|
169
|
+
#
|
170
|
+
# puts DB.get( 19,0 )
|
171
|
+
# <my_document[#19:0]: emb : ["<my_alist[#33:0]: name : record 1, number : 1>", "<my_alist[#34:0]: name : record 2, number : 2>"]>
|
172
|
+
# puts DB.get( 19,0 ){ false }
|
173
|
+
# <my_document[#19:0]: emb : ["#33:0", "#34:0"]>
|
174
|
+
#
|
175
|
+
#
|
176
|
+
def get *rid
|
177
|
+
autocomplete = block_given? ? yield : true
|
178
|
+
rid = rid.join(':')
|
179
|
+
rid = rid[1..-1] if rid[0]=="#"
|
180
|
+
if rid.rid?
|
181
|
+
Api.query( database, "select from #{rid}" ).first &.allocate_model(autocomplete)
|
182
|
+
else
|
183
|
+
raise Arcade::QueryError "Get requires a rid input", caller
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# ------------------------------ property ------------------------------------------------- #
|
188
|
+
# Adds properties to the type
|
189
|
+
#
|
190
|
+
# call via
|
191
|
+
# Api.property <database>, <type>, name1: a_format , name2: a_format
|
192
|
+
#
|
193
|
+
# Format is one of
|
194
|
+
# Boolean, Integer, Short, Long, Float, Double, String
|
195
|
+
# Datetime, Binary, Byte, Decimal, Link
|
196
|
+
# Embedded, EmbeddedList, EmbeddedMap
|
197
|
+
#
|
198
|
+
# In case of an Error, anything is rolled back and nil is returned
|
199
|
+
#
|
200
|
+
def self.property database, type, **args
|
201
|
+
|
202
|
+
begin_transaction database
|
203
|
+
success = args.map do | name, format |
|
204
|
+
r= execute(database) {" create property #{type.to_s}.#{name.to_s} #{format.to_s} " } &.first
|
205
|
+
if r.nil?
|
206
|
+
false
|
207
|
+
else
|
208
|
+
r.keys == [ :propertyName, :typeName, :operation ] && r[:operation] == 'create property'
|
209
|
+
end
|
210
|
+
end.uniq
|
211
|
+
if success == [true]
|
212
|
+
commit database
|
213
|
+
true
|
214
|
+
else
|
215
|
+
rollback database
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
# ------------------------------ index ------------------------------------------------- #
|
222
|
+
def self.index database, type, name , *properties
|
223
|
+
properties = properties.map( &:to_s )
|
224
|
+
unique_requested = "unique" if properties.delete("unique")
|
225
|
+
unique_requested = "notunique" if properties.delete("notunique" )
|
226
|
+
automatic = true if
|
227
|
+
properties << name if properties.empty?
|
228
|
+
end
|
229
|
+
|
230
|
+
def delete rid
|
231
|
+
r = Api.execute( database ){ "delete from #{rid}" }
|
232
|
+
success = r == [{ :count => 1 }]
|
233
|
+
end
|
234
|
+
|
235
|
+
# execute a command which modifies the database
|
236
|
+
#
|
237
|
+
# The operation is performed via Transaction/Commit
|
238
|
+
# If an Error occurs, its rolled back
|
239
|
+
#
|
240
|
+
def execute &block
|
241
|
+
s = Api.begin_transaction database
|
242
|
+
# begin
|
243
|
+
response = Api.execute database, nil, s, &block
|
244
|
+
# rescue HTTPX::HTTPError => e
|
245
|
+
# raise e.message
|
246
|
+
# puts e.methods
|
247
|
+
# puts e.status
|
248
|
+
# puts e.response
|
249
|
+
# puts e.message
|
250
|
+
# puts e.exception
|
251
|
+
# puts e.cause
|
252
|
+
# end
|
253
|
+
# puts response.inspect # debugging
|
254
|
+
r= if response.is_a? Hash
|
255
|
+
_allocate_model res
|
256
|
+
# elsif response.is_a? Array
|
257
|
+
# remove empty results
|
258
|
+
# response.delete_if{|y| y.empty?}
|
259
|
+
# response.map do | res |
|
260
|
+
# if res.key? :"@rid"
|
261
|
+
# allocate_model res
|
262
|
+
# else
|
263
|
+
# res
|
264
|
+
# end
|
265
|
+
# end
|
266
|
+
else
|
267
|
+
response
|
268
|
+
end
|
269
|
+
if Api.commit( database, s) == 204
|
270
|
+
r # return associated array of Arcade::Base-objects
|
271
|
+
else
|
272
|
+
[]
|
273
|
+
end
|
274
|
+
rescue Dry::Struct::Error, HTTPX::HTTPError, Arcade::QueryError => e
|
275
|
+
Api.rollback database, s
|
276
|
+
logger.error "Execution FAILED --> Status #{e.status}"
|
277
|
+
# logger.error "Execution FAILED --> #{e.exception.message}"
|
278
|
+
[] # return empty result
|
279
|
+
end
|
280
|
+
|
281
|
+
# returns an array of results
|
282
|
+
#
|
283
|
+
# detects database-records and allocates them as model-objects
|
284
|
+
#
|
285
|
+
def query query_object
|
286
|
+
Api.query database, query_object.to_s
|
287
|
+
end
|
288
|
+
|
289
|
+
# returns an array of rid's (same logic as create)
|
290
|
+
def create_edge edge_class, from:, to:, **attributes
|
291
|
+
|
292
|
+
content = attributes.empty? ? "" : "CONTENT #{attributes.to_json}"
|
293
|
+
cr = ->( f, t ) do
|
294
|
+
begin
|
295
|
+
edges = Api.execute( database, "create edge #{edge_class} from #{f.rid} to #{t.rid} #{content}").allocate_model(false)
|
296
|
+
rescue HTTPX::HTTPError => e
|
297
|
+
# if e.status == 503
|
298
|
+
# puts e.status
|
299
|
+
# puts e.message
|
300
|
+
# puts e.message.class
|
301
|
+
# end
|
302
|
+
raise unless e.message =~ /Found duplicate key/
|
303
|
+
puts "#"+e.message.split("#").last[0..-3]
|
304
|
+
end
|
305
|
+
#else
|
306
|
+
# logger.error "Could not create Edge #{edge_class} from #{f} to #{t}"
|
307
|
+
## logger.error edges.to_s
|
308
|
+
#end
|
309
|
+
end
|
310
|
+
from = [from] unless from.is_a? Array
|
311
|
+
to = [to] unless to.is_a? Array
|
312
|
+
|
313
|
+
from.map do | from_record |
|
314
|
+
to.map { | to_record | cr[ from_record, to_record ] if to_record.rid? } if from_record.rid?
|
315
|
+
end.flatten
|
316
|
+
|
317
|
+
end
|
318
|
+
|
319
|
+
|
320
|
+
# query all: select @rid, * from {database}
|
321
|
+
|
322
|
+
# not used
|
323
|
+
# def get_schema
|
324
|
+
# query( "select from schema:types" ).map do |a|
|
325
|
+
# puts "a: #{a}"
|
326
|
+
# class_name = a["name"]
|
327
|
+
# inherent_class = a["parentTypes"].empty? ? [Object,nil] : a["parentTypes"].map(&:camelcase_and_namespace)
|
328
|
+
# namespace, type_name = a["type"].camelcase_and_namespace
|
329
|
+
# namespace= Arcade if namespace.nil?
|
330
|
+
# klass= Dry::Core::ClassBuilder.new( name: type_name,
|
331
|
+
# parent: nil,
|
332
|
+
# namespace: namespace).call
|
333
|
+
# end
|
334
|
+
# rescue NameError
|
335
|
+
# logger.error "Dataset type #{e} not defined."
|
336
|
+
# raise
|
337
|
+
# end
|
338
|
+
# Postgres is not implemented
|
339
|
+
# connects to the database and initialises @connection
|
340
|
+
def connection
|
341
|
+
@connection
|
342
|
+
end
|
343
|
+
|
344
|
+
def connect environment=:development # environments: production devel test
|
345
|
+
if [:production, :development, :test].include? environment
|
346
|
+
|
347
|
+
# connect through the ruby postgres driver
|
348
|
+
# c= PG::Connection.new dbname: Config.database[environment],
|
349
|
+
# user: Config.username[environment],
|
350
|
+
# password: Config.password[environment],
|
351
|
+
# host: Config.pg[:host],
|
352
|
+
# port: Config.pg[:port]
|
353
|
+
#
|
354
|
+
end
|
355
|
+
rescue PG::ConnectionBad => e
|
356
|
+
if e.to_s =~ /Credentials/
|
357
|
+
logger.error "NOT CONNECTED ! Either Database is not present or credentials (#{ Config.username[environment]} / #{Config.password[environment]}) are wrong"
|
358
|
+
nil
|
359
|
+
else
|
360
|
+
raise
|
361
|
+
end
|
362
|
+
end # def
|
363
|
+
|
364
|
+
|
365
|
+
|
366
|
+
end # class
|
367
|
+
end # module
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Arcade
|
2
|
+
|
3
|
+
# Error handling
|
4
|
+
class Error < RuntimeError
|
5
|
+
end
|
6
|
+
|
7
|
+
class ArgumentError < ArgumentError
|
8
|
+
end
|
9
|
+
|
10
|
+
class SymbolError < ArgumentError
|
11
|
+
end
|
12
|
+
|
13
|
+
class LoadError < LoadError
|
14
|
+
end
|
15
|
+
|
16
|
+
class ImmutableError < RuntimeError
|
17
|
+
end
|
18
|
+
class IndexError < RuntimeError
|
19
|
+
end
|
20
|
+
|
21
|
+
class RollbackError < RuntimeError
|
22
|
+
end
|
23
|
+
|
24
|
+
class QueryError < RuntimeError
|
25
|
+
end
|
26
|
+
|
27
|
+
# used by Dry::Validation, not covered by "error"
|
28
|
+
class InvalidParamsError < StandardError
|
29
|
+
attr_reader :object
|
30
|
+
# @param [Hash] object that contains details about params errors.
|
31
|
+
# # @param [String] message of the error.
|
32
|
+
def initialize(object, message)
|
33
|
+
@object = object
|
34
|
+
super(message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end # module Arcade
|
39
|
+
|
40
|
+
# Patching Object with universally accessible top level error method.
|
41
|
+
# The method is used throughout the lib instead of plainly raising exceptions.
|
42
|
+
# This allows lib user to easily inject user-specific error handling into the lib
|
43
|
+
# by just replacing Object#error method.
|
44
|
+
#def error message, type=:standard, backtrace=nil
|
45
|
+
# e = case type
|
46
|
+
# when :standard
|
47
|
+
# Arcade::Error.new message
|
48
|
+
# when :args
|
49
|
+
# Arcade::ArgumentError.new message
|
50
|
+
# when :symbol
|
51
|
+
# Arcade::SymbolError.new message
|
52
|
+
# when :load
|
53
|
+
# Arcade::LoadError.new message
|
54
|
+
# when :immutable
|
55
|
+
# Arcade::ImmutableError.new message
|
56
|
+
# when :commit
|
57
|
+
# Arcade::RollbackError.new message
|
58
|
+
# when :query
|
59
|
+
# Arcade::QueryError.new message
|
60
|
+
# when :args
|
61
|
+
# IB::ArgumentError.new message
|
62
|
+
# when :flex
|
63
|
+
# IB::FlexError.new message
|
64
|
+
# when :reader
|
65
|
+
# IB::TransmissionError.new message
|
66
|
+
# when :verify
|
67
|
+
# IB::VerifyError.new message
|
68
|
+
# end
|
69
|
+
# e.set_backtrace(backtrace) if backtrace
|
70
|
+
# raise e
|
71
|
+
#end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#require_relative 'default_formatter'
|
2
|
+
module Arcade
|
3
|
+
module Logging
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
base.send :define_method, :logger do
|
7
|
+
base.logger
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def logger
|
13
|
+
@logger
|
14
|
+
end
|
15
|
+
|
16
|
+
def logger=(logger)
|
17
|
+
@logger = logger
|
18
|
+
end
|
19
|
+
|
20
|
+
def configure_logger(log= STDOUT)
|
21
|
+
if log.is_a? Logger
|
22
|
+
@logger = log
|
23
|
+
else
|
24
|
+
@logger = Logger.new log
|
25
|
+
end
|
26
|
+
@logger.level = Logger::INFO
|
27
|
+
@logger.formatter = DefaultFormatter
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class DefaultFormatter < Logger::Formatter
|
32
|
+
def self.call(severity, time, program_name, msg)
|
33
|
+
"#{time.strftime("%d.%m.(%X)")}#{"%5s" % severity}->#{msg}\n"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
# source: https://github.com/jondot/sneakers/blob/master/lib/sneakers/concerns/logging.rb
|
data/lib/arcade.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Arcade
|
2
|
+
|
3
|
+
end
|
4
|
+
|
5
|
+
require "arcade/version"
|
6
|
+
require "dry/configurable"
|
7
|
+
require "dry/struct"
|
8
|
+
require "dry/core/class_builder"
|
9
|
+
require "dry/core/class_attributes"
|
10
|
+
require 'json'
|
11
|
+
|
12
|
+
module Types
|
13
|
+
include Dry.Types()
|
14
|
+
end
|
15
|
+
require 'yaml'
|
16
|
+
require 'securerandom'
|
17
|
+
require 'httpx'
|
18
|
+
require 'arcade/errors'
|
19
|
+
require_relative '../lib/support/object'
|
20
|
+
require_relative '../lib/support/string'
|
21
|
+
require_relative '../lib/support/class'
|
22
|
+
require_relative '../lib/support/sql'
|
23
|
+
require_relative '../lib/support/model'
|
24
|
+
require_relative '../lib/arcade/logging'
|
25
|
+
require_relative '../lib/config'
|
26
|
+
require_relative '../lib/support/conversions'
|
27
|
+
require_relative '../lib/arcade/api/primitives'
|
28
|
+
require_relative '../lib/arcade/api/operations'
|
29
|
+
require_relative '../lib/arcade/base'
|
30
|
+
require_relative '../lib/arcade/database'
|
31
|
+
require_relative '../lib/init'
|
32
|
+
require_relative "../lib/models"
|
33
|
+
require_relative '../lib/query'
|
34
|
+
require_relative '../lib/match'
|
35
|
+
require_relative '../lib/railtie' if defined? Rails::Railtie
|
36
|
+
|
data/lib/config.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
module Arcade
|
2
|
+
class Config
|
3
|
+
extend Dry::Configurable
|
4
|
+
# central place to initialize constants
|
5
|
+
#
|
6
|
+
# ProjectRoot has to be a Pathname-Object
|
7
|
+
#
|
8
|
+
#puts "expand: #{File.expand_path(__dir__)}"
|
9
|
+
unless Arcade.const_defined?( :ProjectRoot )
|
10
|
+
Arcade::ProjectRoot = if defined?( Rails.env )
|
11
|
+
Rails.root
|
12
|
+
else
|
13
|
+
STDERR.puts "Using default (arcadedb gem) database credentials and settings"
|
14
|
+
# logger is not present at this stage
|
15
|
+
Pathname.new( File.expand_path( "../../", __FILE__ ))
|
16
|
+
end
|
17
|
+
else
|
18
|
+
STDERR.puts "Using provided database credentials and settings fron #{Arcade::ProjectRoot}"
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# initialised a hash { environment => property }
|
23
|
+
setting :username, default: :user, reader: true,
|
24
|
+
constructor: ->(v) { yml(:environment).map{|x,y| [x , y[v.to_s]] }.to_h }
|
25
|
+
setting :password, default: :password, reader: true,
|
26
|
+
constructor: ->(v) { yml(:environment).map{|x,y| [x , y["pass"]] }.to_h }
|
27
|
+
setting :database, default: :database, reader: true,
|
28
|
+
constructor: ->(v) { yml(:environment).map{|x,y| [x , y["dbname"]] }.to_h }
|
29
|
+
setting(:base_uri, default: :host , reader: true,
|
30
|
+
constructor: ->(v) { "http://"+yml(:admin)[v]+':'+yml(:admin)[:port].to_s+"/api/v1/" })
|
31
|
+
setting :autoload, default: :autoload, reader: true , constructor: ->(v) { yml(v) }
|
32
|
+
setting :pg, default: :pg, reader: true , constructor: ->(v) { yml(v) }
|
33
|
+
setting :admin, default: :admin, reader: true , constructor: ->(v) { yml(v) }
|
34
|
+
setting :logger, default: :logger, reader: true ,
|
35
|
+
constructor: ->(v) do
|
36
|
+
if defined?( Rails.env )
|
37
|
+
Rails.logger
|
38
|
+
elsif Object.const_defined?(:Bridgetown)
|
39
|
+
else
|
40
|
+
output = yml(v)
|
41
|
+
if output.upcase == 'STDOUT'
|
42
|
+
Logger.new STDOUT
|
43
|
+
else
|
44
|
+
Logger.new File.open( output, 'a' )
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
setting :namespace, default: :namespace, reader: true , constructor: ->(v) { yml(v) }
|
49
|
+
setting :secret, reader: true, default: 12, constructor: ->(v) { seed(v) }
|
50
|
+
private
|
51
|
+
# if a config dir exists, use it.
|
52
|
+
# Standard: ProjectRoot/config.yml
|
53
|
+
def self.config_file
|
54
|
+
|
55
|
+
configdir = -> do
|
56
|
+
pr = ProjectRoot.is_a?(Pathname)? ProjectRoot : Pathname.new( ProjectRoot )
|
57
|
+
( cd = pr + 'arcade.yml' ).exist? || ( cd = pr + 'config' + 'arcade.yml' ).exist? || ( cd = pr + 'config.yml' )
|
58
|
+
cd
|
59
|
+
end
|
60
|
+
|
61
|
+
@cd ||= configdir[]
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.yml key=nil
|
65
|
+
y= YAML::load_file( config_file )
|
66
|
+
key.nil? ? y : y[key]
|
67
|
+
end
|
68
|
+
def self.seed( key= nil )
|
69
|
+
SecureRandom.hex( 40 )
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/init.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Arcade
|
2
|
+
|
3
|
+
# Arcade::Init.connect environment
|
4
|
+
# --------------------------------
|
5
|
+
# initializes the database connection
|
6
|
+
# and returns the active database handle
|
7
|
+
#
|
8
|
+
# The database cannot switched later
|
9
|
+
#
|
10
|
+
#
|
11
|
+
# Arcade::Init.db
|
12
|
+
# --------------
|
13
|
+
# returns an instance of the database handle
|
14
|
+
#
|
15
|
+
class Init
|
16
|
+
extend Dry::Core::ClassAttributes
|
17
|
+
defines :db # database handle
|
18
|
+
|
19
|
+
def self.connect e= :development
|
20
|
+
|
21
|
+
env = if e.to_s =~ /^p/
|
22
|
+
:production
|
23
|
+
elsif e.to_s =~ /^t/
|
24
|
+
:test
|
25
|
+
else
|
26
|
+
:development
|
27
|
+
end
|
28
|
+
# set the class attribute
|
29
|
+
|
30
|
+
db Database.new(env)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Provides method `db` to every Model class
|
35
|
+
class Base
|
36
|
+
def self.db
|
37
|
+
Init.db
|
38
|
+
end
|
39
|
+
# expose db to instance methods as well
|
40
|
+
private define_method :db, &method(:db)
|
41
|
+
private_class_method :db
|
42
|
+
end
|
43
|
+
# Provides method `db` to every Query-Object
|
44
|
+
class Query
|
45
|
+
def db
|
46
|
+
Init.db
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|