lotus-model 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: de9019e132ab36bb7b30223c52e247df84e3cf3e
4
- data.tar.gz: d56eeb3a71e31193b1509527f24ac8f0822df5f0
3
+ metadata.gz: f21fa9e59f4e1cb1f1892e30557d39293abada84
4
+ data.tar.gz: 10adc53a8de64a6b6ffbe17d99c62af5c9d37b16
5
5
  SHA512:
6
- metadata.gz: 8449498885c9eda612f978aed61dfbe362e213b8c392ce86cb37d9586f5d0865b010f9900246b3621d63627e0900f43a52a0dfe954e9b507306987ab1ef9755b
7
- data.tar.gz: 478a4d4bf0323970ee7adf7733123418745aa135db6dc79142e9f203962793b039e2e017fca8a3d9f1bee01dd3f7511068220c465a44e29399a57c950eea9e61
6
+ metadata.gz: 9e2ccc8f6beac3d0fde6826d9f2a6c8d5eafc8084ce0cbc1e6d61e8be89d0ee6f909f0e7a2b9df30c2517d5d1a3f3470d0205379a8d42c670a3aed78f69836c5
7
+ data.tar.gz: 55c49d4330fa045ace6a741ace5e4ad005c2aaa5680e1c1d5fcd11627f50829a5a5831f37948892a9c3834ea5b4f40d227896e830fd6b3bbc4396f9924c221ab
@@ -1,6 +1,20 @@
1
1
  # Lotus::Model
2
2
  A persistence layer for Lotus
3
3
 
4
+ ## v0.5.1 - 2016-01-12
5
+ ### Added
6
+ - [Taylor Finnell] Let `Lotus::Model::Configuration#adapter` to accept arbitrary options (eg. `adapter type: :sql, uri: 'jdbc:...', after_connect: Proc.new { |connection| connection.auto_commit(true) }`)
7
+
8
+ ### Changed
9
+ - [Andrey Deryabin] Improved `Entity#inspect`
10
+ - [Karim Tarek] Introduced `Lotus::Model::Error` and let all the framework exceptions to inherit from it.
11
+
12
+ ### Fixed
13
+ - [Luca Guidi] Improved error message when trying to use a repository without mapping the corresponding collections
14
+ - [Sean Collins] Improved error message when trying to create database, but it fails (eg. missing `createdb` executable)
15
+ - [Andrey Deryabin] Improved error message when trying to drop database, but a client is still connected (useful for PostgreSQL)
16
+ - [Hiếu Nguyễn] Improved error message when trying to "prepare" database, but it fails
17
+
4
18
  ## v0.5.0 - 2015-09-30
5
19
  ### Added
6
20
  - [Brenno Costa] Official support for JRuby 9k+
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2014-2015 Luca Guidi
1
+ Copyright © 2014-2016 Luca Guidi
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -31,7 +31,7 @@ Like all the other Lotus components, it can be used as a standalone framework or
31
31
  * API Doc: http://rdoc.info/gems/lotus-model
32
32
  * Bugs/Issues: https://github.com/lotus/model/issues
33
33
  * Support: http://stackoverflow.com/questions/tagged/lotus-ruby
34
- * Chat: https://gitter.im/lotus/chat
34
+ * Chat: https://chat.lotusrb.org
35
35
 
36
36
  ## Rubies
37
37
 
