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 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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sequel
4
+ module SQLFormat
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -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: []