appquery 0.2.0 → 0.3.0

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
  SHA256:
3
- metadata.gz: c63ba7b9e16d2f5b7071f8dd9203695f3c46b956d0302ff27a5cab0970cc598f
4
- data.tar.gz: 71bebdc43197fce0e8917a3e6f4be0615bcb28215ef004b2496ce0554241c54d
3
+ metadata.gz: 64e74167bbafa7217db5f9c0bab6efc8b55655abbbcb7e2fccefca3dfe1afae8
4
+ data.tar.gz: 16f6870106206b547ed307fb6cbcd8d9250610239ccf9dc046e6e6c9719d76dd
5
5
  SHA512:
6
- metadata.gz: 4f372fb1b1e524e05a2cdf5338d1114f76e08df3b2ec2028e9ec42b515dcbfe4c4c6d9d318a367351e884cfc3ed8e0c670f215d2ccdb072753271fa248993eed
7
- data.tar.gz: d91262c52aac1d7cb753eab122c2fbf7d352bd160f5112e3139cf1b5bda848e05456644d3e8e37b2c038ba0795fcfe707470c5bb903cc05e0d0d81a30725de80
6
+ metadata.gz: 74ce3c5a8d22b2b41bc477069e9720c7b91cad52909ee3e4db8533c0a6f357227ec7e9485f513b8306a0d4994b53556971ae09284c72c2c5370bee45a0c244e3
7
+ data.tar.gz: 61b01b05753f3a6f27194e47b40bb91aa822c5c263dbe78d0328f1b09aad02d95acbfc7ba191d4fb773b536c1b1ad03465e05c87c4ecf1dc279ed3e461ba97b2
data/Appraisals ADDED
@@ -0,0 +1,15 @@
1
+ appraise "rails-70" do
2
+ gem "rails", "~> 7.0"
3
+ end
4
+
5
+ appraise "rails-71" do
6
+ gem "rails", "~> 7.1"
7
+ end
8
+
9
+ appraise "rails-72" do
10
+ gem "rails", "~> 7.2"
11
+ end
12
+
13
+ appraise "rails-80" do
14
+ gem "rails", "~> 8.0"
15
+ end
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2024 Gert Goet
3
+ Copyright (c) 2025 Gert Goet
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/appquery.svg)](https://badge.fury.io/rb/appquery)
4
4
 
5
- A Rubygem :gem: that makes working with raw SQL queries in Rails projects more convenient.
5
+ A Rubygem :gem: that makes working with raw SQL (READ) queries in Rails projects more convenient.
6
6
  Specifically it provides:
7
7
  - **...a dedicated folder for queries**
8
8
  e.g. `app/queries/reports/weekly.sql` is instantiated via `AppQuery["reports/weekly"]`.
@@ -13,6 +13,31 @@ Specifically it provides:
13
13
  invoke rspec
14
14
  create spec/queries/reports/weekly_query_spec.rb
15
15
  ```
16
+ - **...ERB templating**
17
+ Simple ERB templating with helper-functions:
18
+ ```sql
19
+ -- app/queries/contracts.sql.erb
20
+ SELECT * FROM contracts
21
+ <%= order_by(order) %>
22
+ ```
23
+ ```ruby
24
+ AppQuery["contracts.sql.erb"].render(order: {year: :desc, month: :desc}).select_all
25
+ ```
26
+ - **...positional and named binds**
27
+ Intuitive binds:
28
+ ```ruby
29
+ AppQuery(%{select now() - (:interval)::interval as some_date}).select_value(binds: {interval: '1 day'})
30
+ AppQuery(<<~SQL).select_all(binds: [2.day.ago, Time.now, '5 minutes']).column("series")
31
+ select generate_series($1::timestamp, $2::timestamp, $3::interval) as series
32
+ SQL
33
+ ```
34
+ - **...casting**
35
+ Automatic and custom casting:
36
+ ```ruby
37
+ AppQuery(%{select array[1,2]}).select_value #=> [1,2]
38
+ cast = {"data" => ActiveRecord::Type::Json.new}
39
+ AppQuery(%{select '{"a": 1}' as data}).select_value(cast:)
40
+ ```
16
41
  - **...helpers to rewrite a query for introspection during development and testing**
17
42
  See what a CTE yields: `query.select_all(select: "SELECT * FROM some_cte")`.
18
43
  Query the end result: `query.select_one(select: "SELECT COUNT(*) FROM _ WHERE ...")`.
@@ -38,7 +63,12 @@ Specifically it provides:
38
63
 
39
64
  > [!IMPORTANT]
40
65
  > **Status**: alpha. API might change. See the CHANGELOG for breaking changes when upgrading.
41
- >
66
+ >
67
+
68
+ ## Rationale
69
+
70
+ Sometimes ActiveRecord doesn't cut it, and you'd rather use raw SQL to get the right data out. That, however, introduces some new problems. First of all, you'll run into the not-so-intuitive use of [select_(all|one|value)](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-select_all) — for example, how they differ with respect to type casting, and how their behavior can vary between ActiveRecord versions. Then there's the testability, introspection, and maintainability of the resulting SQL queries.
71
+ This library aims to alleviate all of these issues by providing a consistent interface across select_* methods and ActiveRecord versions. It should make inspecting and testing queries easier—especially when they're built from CTEs.
42
72
 
43
73
  ## Installation
44
74
 
@@ -53,7 +83,83 @@ bundle add appquery
53
83
  > [!NOTE]
54
84
  > The following (trivial) examples are not meant to convince you to ditch your ORM, but just to show how this gem handles raw SQL queries.
55
85
 
56
- ### Create
86
+ ### ...from console
87
+
88
+ Testdriving can be easily done from the console. Either by cloning this repository (recommended, see `Development`-section) or installing the gem in an existing Rails project.
89
+ <details>
90
+ <summary>Database setup (the `bin/console`-script does this for your)</summary>
91
+
92
+ ```ruby
93
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
94
+ ActiveRecord::Base.establish_connection(url: 'postgres://localhost:5432/some_db')
95
+ ```
96
+ </details>
97
+
98
+ The following examples assume PostgreSQL (SQLite where stated):
99
+
100
+ ```ruby
101
+ # showing select_(all|one|value)
102
+ > AppQuery(%{select date('now') as today}).select_all.to_a
103
+ => [{"today" => "2025-05-10"}]
104
+ > AppQuery(%{select date('now') as today}).select_one
105
+ => {"today" => "2025-05-10"}
106
+ > AppQuery(%{select date('now') as today}).select_value
107
+ => "2025-05-10"
108
+
109
+ # binds
110
+ # positional binds
111
+ > AppQuery(%{select now() - ($1)::interval as date}).select_value(binds: ['2 days'])
112
+ # named binds
113
+ > AppQuery(%{select now() - (:interval)::interval as date}).select_value(binds: {interval: '2 days'})
114
+
115
+ # casting
116
+ > AppQuery(%{select date('now') as today}).select_all(cast: true).to_a
117
+ => [{"today" => Sat, 10 May 2025}]
118
+
119
+ ## SQLite doesn't have a notion of dates or timestamp's so casting won't do anything:
120
+ sqlite> AppQuery(%{select date('now') as today}).select_one(cast: true)
121
+ => {"today" => "2025-05-12"}
122
+ ## Providing per-column-casts fixes this:
123
+ casts = {"today" => ActiveRecord::Type::Date.new}
124
+ sqlite> AppQuery(%{select date('now') as today}).select_one(cast: casts)
125
+ => {"today" => Mon, 12 May 2025}
126
+
127
+ # rewriting queries (using CTEs)
128
+ q = AppQuery(<<~SQL)
129
+ WITH articles(id,title,published_on) AS (
130
+ values(1, 'Some title', '2024-3-31'),
131
+ (2, 'Other title', '2024-10-31'),
132
+ (3, 'Same title?', '2024-3-31'))
133
+ select * from articles order by id DESC
134
+ SQL
135
+
136
+ ## query the articles-CTE
137
+ q.select_all(select: %{select * from articles where id < 2}).to_a
138
+
139
+ ## query the end-result (available as the CTE named '_')
140
+ q.select_one(select: %{select * from _ limit 1})
141
+
142
+ ## ERB templating
143
+ # Extract a query from q that can be sorted dynamically:
144
+ q2 = q.with_select("select id,title,published_on::date from articles <%= order_by(order) %>")
145
+ q2.render(order: {"published_on::date": :desc, 'lower(title)': "asc"}).select_all.entries
146
+ # shows latest articles first, and titles sorted alphabetically
147
+ # for articles published on the same date.
148
+ # order_by raises when it's passed something that would result in just `ORDER BY`:
149
+ q2.render(order: {})
150
+ # doing a select using a query that should be rendered, a `AppQuery::UnrenderedQueryError` will be raised:
151
+ q2.select_all.entries
152
+
153
+ # NOTE you can use both `order` and `@order`: local variables like `order` are required,
154
+ # while instance variables like `@order` are optional.
155
+ # To skip the order-part when provided:
156
+ <%= @order.presence && order_by(order) %>
157
+ # or use a default when order-part is always wanted but not always provided:
158
+ <%= order_by(@order || {id: :desc}) %>
159
+ ```
160
+
161
+
162
+ ### ...in a Rails project
57
163
 
58
164
  > [!NOTE]
59
165
  > The included [example Rails app](./examples/ror) contains all data and queries described below.
@@ -462,17 +568,29 @@ query.replace_cte("recent_articles as (select values(1, 'Some article'))")
462
568
 
463
569
  - 💾 tested with **SQLite** and **PostgreSQL**
464
570
  - 🚆 tested with Rails **v6.1**, **v7** and **v8.0**
465
- - 💎 requires Ruby **>v3.1**
571
+ - 💎 requires Ruby **>v3.2**
466
572
  Goal is to support [maintained Ruby versions](https://www.ruby-lang.org/en/downloads/branches/).
467
573
 
468
574
  ## Development
469
575
 
470
576
  After checking out the repo, run `bin/setup` to install dependencies. **Make sure to check it exits with status code 0.**
471
577
 
472
- Using [direnv](https://direnv.net/) for env-vars recommended.
578
+ Using [mise](https://mise.jdx.dev/) for env-vars recommended.
579
+
580
+ ### console
581
+
582
+ The [console-script](./bin/console) is setup such that it's easy to connect with a database and experiment with the library:
583
+ ```bash
584
+ $ ./bin/console sqlite3::memory:
585
+ $ ./bin/console postgres://localhost:5432/some_db
586
+
587
+ # more details
588
+ $ ./bin/console -h
589
+ ```
473
590
 
591
+ ### various
474
592
 
475
- Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
593
+ Run `rake spec` to run the tests.
476
594
 
477
595
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
478
596
 
@@ -483,4 +601,3 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/eval/a
483
601
  ## License
484
602
 
485
603
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
486
-
@@ -0,0 +1,45 @@
1
+ module AppQuery
2
+ class Base
3
+ class_attribute :_cast, default: true, instance_predicate: false
4
+ class_attribute :_default_binds, default: {}, instance_predicate: false
5
+
6
+ class << self
7
+ def run(build_only: false, binds: {}, vars: {}, cast: self.cast, select: nil, **)
8
+ _build(binds:, vars:, cast:, select:).then do
9
+ build_only ? _1 : _1.select_all
10
+ end
11
+ end
12
+
13
+ def build(**opts)
14
+ run(build_only: true, **opts)
15
+ end
16
+
17
+ def default_binds(v = nil)
18
+ return _default_binds if v.nil?
19
+ self._default_binds = v
20
+ end
21
+
22
+ def cast(v = nil)
23
+ return _cast if v.nil?
24
+ self._cast = v
25
+ end
26
+
27
+ def query_name
28
+ derive_query_name unless defined?(@query_name)
29
+ @query_name
30
+ end
31
+
32
+ attr_writer :query_name
33
+
34
+ private
35
+
36
+ def _build(cast:, binds: {}, select: nil, vars: {})
37
+ AppQuery[query_name, binds:, cast:].render(vars).with_select(select)
38
+ end
39
+
40
+ def derive_query_name
41
+ self.query_name = name.underscore.sub(/_query$/, "")
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppQuery
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/app_query.rb CHANGED
@@ -7,6 +7,8 @@ require "active_record"
7
7
  module AppQuery
8
8
  class Error < StandardError; end
9
9
 
10
+ class UnrenderedQueryError < StandardError; end
11
+
10
12
  Configuration = Struct.new(:query_path)
11
13
 
12
14
  def self.configuration
@@ -24,10 +26,14 @@ module AppQuery
24
26
  end
25
27
  reset_configuration!
26
28
 
27
- def self.[](v)
28
- query_name = v.to_s
29
- full_path = (Pathname.new(configuration.query_path) / "#{query_name}.sql").expand_path
30
- Q.new(full_path.read, name: "AppQuery #{query_name}")
29
+ # Examples:
30
+ # AppQuery[:invoices] # looks for invoices.sql
31
+ # AppQuery["reports/weekly"]
32
+ # AppQuery["invoices.sql.erb"]
33
+ def self.[](query_name, **opts)
34
+ filename = File.extname(query_name.to_s).empty? ? "#{query_name}.sql" : query_name.to_s
35
+ full_path = (Pathname.new(configuration.query_path) / filename).expand_path
36
+ Q.new(full_path.read, name: "AppQuery #{query_name}", filename: full_path.to_s, **opts)
31
37
  end
32
38
 
33
39
  class Result < ActiveRecord::Result
@@ -50,6 +56,10 @@ module AppQuery
50
56
  rows.map { _1[ix] }
51
57
  end
52
58
 
59
+ def size
60
+ count
61
+ end
62
+
53
63
  def self.from_ar_result(r, cast = nil)
54
64
  if r.empty?
55
65
  EMPTY
@@ -73,7 +83,7 @@ module AppQuery
73
83
  # => [["{1,2}"]]
74
84
  # > ActiveRecord::Base.connection.select_all("select array[1,2]").cast_values
75
85
  # => [[1, 2]]
76
- rows = rows.map { [_1] } if r.columns.one?
86
+ rows = rows.zip if r.columns.one?
77
87
  new(r.columns, rows, overrides, cast: true)
78
88
  end
79
89
  end
@@ -88,27 +98,102 @@ module AppQuery
88
98
  end
89
99
 
90
100
  class Q
91
- attr_reader :name, :sql
101
+ attr_reader :name, :sql, :binds, :cast
92
102
 
93
- def initialize(sql, name: nil)
103
+ def initialize(sql, name: nil, filename: nil, binds: [], cast: true)
94
104
  @sql = sql
95
105
  @name = name
106
+ @filename = filename
107
+ @binds = binds
108
+ @cast = cast
109
+ end
110
+
111
+ def deep_dup
112
+ super.send(:reset!)
96
113
  end
97
114
 
98
- def select_all(binds: [], select: nil, cast: false)
99
- with_select(select).then do |aq|
100
- ActiveRecord::Base.connection.select_all(aq.to_s, name, binds).then do |result|
101
- Result.from_ar_result(result, cast)
115
+ def reset!
116
+ (instance_variables - %i[@sql @filename @name @binds @cast]).each do
117
+ instance_variable_set(_1, nil)
118
+ end
119
+ self
120
+ end
121
+ private :reset!
122
+
123
+ def render(vars)
124
+ vars ||= {}
125
+ with_sql(to_erb.result(render_helper(vars).get_binding))
126
+ end
127
+
128
+ def to_erb
129
+ ERB.new(sql, trim_mode: "-").tap { _1.location = [@filename, 0] if @filename }
130
+ end
131
+ private :to_erb
132
+
133
+ def render_helper(vars)
134
+ Module.new do
135
+ extend self
136
+
137
+ vars.each do |k, v|
138
+ define_method(k) { v }
139
+ instance_variable_set(:"@#{k}", v)
140
+ end
141
+
142
+ # Examples
143
+ # <%= order_by({year: :desc, month: :desc}) %>
144
+ # #=> ORDER BY year DESC, month DESC
145
+ #
146
+ # Using variable:
147
+ # <%= order_by(ordering) %>
148
+ # NOTE Raises when ordering not provided or when blank.
149
+ #
150
+ # Make it optional:
151
+ # <%= @ordering.presence && order_by(ordering) %>
152
+ #
153
+ def order_by(hash)
154
+ raise ArgumentError, "Provide columns to sort by, e.g. order_by(id: :asc) (got #{hash.inspect})." unless hash.present?
155
+ "ORDER BY " + hash.map do |k, v|
156
+ v.nil? ? k : [k, v.upcase].join(" ")
157
+ end.join(", ")
158
+ end
159
+
160
+ def get_binding
161
+ binding
102
162
  end
103
163
  end
104
164
  end
165
+ private :render_helper
166
+
167
+ def select_all(binds: [], select: nil, cast: self.cast)
168
+ binds = binds.presence || @binds
169
+ with_select(select).render({}).then do |aq|
170
+ if binds.is_a?(Hash)
171
+ sql = if ActiveRecord::VERSION::STRING.to_f >= 7.1
172
+ Arel.sql(aq.to_s, **binds)
173
+ else
174
+ ActiveRecord::Base.sanitize_sql_array([aq.to_s, **binds])
175
+ end
176
+ ActiveRecord::Base.connection.select_all(sql, name).then do |result|
177
+ Result.from_ar_result(result, cast)
178
+ end
179
+ else
180
+ ActiveRecord::Base.connection.select_all(aq.to_s, name, binds).then do |result|
181
+ Result.from_ar_result(result, cast)
182
+ end
183
+ end
184
+ end
185
+ rescue NameError => e
186
+ # Prevent any subclasses, e.g. NoMethodError
187
+ raise e unless e.instance_of?(NameError)
188
+ raise UnrenderedQueryError, "Query is ERB. Use #render before select-ing."
189
+ end
105
190
 
106
- def select_one(binds: [], select: nil, cast: false)
107
- select_all(binds:, select:, cast:).first || {}
191
+ def select_one(binds: [], select: nil, cast: self.cast)
192
+ select_all(binds:, select:, cast:).first
108
193
  end
109
194
 
110
- def select_value(binds: [], select: nil, cast: false)
111
- select_one(binds:, select:, cast:).values.first
195
+ def select_value(binds: [], select: nil, cast: self.cast)
196
+ select_one(binds:, select:, cast:)&.values&.first
112
197
  end
113
198
 
114
199
  def tokens
@@ -123,13 +208,31 @@ module AppQuery
123
208
  tokens.filter { _1[:t] == "CTE_IDENTIFIER" }.map { _1[:v] }
124
209
  end
125
210
 
211
+ def with_binds(binds)
212
+ deep_dup.tap do
213
+ _1.instance_variable_set(:@binds, binds)
214
+ end
215
+ end
216
+
217
+ def with_cast(cast)
218
+ deep_dup.tap do
219
+ _1.instance_variable_set(:@cast, cast)
220
+ end
221
+ end
222
+
223
+ def with_sql(sql)
224
+ deep_dup.tap do
225
+ _1.instance_variable_set(:@sql, sql)
226
+ end
227
+ end
228
+
126
229
  def with_select(sql)
127
- return self unless sql
230
+ return self if sql.nil?
128
231
  if cte_names.include?("_")
129
- self.class.new(tokens.each_with_object([]) do |token, acc|
232
+ with_sql(tokens.each_with_object([]) do |token, acc|
130
233
  v = (token[:t] == "SELECT") ? sql : token[:v]
131
234
  acc << v
132
- end.join, name: name)
235
+ end.join)
133
236
  else
134
237
  append_cte("_ as (\n #{select}\n)").with_select(sql)
135
238
  end
@@ -152,10 +255,10 @@ module AppQuery
152
255
  end
153
256
 
154
257
  if cte_names.none?
155
- self.class.new("WITH #{cte}\n#{self}")
258
+ with_sql("WITH #{cte}\n#{self}")
156
259
  else
157
260
  split_at_type = recursive? ? "RECURSIVE" : "WITH"
158
- self.class.new(tokens.map do |token|
261
+ with_sql(tokens.map do |token|
159
262
  if token[:t] == split_at_type
160
263
  token[:v] + to_append.map { _1[:v] }.join
161
264
  else
@@ -175,11 +278,11 @@ module AppQuery
175
278
  end
176
279
 
177
280
  if cte_names.none?
178
- self.class.new("WITH #{cte}\n#{self}")
281
+ with_sql("WITH #{cte}\n#{self}")
179
282
  else
180
283
  nof_ctes = cte_names.size
181
284
 
182
- self.class.new(tokens.map do |token|
285
+ with_sql(tokens.map do |token|
183
286
  nof_ctes -= 1 if token[:t] == "CTE_SELECT"
184
287
 
185
288
  if nof_ctes.zero?
@@ -212,7 +315,7 @@ module AppQuery
212
315
 
213
316
  cte_found = false
214
317
 
215
- self.class.new(tokens.map do |token|
318
+ with_sql(tokens.map do |token|
216
319
  if cte_found ||= token[:t] == "CTE_IDENTIFIER" && token[:v] == cte_name
217
320
  unless (cte_found = (token[:t] != "CTE_SELECT"))
218
321
  next to_append.map { _1[:v] }.join
@@ -243,3 +346,5 @@ rescue LoadError
243
346
  end
244
347
 
245
348
  require_relative "app_query/rspec" if Object.const_defined? :RSpec
349
+
350
+ require "app_query/base" if defined?(ActiveRecord::Base)
@@ -0,0 +1,5 @@
1
+ [env]
2
+ # used for tests
3
+ PG_DATABASE_URL="postgres://localhost:5432/some_db
4
+ # used from console
5
+ DATABASE_URL="postgres://localhost:5432/some_db
data/mise.toml ADDED
@@ -0,0 +1,6 @@
1
+ [tools]
2
+ ruby = "3.4"
3
+
4
+ [env]
5
+ _.path = ["bin"]
6
+ PROJECT_ROOT = "{{config_root}}"
metadata CHANGED
@@ -1,15 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appquery
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gert Goet
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-11-13 00:00:00.000000000 Z
12
- dependencies: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: appraisal
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
13
26
  description: "Improving introspection and testability of raw SQL queries in Rails\nThis
14
27
  gem improves introspection and testability of raw SQL queries in Rails by:\n- ...providing
15
28
  a separate query-folder and easy instantiation \n A query like `AppQuery[:some_query]`
@@ -27,15 +40,15 @@ executables: []
27
40
  extensions: []
28
41
  extra_rdoc_files: []
29
42
  files:
30
- - ".envrc"
31
- - ".envrc.private.example"
32
43
  - ".rspec"
33
44
  - ".standard.yml"
45
+ - Appraisals
34
46
  - CHANGELOG.md
35
47
  - LICENSE.txt
36
48
  - README.md
37
49
  - Rakefile
38
50
  - lib/app_query.rb
51
+ - lib/app_query/base.rb
39
52
  - lib/app_query/rspec.rb
40
53
  - lib/app_query/rspec/helpers.rb
41
54
  - lib/app_query/tokenizer.rb
@@ -46,8 +59,9 @@ files:
46
59
  - lib/rails/generators/query/templates/query.sql.tt
47
60
  - lib/rails/generators/rspec/query_generator.rb
48
61
  - lib/rails/generators/rspec/templates/query_spec.rb.tt
62
+ - mise.local.toml.example
63
+ - mise.toml
49
64
  - sig/appquery.rbs
50
- - tmp/.gitkeep
51
65
  homepage: https://github.com/eval/appquery
52
66
  licenses:
53
67
  - MIT
@@ -55,7 +69,6 @@ metadata:
55
69
  homepage_uri: https://github.com/eval/appquery
56
70
  source_code_uri: https://github.com/eval/appquery
57
71
  changelog_uri: https://github.com/eval/gem-try/blob/main/CHANGELOG.md
58
- post_install_message:
59
72
  rdoc_options: []
60
73
  require_paths:
61
74
  - lib
@@ -63,15 +76,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
63
76
  requirements:
64
77
  - - ">="
65
78
  - !ruby/object:Gem::Version
66
- version: 3.1.0
79
+ version: 3.2.0
67
80
  required_rubygems_version: !ruby/object:Gem::Requirement
68
81
  requirements:
69
82
  - - ">="
70
83
  - !ruby/object:Gem::Version
71
84
  version: '0'
72
85
  requirements: []
73
- rubygems_version: 3.5.22
74
- signing_key:
86
+ rubygems_version: 3.6.7
75
87
  specification_version: 4
76
88
  summary: "raw SQL \U0001F966, cooked \U0001F372 or: make working with raw SQL queries
77
89
  in Rails convenient by improving their introspection and testability."
data/.envrc DELETED
@@ -1,6 +0,0 @@
1
- # direnv config
2
- PATH_add bin
3
-
4
- export APP_ROOT=$(pwd)
5
-
6
- source_env_if_exists .envrc.private
@@ -1,2 +0,0 @@
1
- # copy this to .envrc.private to use with direnv
2
- export PG_DATABASE_URL=postgres://localhost:5432/some_db
data/tmp/.gitkeep DELETED
File without changes