sequel-sqlformat 0.1.0-arm64-darwin
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 +7 -0
- data/CHANGELOG.md +10 -0
- data/LICENSE +21 -0
- data/README.md +81 -0
- data/lib/sequel/extensions/sqlformat.rb +98 -0
- data/lib/sequel/sqlformat/3.3/sequel_sqlformat.bundle +0 -0
- data/lib/sequel/sqlformat/3.4/sequel_sqlformat.bundle +0 -0
- data/lib/sequel/sqlformat/4.0/sequel_sqlformat.bundle +0 -0
- data/lib/sequel/sqlformat/version.rb +7 -0
- data/lib/sequel/sqlformat.rb +50 -0
- metadata +77 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6100b4499e5dc52064a82ecb726f6c4e9e9004093dba75eff2effd40b10a1e2d
|
|
4
|
+
data.tar.gz: e187eb66070aa7bb530723117e9b748f56648f16adb4c6145c7e9705c08243bb
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 61c899debff1f5d8610c5191ee8c1ec895a34cd66e4855235d412e861eebf9907130e1c431049b6c5bfc271c0230269f8160bb61d47fffb8dc4a1aa3067f05f2
|
|
7
|
+
data.tar.gz: 3f3e87e02dbd6982c235df0b4d9db3446201a7598e20626a3d838916d687b0b3addd4b84b9dca293620063249214d25b535f324e5dfe7ab13e8bfb6a7407b75b
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.0] - 2026-10-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- The `sqlformat` Sequel extension: `Database#format_sql`, `Dataset#formatted_sql`, and `sqlformat_options` on a database or in the connect hash. The dialect comes from the database type.
|
|
8
|
+
- `Sequel::SQLFormat.format(sql, indent:, uppercase:, lines_between_queries:, dialect:)` formats SQL with the Rust `sqlformat` crate 0.5, with no database. The defaults are the crate's defaults.
|
|
9
|
+
|
|
10
|
+
[0.1.0]: https://github.com/outcomesinsights/sequel-sqlformat/releases/tag/v0.1.0
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Outcomes Insights, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# sequel-sqlformat
|
|
2
|
+
|
|
3
|
+
A [Sequel](https://sequel.jeremyevans.net/) extension that formats SQL for reading. It adds
|
|
4
|
+
`Dataset#formatted_sql` and `Database#format_sql`. Formatting runs inside the Ruby process,
|
|
5
|
+
through a native extension built with [magnus](https://github.com/matsadler/magnus) that wraps
|
|
6
|
+
the Rust [`sqlformat`](https://crates.io/crates/sqlformat) crate. No external process starts,
|
|
7
|
+
so formatting many statements costs milliseconds, not seconds.
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
DB.extension :sqlformat
|
|
11
|
+
|
|
12
|
+
DB[:items].where(id: 1).formatted_sql(uppercase: true)
|
|
13
|
+
# SELECT
|
|
14
|
+
# *
|
|
15
|
+
# FROM
|
|
16
|
+
# "items"
|
|
17
|
+
# WHERE
|
|
18
|
+
# ("id" = 1)
|
|
19
|
+
|
|
20
|
+
DB.format_sql("select a, b from t where a = 1") # any SQL string
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
To format one dataset only, load the extension into it: `DB[:items].extension(:sqlformat)`.
|
|
24
|
+
|
|
25
|
+
Without a database:
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
require "sequel/sqlformat"
|
|
29
|
+
|
|
30
|
+
Sequel::SQLFormat.format("select a from t", dialect: :postgresql)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Options
|
|
34
|
+
|
|
35
|
+
| Option | Default | Meaning |
|
|
36
|
+
| ----------------------- | ---------- | --------------------------------------------------------------------------------- |
|
|
37
|
+
| `indent` | `2` | Spaces for each indentation level (0 to 255). |
|
|
38
|
+
| `uppercase` | `nil` | `true` uppercases keywords, `false` lowercases them, `nil` keeps them. |
|
|
39
|
+
| `lines_between_queries` | `1` | Line breaks after each statement (0 to 255). |
|
|
40
|
+
| `dialect` | `:generic` | `:postgresql` adds array syntax. `:sqlserver` adds `[brackets]` and `@variables`. |
|
|
41
|
+
|
|
42
|
+
The defaults are the crate's defaults. Through the extension, the dialect comes from the
|
|
43
|
+
database type: `:postgresql` for PostgreSQL, `:sqlserver` for Microsoft SQL Server, and
|
|
44
|
+
`:generic` for every other database.
|
|
45
|
+
|
|
46
|
+
Set options for a database when you connect, or before you freeze it, or for one call:
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
DB = Sequel.connect(url, sqlformat: { uppercase: true, indent: 4 })
|
|
50
|
+
DB.sqlformat_options = { uppercase: true }
|
|
51
|
+
DB[:items].formatted_sql(uppercase: false)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
An unknown option name raises `ArgumentError`.
|
|
55
|
+
|
|
56
|
+
## What it does and does not do
|
|
57
|
+
|
|
58
|
+
- The crate splits SQL into tokens and does not parse it. It accepts any dialect, including
|
|
59
|
+
DuckDB and Spark SQL, and it never fails on syntax that it does not know.
|
|
60
|
+
- It changes only whitespace and, with `uppercase: true` or `false`, the case of keywords.
|
|
61
|
+
- With `uppercase: true` or `false`, an unquoted identifier that is also a keyword (for
|
|
62
|
+
example `status`) changes case too. Sequel quotes identifiers by default, so this matters
|
|
63
|
+
only for SQL that you write yourself.
|
|
64
|
+
|
|
65
|
+
## Installation
|
|
66
|
+
|
|
67
|
+
Precompiled gems exist for x86_64 and ARM64 Linux, and for Intel and Apple Silicon macOS,
|
|
68
|
+
for Ruby 3.3, 3.4 and 4.0. They need no Rust. Every other platform builds the source gem,
|
|
69
|
+
which needs a Rust toolchain (rustc 1.84 or later) and libclang.
|
|
70
|
+
|
|
71
|
+
## Development
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
just setup # tools, bundle and the git hooks
|
|
75
|
+
just test # compile the extension and run the tests
|
|
76
|
+
just ci # everything CI runs
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## License
|
|
80
|
+
|
|
81
|
+
MIT. The `sqlformat` crate is MIT OR Apache-2.0.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# The sqlformat extension formats SQL for reading: one clause per line, indented
|
|
5
|
+
# subqueries, and optionally uppercase keywords. It formats inside the Ruby process
|
|
6
|
+
# with the Rust `sqlformat` crate, so no external process starts.
|
|
7
|
+
#
|
|
8
|
+
# Load it into a database:
|
|
9
|
+
#
|
|
10
|
+
# DB.extension :sqlformat
|
|
11
|
+
#
|
|
12
|
+
# DB[:items].where(id: 1).formatted_sql
|
|
13
|
+
# # => "SELECT\n *\nFROM\n \"items\"\nWHERE\n (\"id\" = 1)"
|
|
14
|
+
#
|
|
15
|
+
# DB.format_sql("select a from t") # any SQL string
|
|
16
|
+
#
|
|
17
|
+
# Or into one dataset only:
|
|
18
|
+
#
|
|
19
|
+
# DB[:items].extension(:sqlformat).formatted_sql
|
|
20
|
+
#
|
|
21
|
+
# The crate's SQL dialect comes from the database type: :postgresql for PostgreSQL,
|
|
22
|
+
# :sqlserver for Microsoft SQL Server, and :generic for every other database.
|
|
23
|
+
#
|
|
24
|
+
# The default options are the crate's defaults (2 spaces, keyword case unchanged, one
|
|
25
|
+
# line break between statements). Change them for a database, either when connecting
|
|
26
|
+
# or before the database is frozen:
|
|
27
|
+
#
|
|
28
|
+
# DB = Sequel.connect(url, sqlformat: { uppercase: true, indent: 4 })
|
|
29
|
+
# DB.sqlformat_options = { uppercase: true }
|
|
30
|
+
#
|
|
31
|
+
# or for one call:
|
|
32
|
+
#
|
|
33
|
+
# DB[:items].formatted_sql(uppercase: false)
|
|
34
|
+
#
|
|
35
|
+
# The crate works on tokens and does not parse SQL. It changes only whitespace and,
|
|
36
|
+
# with uppercase: true or false, the case of keywords. With uppercase: true or false,
|
|
37
|
+
# an unquoted identifier that is also a keyword changes case too.
|
|
38
|
+
#
|
|
39
|
+
# Related module: Sequel::SQLFormat
|
|
40
|
+
|
|
41
|
+
require_relative "../sqlformat"
|
|
42
|
+
|
|
43
|
+
module Sequel
|
|
44
|
+
module SQLFormat
|
|
45
|
+
OPTION_KEYS = DEFAULTS.keys.freeze
|
|
46
|
+
|
|
47
|
+
# Checks option keys here, so a typo fails where it is written. The values are
|
|
48
|
+
# checked by SQLFormat.format.
|
|
49
|
+
def self.check_options!(opts)
|
|
50
|
+
raise TypeError, "sqlformat options must be a Hash, got #{opts.class}" unless opts.is_a?(Hash)
|
|
51
|
+
|
|
52
|
+
unknown = opts.keys - OPTION_KEYS
|
|
53
|
+
raise ArgumentError, "unknown sqlformat option(s) #{unknown.inspect}; expected #{OPTION_KEYS.inspect}" unless unknown.empty?
|
|
54
|
+
|
|
55
|
+
opts
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
module DatabaseMethods
|
|
59
|
+
def self.extended(db)
|
|
60
|
+
db.instance_exec do
|
|
61
|
+
@sqlformat_options = SQLFormat.check_options!(opts.fetch(:sqlformat, {})).dup.freeze
|
|
62
|
+
end
|
|
63
|
+
db.extend_datasets(DatasetMethods)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# The options this database passes to SQLFormat.format. Per-call options win.
|
|
67
|
+
attr_reader :sqlformat_options
|
|
68
|
+
|
|
69
|
+
def sqlformat_options=(opts)
|
|
70
|
+
@sqlformat_options = SQLFormat.check_options!(opts).dup.freeze
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Formats any SQL string with this database's dialect and options.
|
|
74
|
+
def format_sql(sql, **opts)
|
|
75
|
+
SQLFormat.check_options!(opts)
|
|
76
|
+
SQLFormat.format(sql, **{ dialect: SQLFormat.dialect_for(database_type) }.merge(sqlformat_options, opts))
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
module DatasetMethods
|
|
81
|
+
# The dataset's SQL (Dataset#sql), formatted.
|
|
82
|
+
def formatted_sql(**opts)
|
|
83
|
+
if db.respond_to?(:format_sql)
|
|
84
|
+
db.format_sql(sql, **opts)
|
|
85
|
+
else
|
|
86
|
+
SQLFormat.check_options!(opts)
|
|
87
|
+
SQLFormat.format(sql, **{ dialect: SQLFormat.dialect_for(db.database_type) }.merge(opts))
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Dataset first: Dataset.register_extension also registers a Database extension of the
|
|
94
|
+
# same name (one that only extends datasets), so the Database registration must come
|
|
95
|
+
# last to win.
|
|
96
|
+
Dataset.register_extension(:sqlformat, SQLFormat::DatasetMethods)
|
|
97
|
+
Database.register_extension(:sqlformat, SQLFormat::DatabaseMethods)
|
|
98
|
+
end
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "sqlformat/version"
|
|
4
|
+
|
|
5
|
+
# A precompiled gem keeps one library per Ruby minor version under
|
|
6
|
+
# lib/sequel/sqlformat/<major.minor>/. A gem built from source puts it in
|
|
7
|
+
# lib/sequel/sqlformat/.
|
|
8
|
+
begin
|
|
9
|
+
ruby_minor = RUBY_VERSION[/\A\d+\.\d+/]
|
|
10
|
+
require_relative "sqlformat/#{ruby_minor}/sequel_sqlformat"
|
|
11
|
+
rescue LoadError
|
|
12
|
+
require_relative "sqlformat/sequel_sqlformat"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module Sequel
|
|
16
|
+
# Formats SQL inside the Ruby process with the Rust `sqlformat` crate. The crate
|
|
17
|
+
# splits SQL into tokens and does not parse it, so it accepts any dialect and never
|
|
18
|
+
# fails on unknown syntax. This needs no database; the `sqlformat` Sequel extension
|
|
19
|
+
# (lib/sequel/extensions/sqlformat.rb) adds it to databases and datasets.
|
|
20
|
+
module SQLFormat
|
|
21
|
+
DIALECTS = %i[generic postgresql sqlserver].freeze
|
|
22
|
+
|
|
23
|
+
# The crate's own defaults.
|
|
24
|
+
DEFAULTS = { indent: 2, uppercase: nil, lines_between_queries: 1, dialect: :generic }.freeze
|
|
25
|
+
|
|
26
|
+
# indent: spaces for each indentation level (0 to 255).
|
|
27
|
+
# uppercase: true uppercases keywords, false lowercases them, nil keeps them.
|
|
28
|
+
# lines_between_queries: line breaks after each statement (0 to 255).
|
|
29
|
+
# dialect: :postgresql adds array syntax. :sqlserver adds [brackets] and @variables.
|
|
30
|
+
def self.format(sql, indent: 2, uppercase: nil, lines_between_queries: 1, dialect: :generic)
|
|
31
|
+
raise TypeError, "sql must be a String, got #{sql.class}" unless sql.is_a?(String)
|
|
32
|
+
raise ArgumentError, "unknown dialect #{dialect.inspect}; expected one of #{DIALECTS.inspect}" unless DIALECTS.include?(dialect.to_sym)
|
|
33
|
+
raise ArgumentError, "indent must be an Integer from 0 to 255" unless indent.is_a?(Integer) && indent.between?(0, 255)
|
|
34
|
+
raise ArgumentError, "lines_between_queries must be an Integer from 0 to 255" unless lines_between_queries.is_a?(Integer) && lines_between_queries.between?(0, 255)
|
|
35
|
+
raise ArgumentError, "uppercase must be true, false or nil" unless [ true, false, nil ].include?(uppercase)
|
|
36
|
+
|
|
37
|
+
native_format(sql.encode(Encoding::UTF_8), indent, uppercase, lines_between_queries, dialect.to_s)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# The crate dialect for a Sequel database type. Every type the crate has no mode
|
|
41
|
+
# for, such as DuckDB, Spark, SQLite and MySQL, gets the generic mode.
|
|
42
|
+
def self.dialect_for(database_type)
|
|
43
|
+
case database_type
|
|
44
|
+
when :postgres then :postgresql
|
|
45
|
+
when :mssql then :sqlserver
|
|
46
|
+
else :generic
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: sequel-sqlformat
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: arm64-darwin
|
|
6
|
+
authors:
|
|
7
|
+
- Ryan Duryea
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-10-28 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: sequel
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '5.0'
|
|
27
|
+
description: Adds Database#format_sql and Dataset#formatted_sql to Sequel. Formatting
|
|
28
|
+
runs inside the Ruby process through a native extension (magnus) that wraps the
|
|
29
|
+
Rust sqlformat crate, so no external process starts and many statements format in
|
|
30
|
+
milliseconds.
|
|
31
|
+
email:
|
|
32
|
+
- aguynamedryan@gmail.com
|
|
33
|
+
executables: []
|
|
34
|
+
extensions: []
|
|
35
|
+
extra_rdoc_files: []
|
|
36
|
+
files:
|
|
37
|
+
- CHANGELOG.md
|
|
38
|
+
- LICENSE
|
|
39
|
+
- README.md
|
|
40
|
+
- lib/sequel/extensions/sqlformat.rb
|
|
41
|
+
- lib/sequel/sqlformat.rb
|
|
42
|
+
- lib/sequel/sqlformat/3.3/sequel_sqlformat.bundle
|
|
43
|
+
- lib/sequel/sqlformat/3.4/sequel_sqlformat.bundle
|
|
44
|
+
- lib/sequel/sqlformat/4.0/sequel_sqlformat.bundle
|
|
45
|
+
- lib/sequel/sqlformat/version.rb
|
|
46
|
+
homepage: https://github.com/outcomesinsights/sequel-sqlformat
|
|
47
|
+
licenses:
|
|
48
|
+
- MIT
|
|
49
|
+
metadata:
|
|
50
|
+
allowed_push_host: https://rubygems.org
|
|
51
|
+
homepage_uri: https://github.com/outcomesinsights/sequel-sqlformat
|
|
52
|
+
source_code_uri: https://github.com/outcomesinsights/sequel-sqlformat
|
|
53
|
+
changelog_uri: https://github.com/outcomesinsights/sequel-sqlformat/blob/main/CHANGELOG.md
|
|
54
|
+
rubygems_mfa_required: 'true'
|
|
55
|
+
post_install_message:
|
|
56
|
+
rdoc_options: []
|
|
57
|
+
require_paths:
|
|
58
|
+
- lib
|
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: '3.3'
|
|
64
|
+
- - "<"
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: 4.1.dev
|
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '0'
|
|
72
|
+
requirements: []
|
|
73
|
+
rubygems_version: 3.5.23
|
|
74
|
+
signing_key:
|
|
75
|
+
specification_version: 4
|
|
76
|
+
summary: A Sequel extension that formats SQL, fast, with the Rust sqlformat crate
|
|
77
|
+
test_files: []
|