hanami-db 2.2.0.beta1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3b8f0855774dd7a9d0edc7609c7a07b95080edb38a6d30cab7454c5eb61a3e67
4
+ data.tar.gz: 1398ac362dcab2ac3f74cc59e328b5264c7326ddd6bec6502e3cd747bdceeedc
5
+ SHA512:
6
+ metadata.gz: bf77b5817253e28718b84495d45cc6fe1665718c1c008f70577615e1f4c259e39adbfac342112761b30cd699e1b249b88f05b0d839d8955a2201fa645cd84ac0
7
+ data.tar.gz: b212e3a4b636b0d7bda6a31fad889105a47b9c26a4c094d0a16e1369c41ff01c0fa79a2eefebfa64bce84e3abf5cf6d926d29ec323d5955cc4d0702fcf7a3c5c
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ Copyright © 2024 Tim Riley
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # Hanami::DB
2
+
3
+ The database layer for [full-stack Hanami 2.2 applications](hanami/hanami).
4
+ It's a thin layer on top of [ROM](https://rom-rb.org/) 5.
5
+
6
+ ## Status
7
+
8
+ [![Gem Version](https://badge.fury.io/rb/hanami-db.svg)](https://badge.fury.io/rb/db)
9
+ [![CI](https://github.com/hanami/db/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/hanami/db/actions?query=workflow%3Aci+branch%3Amain)
10
+ [![Depfu](https://badges.depfu.com/badges/7cd17419fba78b726be1353118fb01de/overview.svg)](https://depfu.com/github/hanami/controller?project=Bundler)
11
+
12
+ ## Contact
13
+
14
+ * Home page: http://hanamirb.org
15
+ * Community: http://hanamirb.org/community
16
+ * Guides: https://guides.hanamirb.org
17
+ * Mailing List: http://hanamirb.org/mailing-list
18
+ * API Doc: http://rubydoc.info/gems/hanami-db
19
+ * Chat: http://chat.hanamirb.org
20
+
21
+
22
+ ## Installation
23
+
24
+ __Hanami::DB__ supports Ruby (MRI) 3.1+
25
+
26
+ Add this line to your Hanami application's Gemfile:
27
+
28
+ ```ruby
29
+ gem "hanami-db"
30
+ ```
31
+
32
+ And then execute:
33
+
34
+ ```shell
35
+ $ bundle
36
+ ```
37
+
38
+ ## Versioning
39
+
40
+ __Hanami::DB__ uses [Semantic Versioning 2.0.0](http://semver.org)
41
+
42
+ ## Contributing
43
+
44
+ 1. Fork it
45
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
46
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
47
+ 4. Push to the branch (`git push origin my-new-feature`)
48
+ 5. Create new Pull Request
49
+
50
+ ## Copyright
51
+
52
+ Copyright © 2024 Hanami Team – Released under MIT License
data/hanami-db.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/hanami/db/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "hanami-db"
7
+ spec.version = Hanami::DB::VERSION
8
+ spec.authors = ["Hanami team"]
9
+ spec.email = ["admin@hanamirb.org"]
10
+ spec.summary = "The database layer for Hanami apps"
11
+ spec.homepage = "https://hanamirb.org"
12
+ spec.license = "MIT"
13
+
14
+ spec.metadata = {
15
+ "bug_tracker_uri" => "https://github.com/hanami/db/issues",
16
+ "changelog_uri" => "https://github.com/hanami/db/blob/main/CHANGELOG.md",
17
+ "documentation_uri" => "https://guides.hanamirb.org",
18
+ "funding_uri" => "https://github.com/sponsors/hanami",
19
+ "source_code_uri" => "https://github.com/hanami/db",
20
+ "rubygems_mfa_required" => "true"
21
+ }
22
+
23
+ spec.required_ruby_version = ">= 3.1"
24
+ spec.add_dependency "rom", "~> 5.3"
25
+ spec.add_dependency "rom-sql", "~> 3.6", ">= 3.6.4"
26
+ spec.add_dependency "zeitwerk", "~> 2.6"
27
+
28
+ spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
29
+ spec.files = Dir["*.gemspec", "lib/**/*"]
30
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module DB
5
+ # @api private
6
+ class GemInflector < Zeitwerk::GemInflector
7
+ def camelize(basename, _abspath)
8
+ return "DB" if basename == "db"
9
+
10
+ super
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module DB
5
+ # @api public
6
+ # @since 2.2.0
7
+ class Relation < ROM::Relation[:sql]
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module DB
5
+ # @api public
6
+ # @since 2.2.0
7
+ class Repo < ROM::Repository
8
+ # @api public
9
+ # @since 2.2.0
10
+ def self.[](root)
11
+ fetch_or_store(root) do
12
+ # Override ROM::Repository.[] logic to ensure repos with explicit roots inherit from
13
+ # Hanami::DB::Repo itself, instead of the plain old ROM::Repository::Root.
14
+ Class.new(self).tap { |klass|
15
+ klass.root(root)
16
+ }
17
+ end
18
+ end
19
+
20
+ # @api public
21
+ # @since 2.2.0
22
+ defines :root
23
+
24
+ # @api public
25
+ # @since 2.2.0
26
+ attr_reader :root
27
+
28
+ # @api private
29
+ def self.inherited(klass)
30
+ super
31
+ klass.root(root)
32
+ end
33
+
34
+ # @api public
35
+ # @since 2.2.0
36
+ def initialize(*, **)
37
+ super
38
+
39
+ # Repos in Hanami apps infer a root from their class name (e.g. :posts for PostRepo). This
40
+ # means _every_ repo ends up with an inferred root, many of which will not exist as
41
+ # relations. To avoid errors from fetching these non-existent relations, check first before
42
+ # setting the root.
43
+ @root = set_relation(self.class.root) if set_relation?(self.class.root)
44
+ end
45
+
46
+ private
47
+
48
+ def set_relation?(name) # rubocop:disable Naming/AccessorMethodName
49
+ name && container.relations.key?(name)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module DB
5
+ # @api public
6
+ # @since 2.2.0
7
+ class Struct < ROM::Struct
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "uri"
5
+
6
+ module Hanami
7
+ module DB
8
+ module Testing
9
+ # Replaces development suffix in test mode
10
+ #
11
+ # @api private
12
+ # @since 2.2.0
13
+ DATABASE_NAME_SUFFIX = "_test"
14
+
15
+ # @api private
16
+ # @since 2.2.0
17
+ DATABASE_NAME_MATCHER = /_dev(elopment)?$/
18
+ private_constant :DATABASE_NAME_MATCHER
19
+
20
+ class << self
21
+ # @api private
22
+ # @since 2.2.0
23
+ def database_url(url)
24
+ url = parse_url(url)
25
+
26
+ case deconstruct_url(url)
27
+ in { scheme: "sqlite", opaque: nil, path: } unless path.nil?
28
+ url.path = database_filename(path)
29
+ in { path: String => path } if path =~ DATABASE_NAME_MATCHER
30
+ url.path = path.sub(DATABASE_NAME_MATCHER, DATABASE_NAME_SUFFIX)
31
+ in { path: String => path } unless path.end_with?(DATABASE_NAME_SUFFIX)
32
+ url.path << DATABASE_NAME_SUFFIX
33
+ else
34
+ # do nothing
35
+ end
36
+
37
+ stringify_url(url)
38
+ end
39
+
40
+ private
41
+
42
+ # @api private
43
+ # @since 2.2.0
44
+ def parse_url(url)
45
+ if url.is_a?(URI::Generic)
46
+ # URI#dup does not duplicate internal instance
47
+ # variables, making mutation dangerous.
48
+ URI(stringify_url(url))
49
+ else
50
+ URI(url.to_s)
51
+ end
52
+ end
53
+
54
+ # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
55
+
56
+ # Work around a bug in Ruby 3.0.x that erroneously omits
57
+ # the '//' prefix from hierarchical URLs.
58
+ #
59
+ # @api private
60
+ # @since 2.2.0
61
+ def stringify_url(url)
62
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.1.0")
63
+ return url.to_s
64
+ end
65
+
66
+ require "stringio"
67
+
68
+ buf = StringIO.new
69
+ buf << url.scheme
70
+ buf << ":"
71
+ buf << (url.opaque || "//")
72
+
73
+ if url.user || url.password
74
+ buf << "#{url.user}:#{url.password}@"
75
+ end
76
+
77
+ if url.host
78
+ buf << url.host
79
+ end
80
+
81
+ if url.port
82
+ buf << ":"
83
+ buf << url.port
84
+ end
85
+
86
+ if url.path
87
+ buf << url.path
88
+ end
89
+
90
+ if url.query
91
+ buf << "?"
92
+ buf << url.query
93
+ end
94
+
95
+ if url.fragment
96
+ buf << "#"
97
+ buf << url.fragment
98
+ end
99
+
100
+ buf.string
101
+ end
102
+
103
+ # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity
104
+
105
+ # Deconstructs a URI::Generic for pattern-matching.
106
+ #
107
+ # @param url [URI] Database URL parsed as URI::Generic
108
+ #
109
+ # @return [Hash]
110
+ #
111
+ # @api private
112
+ # @since 2.2.0
113
+ def deconstruct_url(url)
114
+ %i[opaque path scheme].each_with_object({}) do |part, hash|
115
+ hash[part] = url.public_send(part)
116
+ end
117
+ end
118
+
119
+ # Transform filename as with URI paths, but account for extname
120
+ #
121
+ # @param path [String] path component from URI
122
+ #
123
+ # @return [String]
124
+ #
125
+ # @api private
126
+ # @since 2.2.0
127
+ def database_filename(path)
128
+ path = Pathname(path)
129
+ ext = path.extname
130
+ database = path.basename(ext).to_s
131
+
132
+ if database =~ /^dev(elopment)?$/
133
+ database = "test"
134
+ elsif database =~ DATABASE_NAME_MATCHER
135
+ database.sub!(DATABASE_NAME_MATCHER, DATABASE_NAME_SUFFIX)
136
+ elsif !database.end_with?(DATABASE_NAME_SUFFIX)
137
+ database << DATABASE_NAME_SUFFIX
138
+ end
139
+
140
+ path.dirname.join(database + ext).to_s
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module DB
5
+ VERSION = "2.2.0.beta1"
6
+ end
7
+ end
data/lib/hanami/db.rb ADDED
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rom"
4
+ require "rom-sql"
5
+ require "zeitwerk"
6
+
7
+ module Hanami
8
+ module DB
9
+ require_relative "db/gem_inflector"
10
+
11
+ # @api private
12
+ # @since 2.2.0
13
+ def self.loader
14
+ @loader ||= Zeitwerk::Loader.new.tap do |loader|
15
+ root = File.expand_path("..", __dir__)
16
+
17
+ loader.inflector = GemInflector.new("#{root}/hanami/db.rb")
18
+ loader.tag = "hanami-db"
19
+ loader.push_dir root
20
+ loader.ignore(
21
+ "#{root}/hanami-db.rb",
22
+ "#{root}/hanami/db/gem_inflector.rb"
23
+ )
24
+ end
25
+ end
26
+ loader.setup
27
+ end
28
+ end
data/lib/hanami-db.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "hanami/db"
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hanami-db
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.2.0.beta1
5
+ platform: ruby
6
+ authors:
7
+ - Hanami team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-07-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rom
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rom-sql
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.6'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 3.6.4
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '3.6'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 3.6.4
47
+ - !ruby/object:Gem::Dependency
48
+ name: zeitwerk
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.6'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.6'
61
+ description:
62
+ email:
63
+ - admin@hanamirb.org
64
+ executables: []
65
+ extensions: []
66
+ extra_rdoc_files:
67
+ - README.md
68
+ - LICENSE.md
69
+ files:
70
+ - LICENSE.md
71
+ - README.md
72
+ - hanami-db.gemspec
73
+ - lib/hanami-db.rb
74
+ - lib/hanami/db.rb
75
+ - lib/hanami/db/gem_inflector.rb
76
+ - lib/hanami/db/relation.rb
77
+ - lib/hanami/db/repo.rb
78
+ - lib/hanami/db/struct.rb
79
+ - lib/hanami/db/testing.rb
80
+ - lib/hanami/db/version.rb
81
+ homepage: https://hanamirb.org
82
+ licenses:
83
+ - MIT
84
+ metadata:
85
+ bug_tracker_uri: https://github.com/hanami/db/issues
86
+ changelog_uri: https://github.com/hanami/db/blob/main/CHANGELOG.md
87
+ documentation_uri: https://guides.hanamirb.org
88
+ funding_uri: https://github.com/sponsors/hanami
89
+ source_code_uri: https://github.com/hanami/db
90
+ rubygems_mfa_required: 'true'
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '3.1'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubygems_version: 3.5.9
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: The database layer for Hanami apps
110
+ test_files: []