lotus-model 0.5.0 → 0.5.1

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.
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