arcadedb 0.3.1 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,87 @@
1
+ module Arcade
2
+ module Support
3
+ module Model
4
+
5
+ def resolve_edge_name *edge_names
6
+ edge_names.map do | edge_name |
7
+ case edge_name
8
+ when nil
9
+ ""
10
+ when Class
11
+ "'" + edge_name.database_name + "'"
12
+ when String
13
+ "'" + edge_name + "'"
14
+ end
15
+ end.join(',')
16
+ end
17
+
18
+
19
+ # used by array#allocate_model
20
+ def _allocate_model response=nil, auto = Config.autoload
21
+
22
+
23
+ if response.is_a? Hash
24
+ # save rid to a safe place
25
+ temp_rid = response.delete :"@rid"
26
+ type = response.delete :"@type"
27
+ cat = response.delete :"@cat"
28
+
29
+ return response if type.nil?
30
+ temp_rid = "#0:0" if temp_rid.nil?
31
+ type = "d" if type.nil?
32
+ # extract type infos and convert to database-name
33
+ n, type_name = type.camelcase_and_namespace
34
+ n = self.namespace if n.nil?
35
+ # autoconvert rid's in attributes to model-records (exclude edges!)
36
+ if auto && !(cat.to_s =='e')
37
+ response.transform_values! do |x|
38
+ case x
39
+ when String
40
+ x.rid? ? x.load_rid : x
41
+ when Array
42
+ x.map do| y |
43
+ if y.is_a?(Hash) && y.include?(:@type) # if embedded documents are present, load them
44
+ y.allocate_model(false)
45
+ elsif y.rid? # if links are present, load the object
46
+ y.load_rid(false) # do not autoload further records, prevents from recursive locking
47
+ else
48
+ y
49
+ end
50
+ end
51
+ when Hash
52
+ if x.include?(:@type)
53
+ x.allocate_model(false)
54
+ else
55
+ x.transform_values!{|z| z.rid? ? z.load_rid(false) : z }
56
+ end
57
+ else
58
+ x
59
+ end
60
+ end
61
+ end
62
+ # choose the appropriate class
63
+ klass= Dry::Core::ClassBuilder.new( name: type_name, parent: nil, namespace: n).call
64
+ #
65
+ begin
66
+ # create a new object of that class with the appropriate attributes
67
+ new = klass.new **response.merge( rid: temp_rid )
68
+ rescue ::ArgumentError => e
69
+ raise "Allocation of class #{klass.to_s} failed"
70
+ end
71
+ # map additional attributes to `input`
72
+ v = response.except *new.attributes.keys
73
+ v.empty? ? new : new.new( values: v.except( :"@in", :"@out" ) )
74
+ elsif response.is_a? Array
75
+ puts "Allocate_model..detected array"
76
+ ## recursive behavior, just in case
77
+ response.map{ | y | _allocate_model y }
78
+ elsif response.rid?
79
+ # Autoload rid's
80
+ response.load_rid
81
+ else
82
+ response
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,20 @@
1
+ module Arcade
2
+ module Support
3
+ module Object
4
+ # this is the rails method
5
+ def present?
6
+ !blank?
7
+ end
8
+
9
+ # File activesupport/lib/active_support/core_ext/object/blank.rb, line 46
10
+ def presence
11
+ self if present?
12
+ end
13
+ # File activesupport/lib/active_support/core_ext/object/blank.rb, line 19
14
+ def blank?
15
+ respond_to?(:empty?) ? !!empty? : !self
16
+ end
17
+ end
18
+ end
19
+ end
20
+ Object.include Arcade::Support::Object
@@ -0,0 +1,74 @@
1
+ #require 'active_support/inflector'
2
+
3
+ module Arcade
4
+ module Support
5
+ module Sql
6
+
7
+ =begin
8
+ supports
9
+ where: 'string'
10
+ where: { property: 'value', property: value, ... }
11
+ where: ['string, { property: value, ... }, ... ]
12
+
13
+ Used by update and select
14
+
15
+ _Usecase:_
16
+ compose_where 'z=34', u: 6
17
+ => "where z=34 and u = 6"
18
+ =end
19
+
20
+ def compose_where *arg , &b
21
+ arg = arg.flatten.compact
22
+
23
+ unless arg.blank?
24
+ g= generate_sql_list( arg , &b)
25
+ "where #{g}" unless g.empty?
26
+ end
27
+ end
28
+
29
+ =begin
30
+ designs a list of "Key = Value" pairs combined by "and" or the binding provided by the block
31
+ ORD.generate_sql_list where: 25 , upper: '65'
32
+ => "where=25 and upper='65'"
33
+ ORD.generate_sql_list( con_id: 25 , symbol: :G) { ',' }
34
+ => "con_id=25 , symbol='G'"
35
+
36
+ If »NULL« should be addressed, { key: nil } is translated to "key = NULL" (used by set: in update and upsert),
37
+ { key: [nil] } is translated to "key is NULL" ( used by where )
38
+
39
+ =end
40
+ def generate_sql_list attributes = {}, &b
41
+ fill = block_given? ? yield : 'and'
42
+ case attributes
43
+ when ::Hash
44
+ attributes.map do |key, value|
45
+ case value
46
+ when nil
47
+ "#{key}=NULL"
48
+ when ::Array
49
+ if value == [nil]
50
+ "#{key} is NULL"
51
+ else
52
+ "#{key} in #{value.to_db}"
53
+ end
54
+ when Range
55
+ "#{key} between #{value.first.to_or} and #{value.last.to_or} "
56
+ else # String, Symbol, Time, Trueclass, Falseclass ...
57
+ "#{key}=#{value.to_or}"
58
+ end
59
+ end.join(" #{fill} ")
60
+ when ::Array
61
+ attributes.map{|y| generate_sql_list y, &b }.join( " #{fill} " )
62
+ when String
63
+ attributes
64
+ when Symbol, Numeric
65
+ attributes.to_s
66
+ end
67
+ end
68
+
69
+
70
+ # used both in Query and MatchConnect
71
+ # while and where depend on @q, a struct
72
+ end # module
73
+ end # module
74
+ end # modul
@@ -0,0 +1,116 @@
1
+ module Arcade
2
+ module Support
3
+ module String
4
+ #modified version of
5
+ # https://stackoverflow.com/questions/63769351/convert-string-to-camel-case-in-ruby
6
+ # returns an Array [ Namespace(first character upcase) , Type(class, camelcase) ]
7
+ #
8
+ # if the namespace is not found, joins all string-parts
9
+ def camelcase_and_namespace
10
+ if self.count("_") >= 1 || self.count('-') >=1
11
+ delimiters = Regexp.union(['-', '_'])
12
+ n,c= self.split(delimiters).then { |first, *rest| [first.tap {|s| s[0] = s[0].upcase}, rest.map(&:capitalize).join] }
13
+ ## if base is the first part of the type-name, probably Arcade::Base is choosen a namespace. thats wrong
14
+ namespace_present = unless n == 'Base'
15
+ Object.const_get(n) rescue false # Database.namespace
16
+ else
17
+ false
18
+ end
19
+ # if no namespace is found, leave it empty and return the capitalized string as class name
20
+ namespace_present && !c.nil? ? [namespace_present,c] : [Database.namespace, n+c]
21
+ else
22
+ [ Database.namespace, self.capitalize ]
23
+ end
24
+ end
25
+
26
+ def snake_case
27
+ n= if split('::').first == Database.namespace.to_s
28
+ split('::')[1..-1].join
29
+ else
30
+ split("::").join
31
+ end
32
+ n.gsub(/([^\^])([A-Z])/,'\1_\2').downcase
33
+ end
34
+
35
+ # borrowed from ActiveSupport::Inflector
36
+ def underscore
37
+ word = self.dup
38
+ word.gsub!(/::/, '/')
39
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
40
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
41
+ word.tr!("-", "_")
42
+ word.downcase!
43
+ word
44
+ end
45
+ def capitalize_first_letter
46
+ self.sub(/^(.)/) { $1.capitalize }
47
+ end
48
+ # a rid is either #nn:nn or nn:nn
49
+ def rid?
50
+ self =~ /\A[#]{,1}[0-9]{1,}:[0-9]{1,}\z/
51
+ end
52
+ # return a valid rid (format: "nn:mm") or nil
53
+ def rid
54
+ self["#"].nil? ? "#"+ self : self if rid?
55
+ end
56
+
57
+ def where **args
58
+ if rid?
59
+ from_db.where **args
60
+ end
61
+ end
62
+ def to_a
63
+ [ self ]
64
+ end
65
+
66
+ def quote
67
+ str = self.dup
68
+ if str[0, 1] == "'" && str[-1, 1] == "'"
69
+ self
70
+ else
71
+ last_pos = 0
72
+ while (pos = str.index("'", last_pos))
73
+ str.insert(pos, "\\") if pos > 0 && str[pos - 1, 1] != "\\"
74
+ last_pos = pos + 1
75
+ end
76
+ "'#{str}'"
77
+ end
78
+ end
79
+
80
+ ## Load the database object if the string is a rid
81
+ # (Default: No Autoloading of rid-links)
82
+ def load_rid autocomplete = false
83
+ db.get( self ){ autocomplete } if rid? rescue nil
84
+ end
85
+
86
+ # updates the record ### retired in favour of Arcade::Base.update
87
+ # def update **args
88
+ ## remove empty Arrays and Hashes.
89
+ ## To remove attributes, use the remove syntax, do not privide empty fields to update!
90
+ # args.delete_if{|_,y|( y.is_a?(Array) || y.is_a?(Hash)) && y.blank? }
91
+ # return nil if args.empty?
92
+ # Arcade::Query.new( from: self , kind: :update, set: args).execute
93
+ # end
94
+
95
+ def to_human
96
+ self
97
+ end
98
+ private
99
+ def db
100
+ Arcade::Init.db
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ String.include Arcade::Support::String
107
+
108
+ module Types
109
+ include Dry.Types()
110
+
111
+ # include in attribute definitions
112
+ Rid = String.constrained( format: /\A[#]{1}[0-9]{1,}:[0-9]{1,}\z/ )
113
+ Blockchain = String.constrained( format: /^(algo|eth|btc)$/ ) # add other blockchain symbols here
114
+ Email = String.constrained( format: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i )
115
+
116
+ end
data/rails/arcade.rb ADDED
@@ -0,0 +1,20 @@
1
+
2
+ ## This is an init-script intended to be copied to
3
+ ## rails-root/config/initializers
4
+
5
+ module Arcade
6
+ ProjectRoot = Rails.root
7
+ puts "Root: #{Rails.root}"
8
+ puts "Alternative: #{File.expand_path("../",__FILE__)}"
9
+ end
10
+ ## Integrate a namespaced model
11
+ #module HC
12
+ #
13
+ #end
14
+
15
+
16
+
17
+
18
+
19
+
20
+
data/rails/config.yml ADDED
@@ -0,0 +1,10 @@
1
+ ---
2
+ :active_orient:
3
+ ## Namespace: Prefix of Model-Objects. :self -> ActiveOrient::Model::{name}
4
+ ## :object => No Prefix
5
+ ## :active_orient => ActiveOrient::{name}
6
+ :namespace: :object
7
+ ## model_dir: Path to model-files relative to the root of the application
8
+ ## ie. app/model or model
9
+ :model_dir: 'lib/orient'
10
+
data/rails/connect.yml ADDED
@@ -0,0 +1,17 @@
1
+ ---
2
+ :orientdb:
3
+ :server: localhost # 172.28.50.109
4
+ :port: 2480
5
+ :logger: stdout # 'file' or 'stdout'
6
+ :database:
7
+ :development: GratefulDeadConcerts
8
+ :production: hcn_data
9
+ :test: temp
10
+ :admin:
11
+ :user: root
12
+ :pass: root
13
+ :auth:
14
+ :user: root
15
+ :pass: root
16
+
17
+ # hfx: 101
data/rails.md ADDED
@@ -0,0 +1,147 @@
1
+ # ArcadeDB and Rails
2
+
3
+ The usage of ArcadeDB in Rails requires just a few steps.
4
+ Based on a Rails 7 installation
5
+
6
+ ```ruby
7
+ rvm install 3.1
8
+ rvm use 3.1
9
+ gem install bundler
10
+ gem install rails
11
+ rails -v # Rails 7.xx
12
+ ```
13
+
14
+ Create your working directory and initialize the system
15
+
16
+ ```ruby
17
+ mkdir rails_project; cd rails_project
18
+ rails new -OCT -css {tailwind, sass, bulma etc} .
19
+ ```
20
+ This initializes a Rails-Stack, without active-record, action-cable and the test-suite.
21
+ (We will use rspec later)
22
+
23
+ This can be checked by inspecting «/config/application.rb «
24
+
25
+ ```ruby
26
+ ./bin/dev
27
+ ```
28
+ should work at this stage.
29
+
30
+ ## Modify the Gemfile
31
+ Inform rails to use arcadedb
32
+
33
+ ```
34
+ echo " gem 'arcadedb' , :path => '/home/your_cloned_active_orient_path/activeorient' " >> Gemfile
35
+ # or
36
+
37
+ echo " gem 'arcadedb' , :git => 'https://github.com/topofocus/arcadedb.git' " >> Gemfile
38
+
39
+ ```
40
+
41
+ Run the bundler
42
+
43
+ ```
44
+ bundle install & bundle update
45
+ ```
46
+ ## Copy Initializer and Configuration Files
47
+ change to the base-dir of the gem
48
+ --> bundle show active-orient
49
+ then copy
50
+
51
+ * rails/arcade.rb to config/initializers in the rails-project dir
52
+ * rails/.arcade.yml to config/ in the rails project
53
+
54
+ and modify the arcade.yml-file accordingly.
55
+
56
+
57
+ The database is present in the rails console, and
58
+ ```ruby
59
+ rails c
60
+ puts DB.types
61
+
62
+
63
+ ```
64
+ should display details.
65
+
66
+
67
+ **Notice** The spring-facility is running in the background. Stop the server prior reloading
68
+ the console ( ./bin/spring stop ).
69
+
70
+ ## Model-files
71
+ The final step is to generate Model-Files.
72
+
73
+ In «/config/config.yml» the «:model_dir»-var points to
74
+ the location of the model-files. The default is 'lib/orient'. Change to your needs.
75
+ Don't use the app directory, as its autoloaded too early.
76
+
77
+ Upon startup, present model-classes are destroyed and overridden by present files in the autoload directory.
78
+
79
+ After envoking the rails console, the logfile displays sucessfully loaded and missing files, ie.
80
+
81
+ ```
82
+ 14.01.(08:28:45) INFO->ModelClass#RequireModelFile:..:model-file not present: /home/topo/workspace/orient-rails/lib/orient/followed_by.rb
83
+ 14.01.(08:28:45) INFO->ModelClass#RequireModelFile:..:/home/topo/workspace/orient-rails/lib/orient/v.rb sucessfully loaded
84
+ ```
85
+
86
+ ## Model-file Example
87
+
88
+ To query the GratefulDeadConcerts Database, «v.rb» hosts the essential model methods.
89
+ As always, use «def self.{method}« for class methods and simply «def {method}» for methods working on the record level.
90
+
91
+ ```
92
+ 1 class V
93
+ 2 def self.artists **attributes
94
+ 3 names 'artist', **attributes
95
+ 4 end
96
+ 5
97
+ 6 def self.songs **attributes
98
+ 7 names 'song', **attributes
99
+ 8 end
100
+ 9
101
+ 10 def self.types
102
+ 11 oo = OrientSupport::OrientQuery
103
+ 12 this_query = oo.new distinct: [:type, :a ] # --> "select distinct( type ) as a "
104
+ 13 query_database( this_query ).a # returns an array of types, i.e. ["artist", "song"]
105
+ 14 end
106
+ 15 private
107
+ 16 def self.names type, sort: :asc, limit: 20, skip: 0
108
+ 17 puts "in names"
109
+ 18 oo = OrientSupport::OrientQuery
110
+ 19 query_database oo.new( where: {type: type },
111
+ 20 order: { name: sort } ,
112
+ 21 limit: limit ,
113
+ 22 skip: skip )
114
+ 23 end
115
+ 24 end
116
+
117
+ ```
118
+
119
+ Now
120
+
121
+ ```ruby
122
+ V.types
123
+ V.artists limit: 15, skip: 34, sort: :desc
124
+ ```
125
+ queries the database, fetches 15 artists.
126
+
127
+ ## Routing
128
+
129
+ for now, restful routing has some restrictions.
130
+
131
+ Rails-routing is depending on the "id"-attribute. Even if this is remapped to rid, the ressources-entries in "config/routes.rb" have to be modified by
132
+
133
+ ```ruiby
134
+ resources :{controller}, id: /[^\/]+/
135
+ ```
136
+ this enables the usage of id: "xx:yy"
137
+
138
+ In the controller the record is fetched as usual:
139
+ ```ruby
140
+ def show
141
+ @{your coice} = {ActiveOrient-Model-Class}.autoload_object params[:id]
142
+ end
143
+ ```
144
+
145
+
146
+
147
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arcadedb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: '0.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hartmut Bischoff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-16 00:00:00.000000000 Z
11
+ date: 2023-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '4.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: typhoeus
56
+ name: httpx
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -108,12 +108,71 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: dry-configurable
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: Provides access to ArcadeDB from ruby
112
126
  email: topofocus@gmail.com
113
127
  executables: []
114
128
  extensions: []
115
129
  extra_rdoc_files: []
116
- files: []
130
+ files:
131
+ - ".gitignore"
132
+ - CHANGELOG.md
133
+ - Gemfile
134
+ - Gemfile.lock
135
+ - Guardfile
136
+ - LICENSE
137
+ - README.md
138
+ - Rakefile
139
+ - arcade.yml
140
+ - arcadedb.gemspec
141
+ - bin/+
142
+ - bin/console
143
+ - examples/books.rb
144
+ - examples/relation_1__1.rb
145
+ - examples/relation_1__n.rb
146
+ - examples/relation_n_n.rb
147
+ - lib/arcade.rb
148
+ - lib/arcade/api/operations.rb
149
+ - lib/arcade/api/primitives.rb
150
+ - lib/arcade/base.rb
151
+ - lib/arcade/database.rb
152
+ - lib/arcade/errors.rb
153
+ - lib/arcade/logging.rb
154
+ - lib/arcade/version.rb
155
+ - lib/config.rb
156
+ - lib/init.rb
157
+ - lib/match.rb
158
+ - lib/model/basicdocument.rb
159
+ - lib/model/basicedge.rb
160
+ - lib/model/basicvertex.rb
161
+ - lib/model/document.rb
162
+ - lib/model/edge.rb
163
+ - lib/model/vertex.rb
164
+ - lib/models.rb
165
+ - lib/query.rb
166
+ - lib/support/class.rb
167
+ - lib/support/conversions.rb
168
+ - lib/support/model.rb
169
+ - lib/support/object.rb
170
+ - lib/support/sql.rb
171
+ - lib/support/string.rb
172
+ - rails.md
173
+ - rails/arcade.rb
174
+ - rails/config.yml
175
+ - rails/connect.yml
117
176
  homepage: https://github.com/topofocus/arcadedb
118
177
  licenses:
119
178
  - MIT
@@ -133,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
192
  - !ruby/object:Gem::Version
134
193
  version: '0'
135
194
  requirements: []
136
- rubygems_version: 3.3.7
195
+ rubygems_version: 3.4.6
137
196
  signing_key:
138
197
  specification_version: 4
139
198
  summary: Ruby Interface to ArcadeDB