goldlapel 0.0.1.pre.rc1-aarch64-linux
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/README.md +116 -0
- data/bin/goldlapel-linux-aarch64 +0 -0
- data/lib/goldlapel/proxy.rb +293 -0
- data/lib/goldlapel.rb +26 -0
- metadata +50 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8a2ede97de5a466d34bef7406ef0d4891eb085b2c826a9b471287323ee07e44b
|
|
4
|
+
data.tar.gz: c6e806544b943d0addb3bd921a31f4deea2c0af36f3e8d0693d66bea0510af22
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: '0368b6e9ca5dc6685d34df7d4f28d51df78cf85f85b58f964541bc70baa07b107de4bca9d71ee4141ad5702e434c50d3fc6addc6165d2b0efb8d423049f67b73'
|
|
7
|
+
data.tar.gz: d844fe2fb94bc4071cef2764be5f50c936cbc31a35d47d634ec32a1cca593de09d86f1255d2ec9dd8f788d19c06fbc51673e36d69a2bf2e36578be9da9c55439
|
data/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Gold Lapel
|
|
2
|
+
|
|
3
|
+
Self-optimizing Postgres proxy — automatic materialized views and indexes. Zero code changes required.
|
|
4
|
+
|
|
5
|
+
Gold Lapel sits between your app and Postgres, watches query patterns, and automatically creates materialized views and indexes to make your database faster. Port 7932 (79 = atomic number for gold, 32 from Postgres).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
gem install goldlapel
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or add to your Gemfile:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
gem "goldlapel"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
require "goldlapel"
|
|
23
|
+
|
|
24
|
+
# Start the proxy — returns a connection string pointing at Gold Lapel
|
|
25
|
+
url = GoldLapel.start("postgresql://user:pass@localhost:5432/mydb")
|
|
26
|
+
|
|
27
|
+
# Use the URL with any Postgres driver
|
|
28
|
+
require "pg"
|
|
29
|
+
conn = PG.connect(url)
|
|
30
|
+
|
|
31
|
+
# Or Sequel, ActiveRecord, ROM — anything that speaks Postgres
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Gold Lapel is driver-agnostic. `start` returns a connection string (`postgresql://...@localhost:7932/...`) that works with any Postgres driver or ORM.
|
|
35
|
+
|
|
36
|
+
## API
|
|
37
|
+
|
|
38
|
+
### `GoldLapel.start(upstream, port: nil, config: {}, extra_args: [])`
|
|
39
|
+
|
|
40
|
+
Starts the Gold Lapel proxy and returns the proxy connection string.
|
|
41
|
+
|
|
42
|
+
- `upstream` — your Postgres connection string (e.g. `postgresql://user:pass@localhost:5432/mydb`)
|
|
43
|
+
- `port` — proxy port (default: 7932)
|
|
44
|
+
- `config` — configuration hash (see [Configuration](#configuration) below)
|
|
45
|
+
- `extra_args` — additional CLI flags passed to the binary (e.g. `["--threshold-impact", "5000"]`)
|
|
46
|
+
|
|
47
|
+
### `GoldLapel.stop`
|
|
48
|
+
|
|
49
|
+
Stops the proxy. Also called automatically on process exit.
|
|
50
|
+
|
|
51
|
+
### `GoldLapel.proxy_url`
|
|
52
|
+
|
|
53
|
+
Returns the current proxy URL, or `nil` if not running.
|
|
54
|
+
|
|
55
|
+
### `GoldLapel.dashboard_url`
|
|
56
|
+
|
|
57
|
+
Returns the dashboard URL (e.g. `http://127.0.0.1:7933`), or `nil` if not running. The dashboard port defaults to 7933 and can be configured via `config: { dashboard_port: 9090 }` or disabled with `dashboard_port: 0`.
|
|
58
|
+
|
|
59
|
+
### `GoldLapel.config_keys`
|
|
60
|
+
|
|
61
|
+
Returns an array of all valid configuration key names (as strings).
|
|
62
|
+
|
|
63
|
+
### `GoldLapel::Proxy.new(upstream, port: nil, config: {}, extra_args: [])`
|
|
64
|
+
|
|
65
|
+
Class interface for managing multiple instances:
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
proxy = GoldLapel::Proxy.new("postgresql://user:pass@localhost:5432/mydb", port: 7932)
|
|
69
|
+
url = proxy.start
|
|
70
|
+
# ...
|
|
71
|
+
proxy.stop
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
Pass a config hash to configure the proxy:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
require "goldlapel"
|
|
80
|
+
|
|
81
|
+
url = GoldLapel.start("postgresql://user:pass@localhost/mydb", config: {
|
|
82
|
+
mode: "butler",
|
|
83
|
+
pool_size: 50,
|
|
84
|
+
disable_matviews: true,
|
|
85
|
+
replica: ["postgresql://user:pass@replica1/mydb"],
|
|
86
|
+
})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Keys use `snake_case` (symbols or strings) and map to CLI flags (`pool_size` -> `--pool-size`). Boolean keys are flags -- `true` enables them. Array keys produce repeated flags.
|
|
90
|
+
|
|
91
|
+
Unknown keys raise `ArgumentError`. To see all valid keys:
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
GoldLapel.config_keys
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
For the full configuration reference, see the [main documentation](https://github.com/goldlapel/goldlapel#setting-reference).
|
|
98
|
+
|
|
99
|
+
You can also pass raw CLI flags via `extra_args`, or set environment variables (`GOLDLAPEL_PORT`, `GOLDLAPEL_UPSTREAM`, etc.) -- the binary reads them automatically.
|
|
100
|
+
|
|
101
|
+
## How It Works
|
|
102
|
+
|
|
103
|
+
This gem bundles the Gold Lapel Rust binary for your platform. When you call `start`, it:
|
|
104
|
+
|
|
105
|
+
1. Locates the binary (bundled in gem, on PATH, or via `GOLDLAPEL_BINARY` env var)
|
|
106
|
+
2. Spawns it as a subprocess listening on localhost
|
|
107
|
+
3. Waits for the port to be ready
|
|
108
|
+
4. Returns a connection string pointing at the proxy
|
|
109
|
+
5. Cleans up automatically on process exit
|
|
110
|
+
|
|
111
|
+
The binary does all the work — this wrapper just manages its lifecycle.
|
|
112
|
+
|
|
113
|
+
## Links
|
|
114
|
+
|
|
115
|
+
- [Website](https://goldlapel.com)
|
|
116
|
+
- [Documentation](https://github.com/goldlapel/goldlapel)
|
|
Binary file
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
require "socket"
|
|
5
|
+
require "rbconfig"
|
|
6
|
+
|
|
7
|
+
module GoldLapel
|
|
8
|
+
DEFAULT_PORT = 7932
|
|
9
|
+
DEFAULT_DASHBOARD_PORT = 7933
|
|
10
|
+
STARTUP_TIMEOUT = 10.0
|
|
11
|
+
STARTUP_POLL_INTERVAL = 0.05
|
|
12
|
+
|
|
13
|
+
class Proxy
|
|
14
|
+
attr_reader :url, :upstream, :dashboard_url
|
|
15
|
+
|
|
16
|
+
VALID_CONFIG_KEYS = %w[
|
|
17
|
+
mode min_pattern_count refresh_interval_secs pattern_ttl_secs
|
|
18
|
+
max_tables_per_view max_columns_per_view deep_pagination_threshold
|
|
19
|
+
report_interval_secs result_cache_size batch_cache_size
|
|
20
|
+
batch_cache_ttl_secs redis_url pool_size pool_timeout_secs
|
|
21
|
+
pool_mode mgmt_idle_timeout fallback read_after_write_secs
|
|
22
|
+
n1_threshold n1_window_ms n1_cross_threshold
|
|
23
|
+
tls_cert tls_key tls_client_ca config dashboard_port
|
|
24
|
+
disable_matviews disable_consolidation disable_btree_indexes
|
|
25
|
+
disable_trigram_indexes disable_expression_indexes
|
|
26
|
+
disable_partial_indexes disable_rewrite disable_prepared_cache
|
|
27
|
+
disable_result_cache disable_redis_cache disable_pool
|
|
28
|
+
disable_n1 disable_n1_cross_connection disable_shadow_mode
|
|
29
|
+
enable_coalescing replica exclude_tables
|
|
30
|
+
].freeze
|
|
31
|
+
|
|
32
|
+
BOOLEAN_KEYS = %w[
|
|
33
|
+
disable_matviews disable_consolidation disable_btree_indexes
|
|
34
|
+
disable_trigram_indexes disable_expression_indexes
|
|
35
|
+
disable_partial_indexes disable_rewrite disable_prepared_cache
|
|
36
|
+
disable_result_cache disable_redis_cache disable_pool
|
|
37
|
+
disable_n1 disable_n1_cross_connection disable_shadow_mode
|
|
38
|
+
enable_coalescing
|
|
39
|
+
].freeze
|
|
40
|
+
|
|
41
|
+
LIST_KEYS = %w[
|
|
42
|
+
replica exclude_tables
|
|
43
|
+
].freeze
|
|
44
|
+
|
|
45
|
+
def self.config_keys
|
|
46
|
+
VALID_CONFIG_KEYS.dup
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.config_to_args(config)
|
|
50
|
+
return [] if config.nil? || config.empty?
|
|
51
|
+
|
|
52
|
+
args = []
|
|
53
|
+
config.each do |key, value|
|
|
54
|
+
key = key.to_s
|
|
55
|
+
unless VALID_CONFIG_KEYS.include?(key)
|
|
56
|
+
raise ArgumentError, "Unknown config key: #{key}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
flag = "--#{key.tr('_', '-')}"
|
|
60
|
+
|
|
61
|
+
if BOOLEAN_KEYS.include?(key)
|
|
62
|
+
unless value == true || value == false
|
|
63
|
+
raise TypeError, "Config key '#{key}' expects a boolean, got #{value.class}"
|
|
64
|
+
end
|
|
65
|
+
args << flag if value
|
|
66
|
+
elsif LIST_KEYS.include?(key)
|
|
67
|
+
Array(value).each do |item|
|
|
68
|
+
args.push(flag, item.to_s)
|
|
69
|
+
end
|
|
70
|
+
else
|
|
71
|
+
args.push(flag, value.to_s)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
args
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def initialize(upstream, port: nil, config: {}, extra_args: [])
|
|
78
|
+
@upstream = upstream
|
|
79
|
+
@port = port || DEFAULT_PORT
|
|
80
|
+
@config = config
|
|
81
|
+
@extra_args = extra_args
|
|
82
|
+
@pid = nil
|
|
83
|
+
@url = nil
|
|
84
|
+
@dashboard_url = nil
|
|
85
|
+
@stderr_reader = nil
|
|
86
|
+
|
|
87
|
+
@dashboard_port = if config.key?(:dashboard_port) || config.key?("dashboard_port")
|
|
88
|
+
config.fetch(:dashboard_port, config.fetch("dashboard_port", DEFAULT_DASHBOARD_PORT)).to_i
|
|
89
|
+
else
|
|
90
|
+
DEFAULT_DASHBOARD_PORT
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def start
|
|
95
|
+
return @url if running?
|
|
96
|
+
|
|
97
|
+
binary = self.class.find_binary
|
|
98
|
+
cmd = [
|
|
99
|
+
binary,
|
|
100
|
+
"--upstream", @upstream,
|
|
101
|
+
"--port", @port.to_s,
|
|
102
|
+
*self.class.config_to_args(@config),
|
|
103
|
+
*@extra_args,
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
stdin, stdout, stderr, wait_thr = Open3.popen3(*cmd)
|
|
107
|
+
stdin.close
|
|
108
|
+
stdout.close
|
|
109
|
+
@pid = wait_thr.pid
|
|
110
|
+
@stderr_reader = stderr
|
|
111
|
+
@wait_thr = wait_thr
|
|
112
|
+
|
|
113
|
+
unless self.class.wait_for_port("127.0.0.1", @port, STARTUP_TIMEOUT)
|
|
114
|
+
Process.kill("KILL", @pid) rescue Errno::ESRCH
|
|
115
|
+
@wait_thr.join rescue nil
|
|
116
|
+
stderr_output = stderr.read
|
|
117
|
+
stderr.close
|
|
118
|
+
@pid = nil
|
|
119
|
+
@wait_thr = nil
|
|
120
|
+
@stderr_reader = nil
|
|
121
|
+
raise "Gold Lapel failed to start on port #{@port} " \
|
|
122
|
+
"within #{STARTUP_TIMEOUT}s.\nstderr: #{stderr_output}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
@stderr_reader.close
|
|
126
|
+
@stderr_reader = nil
|
|
127
|
+
@url = self.class.make_proxy_url(@upstream, @port)
|
|
128
|
+
@dashboard_url = @dashboard_port > 0 ? "http://127.0.0.1:#{@dashboard_port}" : nil
|
|
129
|
+
|
|
130
|
+
if @dashboard_port > 0
|
|
131
|
+
puts "goldlapel → :#{@port} (proxy) | http://127.0.0.1:#{@dashboard_port} (dashboard)"
|
|
132
|
+
else
|
|
133
|
+
puts "goldlapel → :#{@port} (proxy)"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
@url
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def stop
|
|
140
|
+
if @pid
|
|
141
|
+
begin
|
|
142
|
+
Process.kill("TERM", @pid)
|
|
143
|
+
unless @wait_thr.join(5)
|
|
144
|
+
Process.kill("KILL", @pid) rescue Errno::ESRCH
|
|
145
|
+
@wait_thr.join(5) rescue nil
|
|
146
|
+
end
|
|
147
|
+
rescue Errno::ESRCH
|
|
148
|
+
# Process already exited
|
|
149
|
+
end
|
|
150
|
+
@stderr_reader&.close rescue IOError
|
|
151
|
+
@pid = nil
|
|
152
|
+
@url = nil
|
|
153
|
+
@dashboard_url = nil
|
|
154
|
+
@wait_thr = nil
|
|
155
|
+
@stderr_reader = nil
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def running?
|
|
160
|
+
return false unless @pid
|
|
161
|
+
Process.kill(0, @pid)
|
|
162
|
+
true
|
|
163
|
+
rescue Errno::ESRCH, Errno::EPERM
|
|
164
|
+
false
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# --- Class-level helpers ---
|
|
168
|
+
|
|
169
|
+
def self.find_binary
|
|
170
|
+
# 1. Explicit override via env var
|
|
171
|
+
env_path = ENV["GOLDLAPEL_BINARY"]
|
|
172
|
+
if env_path
|
|
173
|
+
return env_path if File.file?(env_path)
|
|
174
|
+
raise "GOLDLAPEL_BINARY points to #{env_path} but file not found"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# 2. Bundled binary (inside the installed gem)
|
|
178
|
+
system_name = case RbConfig::CONFIG["host_os"]
|
|
179
|
+
when /linux/i then "linux"
|
|
180
|
+
when /darwin/i then "darwin"
|
|
181
|
+
when /mswin|mingw|cygwin/i then "windows"
|
|
182
|
+
else RbConfig::CONFIG["host_os"]
|
|
183
|
+
end
|
|
184
|
+
machine = RbConfig::CONFIG["host_cpu"]
|
|
185
|
+
arch = case machine
|
|
186
|
+
when /x86_64|amd64/i then "x86_64"
|
|
187
|
+
when /arm64|aarch64/i then "aarch64"
|
|
188
|
+
else machine
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
binary_name = "goldlapel-#{system_name}-#{arch}"
|
|
192
|
+
binary_name += ".exe" if system_name == "windows"
|
|
193
|
+
bundled = File.join(__dir__, "..", "..", "bin", binary_name)
|
|
194
|
+
return bundled if File.file?(bundled)
|
|
195
|
+
|
|
196
|
+
# 3. On PATH
|
|
197
|
+
on_path = which("goldlapel")
|
|
198
|
+
return on_path if on_path
|
|
199
|
+
|
|
200
|
+
raise "Gold Lapel binary not found. Set GOLDLAPEL_BINARY env var, " \
|
|
201
|
+
"install the platform-specific package, or ensure 'goldlapel' is on PATH."
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def self.make_proxy_url(upstream, port)
|
|
205
|
+
# pg URL with explicit port
|
|
206
|
+
if upstream =~ /\A(postgres(?:ql)?:\/\/(?:.*@)?)([^:\/?#]+):(\d+)(.*)\z/
|
|
207
|
+
return "#{$1}localhost:#{port}#{$4}"
|
|
208
|
+
end
|
|
209
|
+
# pg URL without port
|
|
210
|
+
if upstream =~ /\A(postgres(?:ql)?:\/\/(?:.*@)?)([^:\/?#]+)(.*)\z/
|
|
211
|
+
return "#{$1}localhost:#{port}#{$3}"
|
|
212
|
+
end
|
|
213
|
+
# bare host:port (guard against scheme colons)
|
|
214
|
+
if !upstream.include?("://") && upstream.include?(":")
|
|
215
|
+
return "localhost:#{port}"
|
|
216
|
+
end
|
|
217
|
+
# bare host
|
|
218
|
+
"localhost:#{port}"
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def self.wait_for_port(host, port, timeout)
|
|
222
|
+
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timeout
|
|
223
|
+
while Process.clock_gettime(Process::CLOCK_MONOTONIC) < deadline
|
|
224
|
+
begin
|
|
225
|
+
sock = TCPSocket.new(host, port)
|
|
226
|
+
sock.close
|
|
227
|
+
return true
|
|
228
|
+
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, Errno::EHOSTUNREACH
|
|
229
|
+
sleep STARTUP_POLL_INTERVAL
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
false
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Module-level singleton
|
|
236
|
+
@instance = nil
|
|
237
|
+
@cleanup_registered = false
|
|
238
|
+
|
|
239
|
+
class << self
|
|
240
|
+
def start(upstream, port: nil, config: {}, extra_args: [])
|
|
241
|
+
if @instance&.running?
|
|
242
|
+
if @instance.upstream != upstream
|
|
243
|
+
raise "Gold Lapel is already running for a different upstream. " \
|
|
244
|
+
"Call GoldLapel.stop before starting with a new upstream."
|
|
245
|
+
end
|
|
246
|
+
return @instance.url
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
@instance = Proxy.new(upstream, port: port, config: config, extra_args: extra_args)
|
|
250
|
+
unless @cleanup_registered
|
|
251
|
+
at_exit { cleanup }
|
|
252
|
+
@cleanup_registered = true
|
|
253
|
+
end
|
|
254
|
+
@instance.start
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def stop
|
|
258
|
+
if @instance
|
|
259
|
+
@instance.stop
|
|
260
|
+
@instance = nil
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def proxy_url
|
|
265
|
+
@instance&.url
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def dashboard_url
|
|
269
|
+
@instance&.dashboard_url
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
private
|
|
273
|
+
|
|
274
|
+
def cleanup
|
|
275
|
+
if @instance
|
|
276
|
+
@instance.stop
|
|
277
|
+
@instance = nil
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def which(cmd)
|
|
282
|
+
exts = ENV["PATHEXT"] ? ENV["PATHEXT"].split(";") : [""]
|
|
283
|
+
(ENV["PATH"] || "").split(File::PATH_SEPARATOR).each do |path|
|
|
284
|
+
exts.each do |ext|
|
|
285
|
+
full = File.join(path, "#{cmd}#{ext}")
|
|
286
|
+
return full if File.executable?(full) && File.file?(full)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
nil
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
end
|
data/lib/goldlapel.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "goldlapel/proxy"
|
|
4
|
+
|
|
5
|
+
module GoldLapel
|
|
6
|
+
# Module-level convenience methods (singleton pattern)
|
|
7
|
+
def self.start(upstream, port: nil, config: {}, extra_args: [])
|
|
8
|
+
Proxy.start(upstream, port: port, config: config, extra_args: extra_args)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.stop
|
|
12
|
+
Proxy.stop
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.proxy_url
|
|
16
|
+
Proxy.proxy_url
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.dashboard_url
|
|
20
|
+
Proxy.dashboard_url
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.config_keys
|
|
24
|
+
Proxy.config_keys
|
|
25
|
+
end
|
|
26
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: goldlapel
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1.pre.rc1
|
|
5
|
+
platform: aarch64-linux
|
|
6
|
+
authors:
|
|
7
|
+
- Stephen Gibson
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-03-15 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Gold Lapel sits between your app and Postgres, watches query patterns,
|
|
14
|
+
and automatically creates materialized views and indexes to make your database faster.
|
|
15
|
+
Zero code changes required.
|
|
16
|
+
email:
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- README.md
|
|
22
|
+
- bin/goldlapel-linux-aarch64
|
|
23
|
+
- lib/goldlapel.rb
|
|
24
|
+
- lib/goldlapel/proxy.rb
|
|
25
|
+
homepage: https://goldlapel.com
|
|
26
|
+
licenses:
|
|
27
|
+
- Proprietary
|
|
28
|
+
metadata:
|
|
29
|
+
homepage_uri: https://goldlapel.com
|
|
30
|
+
source_code_uri: https://github.com/goldlapel/goldlapel-ruby
|
|
31
|
+
post_install_message:
|
|
32
|
+
rdoc_options: []
|
|
33
|
+
require_paths:
|
|
34
|
+
- lib
|
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 3.2.0
|
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
42
|
+
- - ">"
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: 1.3.1
|
|
45
|
+
requirements: []
|
|
46
|
+
rubygems_version: 3.4.20
|
|
47
|
+
signing_key:
|
|
48
|
+
specification_version: 4
|
|
49
|
+
summary: Self-optimizing Postgres proxy — automatic materialized views and indexes
|
|
50
|
+
test_files: []
|