@@ -624,4 +624,4 @@ __Lotus::Model__ uses [Semantic Versioning 2.0.0](http://semver.org)
624
624
 
625
625
  ## Copyright
626
626
 
627
- Copyright © 2014-2015 Luca Guidi – Released under MIT License
627
+ Copyright © 2014-2016 Luca Guidi – Released under MIT License
@@ -140,15 +140,13 @@ module Lotus
140
140
  # DeletedUser.attributes => #<Set: {:id, :name, :deleted_at}>
141
141
  #
142
142
  def attributes(*attrs)
143
- if attrs.any?
144
- attrs = Lotus::Utils::Kernel.Array(attrs)
145
- self.attributes.merge attrs
143
+ return @attributes ||= Set.new unless attrs.any?
146
144
 
147
- attrs.each do |attr|
148
- define_attr_accessor(attr) if defined_attribute?(attr)
145
+ Lotus::Utils::Kernel.Array(attrs).each do |attr|
146
+ if allowed_attribute_name?(attr)
147
+ define_attr_accessor(attr)
148
+ self.attributes << attr
149
149
  end
150
- else
151
- @attributes ||= Set.new
152
150
  end
153
151
  end
154
152
 
@@ -164,11 +162,10 @@ module Lotus
164
162
 
165
163
  # Check if attr_reader define the given attribute
166
164
  #
167
- # @since 0.3.1
165
+ # @since 0.5.1
168
166
  # @api private
169
- def defined_attribute?(name)
170
- name == :id ||
171
- !instance_methods.include?(name)
167
+ def allowed_attribute_name?(name)
168
+ !instance_methods.include?(name)
172
169
  end
173
170
 
174
171
  protected
@@ -223,9 +220,51 @@ module Lotus
223
220
  # user = User.new(id: 23, name: 'Luca')
224
221
  # user.to_h # => { :id => 23, :name => "Luca" }
225
222
  def to_h
226
- Hash[self.class.attributes.map { |a| [a, public_send(a)] }]
223
+ Hash[attribute_names.map { |a| [a, read_attribute(a)] }]
224
+ end
225
+
226
+ # Return the set of attribute names
227
+ #
228
+ # @since 0.5.1
229
+ #
230
+ # @example
231
+ # require 'lotus/model'
232
+ # class User
233
+ # include Lotus::Entity
234
+ # attributes :name
235
+ # end
236
+ #
237
+ # user = User.new(id: 23, name: 'Luca')
238
+ # user.attribute_names # #<Set: {:id, :name}>
239
+ def attribute_names
240
+ self.class.attributes
241
+ end
242
+
243
+ # Return the contents of the entity as a nicely formatted string.
244
+ #
245
+ # Display all attributes of the entity for inspection (even if they are nil)
246
+ #
247
+ # @since 0.5.1
248
+ #
249
+ # @example
250
+ # require 'lotus/model'
251
+ # class User
252
+ # include Lotus::Entity
253
+ # attributes :name, :email
254
+ # end
255
+ #
256
+ # user = User.new(id: 23, name: 'Luca')
257
+ # user.inspect # #<User:0x007fa7eefe0b58 @id=nil @name="Luca" @email=nil>
258
+ def inspect
259
+ attr_list = attribute_names.inject([]) do |res, name|
260
+ res << "@#{name}=#{read_attribute(name).inspect}"
261
+ end.join(' ')
262
+
263
+ "#<#{self.class.name}:0x00#{(__id__ << 1).to_s(16)} #{attr_list}>"
227
264
  end
228
265
 
266
+ alias_method :to_s, :inspect
267
+
229
268
  # Set attributes for entity
230
269
  #
231
270
  # @since 0.2.0
@@ -246,5 +285,14 @@ module Lotus
246
285
  end
247
286
  end
248
287
 
288
+ private
289
+
290
+ # Return the value by attribute name
291
+ #
292
+ # @since 0.5.1
293
+ # @api private
294
+ def read_attribute(attr_name)
295
+ public_send(attr_name)
296
+ end
249
297
  end
250
298
  end
@@ -4,6 +4,7 @@ require 'lotus/entity/dirty_tracking'
4
4
  require 'lotus/repository'
5
5
  require 'lotus/model/mapper'
6
6
  require 'lotus/model/configuration'
7
+ require 'lotus/model/error'
7
8
 
8
9
  module Lotus
9
10
  # Model
@@ -16,7 +17,7 @@ module Lotus
16
17
  # @since 0.1.0
17
18
  #
18
19
  # @see Lotus::Repository.update
19
- class NonPersistedEntityError < ::StandardError
20
+ class NonPersistedEntityError < Lotus::Model::Error
20
21
  end
21
22
 
22
23
  # Error for invalid mapper configuration
@@ -25,13 +26,13 @@ module Lotus
25
26
  # @since 0.2.0
26
27
  #
27
28
  # @see Lotus::Configuration#mapping
28
- class InvalidMappingError < ::StandardError
29
+ class InvalidMappingError < Lotus::Model::Error
29
30
  end
30
31
 
31
32
  # Error for invalid raw command syntax
32
33
  #
33
34
  # @since 0.5.0
34
- class InvalidCommandError < ::StandardError
35
+ class InvalidCommandError < Lotus::Model::Error
35
36
  def initialize(message = "Invalid command")
36
37
  super
37
38
  end
@@ -40,7 +41,7 @@ module Lotus
40
41
  # Error for invalid raw query syntax
41
42
  #
42
43
  # @since 0.3.1
43
- class InvalidQueryError < ::StandardError
44
+ class InvalidQueryError < Lotus::Model::Error
44
45
  def initialize(message = "Invalid query")
45
46
  super
46
47
  end
@@ -11,7 +11,7 @@ module Lotus
11
11
  # @see Lotus::Model::Adapters::SqlAdapter#initialize
12
12
  #
13
13
  # @since 0.1.0
14
- class DatabaseAdapterNotFound < ::StandardError
14
+ class DatabaseAdapterNotFound < Lotus::Model::Error
15
15
  end
16
16
 
17
17
  # It's raised when an adapter does not support a feature.
@@ -22,14 +22,14 @@ module Lotus
22
22
  # @see Lotus::Model::Adapters::Abstract#connection_string
23
23
  #
24
24
  # @since 0.3.0
25
- class NotSupportedError < ::StandardError
25
+ class NotSupportedError < Lotus::Model::Error
26
26
  end
27
27
 
28
28
  # It's raised when an operation is requested to an adapter after it was
29
29
  # disconnected.
30
30
  #
31
31
  # @since 0.5.0
32
- class DisconnectedAdapterError < ::StandardError
32
+ class DisconnectedAdapterError < Lotus::Model::Error
33
33
  def initialize
34
34
  super "You have tried to perform an operation on a disconnected adapter"
35
35
  end
@@ -85,10 +85,13 @@ module Lotus
85
85
  #
86
86
  # @param uri [String] the optional connection string to the database
87
87
  #
88
+ # @param options [Hash] a list of non-mandatory adapter options
89
+ #
88
90
  # @since 0.1.0
89
- def initialize(mapper, uri = nil)
91
+ def initialize(mapper, uri = nil, options = {})
90
92
  @mapper = mapper
91
93
  @uri = uri
94
+ @options = options
92
95
  end
93
96
 
94
97
  # Creates or updates a record in the database for the given entity.
@@ -59,6 +59,7 @@ module Lotus
59
59
  #
60
60
  # @param mapper [Object] the database mapper
61
61
  # @param uri [String] the connection uri
62
+ # @param options [Hash] a hash of non-mandatory adapter options
62
63
  #
63
64
  # @return [Lotus::Model::Adapters::FileSystemAdapter]
64
65
  #
@@ -66,7 +67,7 @@ module Lotus
66
67
  #
67
68
  # @api private
68
69
  # @since 0.2.0
69
- def initialize(mapper, uri)
70
+ def initialize(mapper, uri, options = {})
70
71
  super
71
72
  prepare(uri)
72
73
 
@@ -24,6 +24,7 @@ module Lotus
24
24
  #
25
25
  # @param mapper [Object] the database mapper
26
26
  # @param uri [String] the connection uri (ignored)
27
+ # @param options [Hash] a hash of non mandatory adapter options
27
28
  #
28
29
  # @return [Lotus::Model::Adapters::MemoryAdapter]
29
30
  #
@@ -31,7 +32,7 @@ module Lotus
31
32
  #
32
33
  # @api private
33
34
  # @since 0.1.0
34
- def initialize(mapper, uri = nil)
35
+ def initialize(mapper, uri = nil, options = {})
35
36
  super
36
37
 
37
38
  @mutex = Mutex.new
@@ -1,10 +1,12 @@
1
+ require 'lotus/model/error'
2
+
1
3
  module Lotus
2
4
  module Model
3
5
  module Adapters
4
6
  # @since 0.2.0
5
- class NoAdapterError < ::StandardError
7
+ class NoAdapterError < Lotus::Model::Error
6
8
  def initialize(method_name)
7
- super("Cannot invoke `#{ method_name }' without selecting an adapter. Please check your framework configuration.")
9
+ super("Cannot invoke `#{ method_name }' on repository. Please check if `adapter' and `mapping' are set.")
8
10
  end
9
11
  end
10
12
 
@@ -28,6 +28,7 @@ module Lotus
28
28
  #
29
29
  # @param mapper [Object] the database mapper
30
30
  # @param uri [String] the connection uri for the database
31
+ # @param options [Hash] a hash of non-mandatory adapter options
31
32
  #
32
33
  # @return [Lotus::Model::Adapters::SqlAdapter]
33
34
  #
@@ -41,9 +42,9 @@ module Lotus
41
42
  #
42
43
  # @api private
43
44
  # @since 0.1.0
44
- def initialize(mapper, uri)
45
+ def initialize(mapper, uri, options = {})
45
46
  super
46
- @connection = Sequel.connect(@uri)
47
+ @connection = Sequel.connect(@uri, @options)
47
48
  rescue Sequel::AdapterNotFound => e
48
49
  raise DatabaseAdapterNotFound.new(e.message)
49
50
  end
@@ -6,7 +6,7 @@ module Lotus
6
6
  # Raised when an adapter class does not exist
7
7
  #
8
8
  # @since 0.2.0
9
- class AdapterNotFound < ::StandardError
9
+ class AdapterNotFound < Lotus::Model::Error
10
10
  def initialize(adapter_name)
11
11
  super "Cannot find Lotus::Model adapter #{adapter_name}"
12
12
  end
@@ -46,6 +46,10 @@ module Lotus
46
46
  # @since 0.2.0
47
47
  attr_reader :uri
48
48
 
49
+ # @return [Hash] a list of non-mandatory options for the adapter
50
+ #
51
+ attr_reader :options
52
+
49
53
  # @return [String] the adapter class name
50
54
  #
51
55
  # @since 0.2.0
@@ -62,8 +66,12 @@ module Lotus
62
66
  #
63
67
  # @since 0.2.0
64
68
  def initialize(**options)
65
- @type = options[:type]
66
- @uri = options[:uri]
69
+ opts = options.dup
70
+
71
+ @type = opts.delete(:type)
72
+ @uri = opts.delete(:uri)
73
+ @options = opts
74
+
67
75
  @class_name ||= Lotus::Utils::String.new("#{@type}_adapter").classify
68
76
  end
69
77
 
@@ -94,7 +102,7 @@ module Lotus
94
102
  def instantiate_adapter(mapper)
95
103
  begin
96
104
  klass = Lotus::Utils::Class.load!(class_name, Lotus::Model::Adapters)
97
- klass.new(mapper, uri)
105
+ klass.new(mapper, uri, options)
98
106
  rescue NameError
99
107
  raise AdapterNotFound.new(class_name)
100
108
  rescue => e
@@ -0,0 +1,7 @@
1
+ module Lotus
2
+ module Model
3
+ # @since 0.5.1
4
+ class Error < ::StandardError
5
+ end
6
+ end
7
+ end
@@ -8,7 +8,7 @@ module Lotus
8
8
  # @since 0.2.0
9
9
  #
10
10
  # @see Lotus::Model::Configuration#mapping
11
- class NoMappingError < ::StandardError
11
+ class NoMappingError < Lotus::Model::Error
12
12
  def initialize
13
13
  super("Mapping is missing. Please check your framework configuration.")
14
14
  end
@@ -14,7 +14,7 @@ module Lotus
14
14
  # collection.
15
15
  #
16
16
  # @since 0.1.0
17
- class UnmappedCollectionError < ::StandardError
17
+ class UnmappedCollectionError < Lotus::Model::Error
18
18
  def initialize(name)
19
19
  super("Cannot find collection: #{ name }")
20
20
  end
@@ -26,7 +26,7 @@ module Lotus
26
26
  # entity.
27
27
  #
28
28
  # @since 0.2.0
29
- class EntityNotFound < ::StandardError
29
+ class EntityNotFound < Lotus::Model::Error
30
30
  def initialize(name)
31
31
  super("Cannot find class for entity: #{ name }")
32
32
  end
@@ -38,7 +38,7 @@ module Lotus
38
38
  # repository.
39
39
  #
40
40
  # @since 0.2.0
41
- class RepositoryNotFound < ::StandardError
41
+ class RepositoryNotFound < Lotus::Model::Error
42
42
  def initialize(name)
43
43
  super("Cannot find class for repository: #{ name }")
44
44
  end
@@ -8,7 +8,7 @@ module Lotus
8
8
  # Migration error
9
9
  #
10
10
  # @since 0.4.0
11
- class MigrationError < ::StandardError
11
+ class MigrationError < Lotus::Model::Error
12
12
  end
13
13
 
14
14
  # Define a migration
@@ -292,6 +292,8 @@ module Lotus
292
292
  Sequel.connect(
293
293
  configuration.adapter.uri
294
294
  )
295
+ rescue Sequel::AdapterNotFound
296
+ raise MigrationError.new("Current adapter (#{ configuration.adapter.type }) doesn't support SQL database operations.")
295
297
  end
296
298
 
297
299
  # Lotus::Model configuration
@@ -10,6 +10,14 @@ module Lotus
10
10
  # @api private
11
11
  def create
12
12
  new_connection(global: true).run %(CREATE DATABASE #{ database };)
13
+ rescue Sequel::DatabaseError => e
14
+ message = if e.message.match(/database exists/)
15
+ "Database creation failed. There is 1 other session using the database"
16
+ else
17
+ e.message
18
+ end
19
+
20
+ raise MigrationError.new(message)
13
21
  end
14
22
 
15
23
  # @since 0.4.0
@@ -26,7 +26,16 @@ module Lotus
26
26
  # @api private
27
27
  def create
28
28
  set_environment_variables
29
- `createdb #{ database }`
29
+
30
+ call_db_command('createdb') do |error_message|
31
+ message = if error_message.match(/already exists/)
32
+ "createdb: database creation failed. There is 1 other session using the database."
33
+ else
34
+ error_message
35
+ end
36
+
37
+ raise MigrationError.new(message)
38
+ end
30
39
  end
31
40
 
32
41
  # @since 0.4.0
@@ -34,22 +43,14 @@ module Lotus
34
43
  def drop
35
44
  set_environment_variables
36
45
 
37
- require 'open3'
38
-
39
- Open3.popen3('dropdb', database) do |stdin, stdout, stderr, wait_thr|
40
- exit_status = wait_thr.value
41
-
42
- unless exit_status.success?
43
- error_message = stderr.read
44
-
45
- message = if error_message.match(/does not exist/)
46
- "Cannot find database: #{ database }"
47
- else
48
- message
49
- end
50
-
51
- raise MigrationError.new(message)
46
+ call_db_command('dropdb') do |error_message|
47
+ message = if error_message.match(/does not exist/)
48
+ "Cannot find database: #{ database }"
49
+ else
50
+ error_message
52
51
  end
52
+
53
+ raise MigrationError.new(message)
53
54
  end
54
55
  end
55
56
 
@@ -96,6 +97,22 @@ module Lotus
96
97
  def dump_migrations_data
97
98
  system "pg_dump -t #{ migrations_table } #{ database } >> #{ escape(schema) }"
98
99
  end
100
+
101
+ # @since 0.5.1
102
+ # @api private
103
+ def call_db_command(command)
104
+ require 'open3'
105
+
106
+ begin
107
+ Open3.popen3(command, database) do |stdin, stdout, stderr, wait_thr|
108
+ unless wait_thr.value.success? # wait_thr.value is the exit status
109
+ yield stderr.read
110
+ end
111
+ end
112
+ rescue SystemCallError => e
113
+ yield e.message
114
+ end
115
+ end
99
116
  end
100
117
  end
101
118
  end
@@ -3,6 +3,6 @@ module Lotus
3
3
  # Defines the version
4
4
  #
5
5
  # @since 0.1.0
6
- VERSION = '0.5.0'.freeze
6
+ VERSION = '0.5.1'.freeze
7
7
  end
8
8
  end
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ['lib']
20
20
  spec.required_ruby_version = '>= 2.0.0'
21
21
 
22
- spec.add_runtime_dependency 'lotus-utils', '~> 0.5'
22
+ spec.add_runtime_dependency 'lotus-utils', '~> 0.6'
23
23
  spec.add_runtime_dependency 'sequel', '~> 4.9'
24
24
 
25
25
  spec.add_development_dependency 'bundler', '~> 1.6'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lotus-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-09-30 00:00:00.000000000 Z
13
+ date: 2016-01-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: lotus-utils
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - "~>"
20
20
  - !ruby/object:Gem::Version
21
- version: '0.5'
21
+ version: '0.6'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - "~>"
27
27
  - !ruby/object:Gem::Version
28
- version: '0.5'
28
+ version: '0.6'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: sequel
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -120,6 +120,7 @@ files:
120
120
  - lib/lotus/model/config/adapter.rb
121
121
  - lib/lotus/model/config/mapper.rb
122
122
  - lib/lotus/model/configuration.rb
123
+ - lib/lotus/model/error.rb
123
124
  - lib/lotus/model/mapper.rb
124
125
  - lib/lotus/model/mapping.rb
125
126
  - lib/lotus/model/mapping/attribute.rb
@@ -155,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
156
  version: '0'
156
157
  requirements: []
157
158
  rubyforge_project:
158
- rubygems_version: 2.4.5.1
159
+ rubygems_version: 2.5.1
159
160
  signing_key:
160
161
  specification_version: 4
161
162
  summary: A persistence layer for Lotus