appquery 0.6.0.rc9 → 0.6.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +54 -23
  3. data/lib/app_query/version.rb +1 -1
  4. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e25e411862644c1f8c660265f3ad89dc6c42cd0d41e4ddec4bd58936f73224f
4
- data.tar.gz: 20ce2aab12e0970c6be53683d679f89efc22d3538589486b044af58e66a0aa5b
3
+ metadata.gz: d2b91bbf7a82c936eaa700c842aadc4cf3275eafbf3dab96d1f57fe0d2c208cd
4
+ data.tar.gz: 8b9180cf1818c8a7275075fc5d4fd3c3ac336146ea2ef9492205a0c0988945b7
5
5
  SHA512:
6
- metadata.gz: 18d0837262b9bf8bfaf2fc450c398cdab3f2269703169802a67820dfc65f5cfc22bbaf7d27fcf17c8643d4955e258e25a2def45f2c34a55229ef8f823ccf46c6
7
- data.tar.gz: 56d82917430c3b5e7ed140caed4df130f09cd18b4b436f8d2bb6e5d11562b438c104a961065c8e6f50c9a544bf3624fa8861424060489f76669abb85f28761b9
6
+ metadata.gz: '073497cc044bfa98614a5cdafb9b59931a9c30e635f7bd6e32c3ebb7342bab1139a7f6c651fad9fa5d804d715b61afacb412ed597f45a8225ee2a33cb50f1c19'
7
+ data.tar.gz: 183aa21ef6e49c094974deccf0edf6b6a46b9eba0bca3a04a70cce3236e720817ba5ec76d729924dd4dce3d54797372d0faaeb920e2208eb7a149ae7f65c55e0
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/appquery.svg)](https://badge.fury.io/rb/appquery)
4
4
  [![API Docs](https://img.shields.io/badge/API_Docs-YARD-blue.svg)](https://eval.github.io/appquery/)
5
5
 
6
- A Ruby gem for working with raw SQL in Rails. Store queries in `app/queries/`, execute them with proper type casting, and filter/transform results using CTEs.
6
+ A Ruby gem providing ergonomic raw SQL queries for ActiveRecord. Inline or stored queries in `app/queries/`, execute them with proper type casting, filter/transform results using CTEs and have parameterization via ERB.
7
7
 
8
8
  ```ruby
9
9
  # Load and execute
@@ -12,6 +12,8 @@ week.entries
12
12
  #=> [{"week" => 2025-01-13, "category" => "Electronics", "revenue" => 12500, "target_met" => true}, ...]
13
13
 
14
14
  # Filter results (query wraps in CTE, :_ references it)
15
+ week.count
16
+ #=> 5
15
17
  week.count("SELECT * FROM :_ WHERE NOT target_met")
16
18
  #=> 3
17
19
 
@@ -36,12 +38,14 @@ query.prepend_cte("sales AS (SELECT * FROM mock_data)")
36
38
  **Highlights**: query files with generator · `select_all`/`select_one`/`select_value`/`count`/`column`/`ids` · query transformation via CTEs · immutable (derive new queries from existing) · named binds · ERB helpers (`order_by`, `paginate`, `values`, `bind`) · automatic + custom type casting · RSpec integration
37
39
 
38
40
  > [!IMPORTANT]
39
- > **Status**: alpha. API might change. See [the CHANGELOG](./CHANGELOG.md) for breaking changes when upgrading.
41
+ > **Status**: using it in production for multiple projects, but API might change pre v1.0. See [the CHANGELOG](./CHANGELOG.md) for breaking changes when upgrading.
40
42
  >
41
43
 
42
44
  ## Rationale
43
45
 
44
- 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.
46
+ Sometimes ActiveRecord doesn't cut it: you need performance, would rather use raw SQL instead of Arel and hash-maps are fine instead of full-fledge ActiveRecord instances.
47
+ 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.
48
+
45
49
  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.
46
50
 
47
51
  ## Installation
@@ -74,29 +78,15 @@ The prompt indicates what adapter the example uses:
74
78
  ```ruby
75
79
  # showing select_(all|one|value)
76
80
  [postgresql]> AppQuery(%{select date('now') as today}).select_all.entries
77
- => [{"today" => "2025-05-10"}]
81
+ => [{"today" => Fri, 02 Jan 2026}]
78
82
  [postgresql]> AppQuery(%{select date('now') as today}).select_one
79
- => {"today" => "2025-05-10"}
83
+ => {"today" => Fri, 02 Jan 2026}
80
84
  [postgresql]> AppQuery(%{select date('now') as today}).select_value
81
- => "2025-05-10"
82
-
83
- # binds
84
- ## named binds
85
- [postgresql]> AppQuery(%{select now() - (:interval)::interval as date}).select_value(binds: {interval: '2 days'})
86
-
87
- ## not all binds need to be provided (ie they are nil by default) - so defaults can be added in SQL:
88
- [postgresql]> AppQuery(<<~SQL).select_all(binds: {ts1: 2.days.ago, ts2: Time.now, interval: '1 hour'}).column("series")
89
- SELECT generate_series(
90
- :ts1::timestamp,
91
- :ts2::timestamp,
92
- COALESCE(:interval, '5 minutes')::interval
93
- ) AS series
94
- SQL
85
+ => Fri, 02 Jan 2026
95
86
 
96
87
  # casting
97
- ## Cast values are used by default:
98
- [postgresql]> AppQuery(%{select date('now')}).select_one
99
- => {"today" => Sat, 10 May 2025}
88
+ As can be seen from these examples, values are automatically casted.
89
+
100
90
  ## compare ActiveRecord
101
91
  [postgresql]> ActiveRecord::Base.connection.select_one(%{select date('now') as today})
102
92
  => {"today" => "2025-12-20"}
@@ -109,6 +99,24 @@ cast = {today: :date}
109
99
  [sqlite]> AppQuery(%{select date('now') as today}).select_one(cast:)
110
100
  => {"today" => Mon, 12 May 2025}
111
101
 
102
+ # binds
103
+ ## named binds
104
+ [postgresql]> AppQuery(%{select now() - (:interval)::interval as date}).select_value(binds: {interval: '2 days'})
105
+ => 2025-12-31 12:57:27.41132 UTC
106
+
107
+ ## not all binds need to be provided (ie they are nil by default) - so defaults can be added in SQL:
108
+ [postgresql]> AppQuery(<<~SQL).select_all(binds: {ts1: 2.days.ago, ts2: Time.now, interval: '1 hour'}).column("series")
109
+ SELECT generate_series(
110
+ :ts1::timestamp,
111
+ :ts2::timestamp,
112
+ COALESCE(:interval, '5 minutes')::interval
113
+ ) AS series
114
+ SQL
115
+ =>
116
+ [2025-12-31 12:57:46.969709 UTC,
117
+ 2025-12-31 13:57:46.969709 UTC,
118
+ 2025-12-31 14:57:46.969709 UTC,
119
+ ...]
112
120
 
113
121
  # rewriting queries (using CTEs)
114
122
  [postgresql]> articles = [
@@ -376,7 +384,30 @@ $ bin/run rails_head console
376
384
 
377
385
  Run `rake spec` to run the tests.
378
386
 
379
- 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).
387
+ To install this gem onto your local machine, run `bundle exec rake install`.
388
+
389
+ ### Releasing
390
+
391
+ Create a signed git tag and push:
392
+
393
+ ```bash
394
+ # Regular release
395
+ git tag -s 1.2.3 -m "Release 1.2.3"
396
+
397
+ # Prerelease
398
+ git tag -s 1.2.3.rc1 -m "Release 1.2.3.rc1"
399
+
400
+ # Push the tag
401
+ git push origin --tags
402
+ ```
403
+
404
+ CI will build the gem, sign it (Sigstore attestation), push to RubyGems, and create a GitHub release (see [release.yml](https://github.com/eval/appquery/blob/3ed2adfacf952acc191a21a44b7c43a375b8975b/.github/workflows/release.yml#L34)).
405
+
406
+ After the release, update version.rb to the next dev version:
407
+
408
+ ```ruby
409
+ VERSION = "1.2.4.dev"
410
+ ```
380
411
 
381
412
  ## Contributing
382
413
 
@@ -3,5 +3,5 @@
3
3
  module AppQuery
4
4
  # This should just contain the .dev of the upcoming version.
5
5
  # When doing the actual release, CI will write the tag here before pushing the gem.
6
- VERSION = "0.6.0.rc9"
6
+ VERSION = "0.6.0"
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appquery
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0.rc9
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gert Goet