hanami-db 2.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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: []