sqlsnip 0.1.0 → 0.2.1
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 +4 -4
- data/exe/sqlsnip +57 -18
- data/lib/sqlsnip/version.rb +1 -1
- data/lib/sqlsnip.rb +101 -60
- metadata +30 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eff6793c0897ff170d7113e76b9599ebba9e781a17a7c79f0e290072f51b8126
|
4
|
+
data.tar.gz: 18cb83ef312352f398989ad01f96bff419db7cf755d1c93d891bb9c8cc641c08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b28921c49c85b91418e74a5e193431187778fa84a274c5a3d894b03fc0269da4cec30955d551123eb1451f7af325cf67115b75068a604cbae38b290f71e5e09
|
7
|
+
data.tar.gz: 1836d49c1dc2f46f4889d92243b2b59452017ccabb68af0ed261ab62b2d5990ff0a0bee7627b4580a219b1a6e13e81fc5d117b6f6ad2364b0625fece9fd47fc8
|
data/exe/sqlsnip
CHANGED
@@ -11,11 +11,11 @@ SPEC = %(
|
|
11
11
|
-- FILE [START [STOP]]
|
12
12
|
|
13
13
|
Prepares a range of lines in a SQL file for execution by adding drop
|
14
|
-
statements for
|
15
|
-
file is executed. Prints the resulting SQL script on standard output so
|
16
|
-
can be piped to psql(1)
|
14
|
+
statements for objects defined in the range. If the range is absent, the
|
15
|
+
whole file is executed. Prints the resulting SQL script on standard output so
|
16
|
+
it can be piped to psql(1)
|
17
17
|
|
18
|
-
The range is given by a start and a stop line number (inclusive)
|
18
|
+
The range is given by a start and a stop line number (inclusive). It is
|
19
19
|
scanned for lines matching 'create' and a drop statement is added for each
|
20
20
|
match. Table, view, function, procedure, and trigger objects are supported.
|
21
21
|
'or replace' definitions does not generate drop statements
|
@@ -28,37 +28,76 @@ SPEC = %(
|
|
28
28
|
Note that the parser is very primitive: It expects the header of the
|
29
29
|
definition to be on one line. It also doesn't know about comments
|
30
30
|
|
31
|
+
-i,interactive
|
32
|
+
Emit PSQL session statements (ON_ERROR_STOP)
|
33
|
+
|
34
|
+
-s,schema=SCHEMA?
|
35
|
+
Set initial search path. If SCHEMA is absent no initial search path is
|
36
|
+
emitted. Explicit search path settings in the source are always emitted
|
37
|
+
|
38
|
+
-d,drop-only
|
39
|
+
Only emit drop-statements. Can be used to insert drop statements in the
|
40
|
+
current editor
|
41
|
+
|
31
42
|
EXAMPLE
|
32
43
|
|
33
44
|
sqlsnip can be used to create a vim macro in .vimrcc that executes the
|
34
45
|
selected text or the whole file:
|
35
46
|
|
36
|
-
\\function!
|
47
|
+
\\function! PrepareSqlRange() range
|
37
48
|
let path = expand('%:p')
|
38
|
-
let
|
49
|
+
let start_line = line("'<")
|
50
|
+
let end_line = line("'>")
|
51
|
+
let result = system('sqlsnip ' . path . ' ' . start_line . ' ' . end_line . ' | psql')
|
39
52
|
echo result
|
40
53
|
endfunction
|
41
54
|
|
42
|
-
|
55
|
+
" CTRL-X - execute selected range
|
56
|
+
map <C-X> :call PrepareSqlRange()<CR>
|
57
|
+
|
58
|
+
...or the whole file
|
59
|
+
|
60
|
+
\\function! PrepareSqlFile() range
|
43
61
|
let path = expand('%:p')
|
44
|
-
let
|
45
|
-
let end_line = line("'>")
|
46
|
-
let result = system('sqlsnip ' . path . ' ' . start_line . ' ' . end_line . ' | psql')
|
62
|
+
let result = system('sqlsnip' . path . ' | psql')
|
47
63
|
echo result
|
48
64
|
endfunction
|
49
65
|
|
50
66
|
" CTRL+G - execute whole file
|
51
|
-
map <C-G> :call
|
67
|
+
map <C-G> :call PrepareSqlFile()<CR>
|
68
|
+
|
69
|
+
...or to just replace the current selected text with drop statements
|
70
|
+
|
71
|
+
\\function! ReplaceSqlRange() range " ChatGPT
|
72
|
+
let start_line = line("'<")
|
73
|
+
let end_line = line("'>")
|
74
|
+
let save_cursor = getpos('.')
|
75
|
+
let range_text = getline(start_line, end_line)
|
76
|
+
let path = expand('%:p')
|
77
|
+
let shell_output = system('bundle exec exe/sqlsnip -ds"" ' . path)
|
78
|
+
let shell_output_lines = split(shell_output, "\n")
|
79
|
+
call deletebufline('%', start_line, end_line)
|
80
|
+
call append(start_line - 1, shell_output_lines)
|
81
|
+
call setpos('.', save_cursor)
|
82
|
+
endfunction
|
83
|
+
|
84
|
+
" CTRL+I - insert drop statements
|
85
|
+
map <C-I> :call ReplaceSqlRange()<CR>
|
52
86
|
|
53
|
-
" CTRL-X - execute selected range
|
54
|
-
map <C-X> :call ExecuteSqlRange()<CR>
|
55
87
|
)
|
56
88
|
|
57
89
|
opts, args = ShellOpts.process(SPEC, ARGV)
|
58
|
-
file, start_line, stop_line = args.
|
59
|
-
start_line
|
60
|
-
stop_line
|
90
|
+
file, start_line, stop_line = args.expect(1..3)
|
91
|
+
start_line &&= start_line.to_i
|
92
|
+
stop_line &&= stop_line.to_i
|
93
|
+
|
94
|
+
search_path = opts.schema? ? opts.schema || "" : nil
|
95
|
+
|
96
|
+
source = Sqlsnip::Source.parse(file, start_line, stop_line, search_path: search_path)
|
97
|
+
puts source.generate(interactive: opts.interactive?)
|
61
98
|
|
62
|
-
|
63
|
-
|
99
|
+
if !opts.drop_only?
|
100
|
+
puts
|
101
|
+
puts source.lines
|
102
|
+
end
|
64
103
|
|
data/lib/sqlsnip/version.rb
CHANGED
data/lib/sqlsnip.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'string-text'
|
4
|
+
require 'constrain'
|
5
|
+
include Constrain
|
6
|
+
|
3
7
|
require_relative "sqlsnip/version"
|
4
8
|
|
9
|
+
|
5
10
|
module Sqlsnip
|
6
11
|
class Error < StandardError; end
|
7
12
|
|
8
|
-
class
|
13
|
+
class Source
|
9
14
|
UID_RE = /(?:[.\w]+)/
|
10
15
|
TABLE_MODIFIERS_RE = /(?:global|local|temporary|temp|unlogged)/
|
11
16
|
VIEW_MODIFIERS_RE = /(?:temp|temporary|recursive)/
|
@@ -27,80 +32,57 @@ module Sqlsnip
|
|
27
32
|
|
28
33
|
SEARCH_PATH_RE = /^\s*set\s+search_path/
|
29
34
|
|
30
|
-
|
31
|
-
attr_reader :
|
35
|
+
# Source file
|
36
|
+
attr_reader :file
|
37
|
+
|
38
|
+
# Starting and ending line (inclusive). May be nil
|
39
|
+
attr_reader :start_line, :stop_line
|
40
|
+
|
41
|
+
# The selected range of lines as read from the file
|
42
|
+
attr_reader :lines
|
43
|
+
|
44
|
+
# Array of generated statements
|
45
|
+
attr_reader :stmts
|
32
46
|
|
33
|
-
|
47
|
+
# Initial search path
|
48
|
+
attr_reader :search_path
|
49
|
+
|
50
|
+
def initialize(file, start_line = nil, stop_line = nil, search_path: nil)
|
51
|
+
constrain file, String
|
52
|
+
constrain start_line, Integer, nil
|
53
|
+
constrain stop_line, Integer, nil
|
54
|
+
constrain search_path, String, nil
|
34
55
|
@file, @start_line, @stop_line = file, start_line, stop_line
|
35
56
|
File.exist?(@file) or raise Error, "Can't find #{file}"
|
36
57
|
@lines = []
|
37
|
-
@
|
58
|
+
@stmts = nil
|
59
|
+
@search_path = search_path
|
60
|
+
if @search_path && !@search_path.empty?
|
61
|
+
@search_path_stmt = "set search_path to #{@search_path};"
|
62
|
+
end
|
38
63
|
@project_dir = nil
|
39
64
|
end
|
40
65
|
|
41
|
-
def
|
66
|
+
def parse
|
42
67
|
read_lines
|
43
|
-
|
44
|
-
|
45
|
-
search_path = @initial_search_path
|
46
|
-
if search_path.nil?
|
47
|
-
schema = find_schema_from_file(file)
|
48
|
-
search_path = "set search_path to #{schema}"
|
49
|
-
end
|
50
|
-
stmts.unshift search_path
|
51
|
-
end
|
52
|
-
|
53
|
-
puts '\set ON_ERROR_STOP on'
|
54
|
-
puts stmts
|
55
|
-
puts
|
56
|
-
puts lines
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
attr_reader :initial_search_path, :project_dir
|
61
|
-
|
62
|
-
def read_lines
|
63
|
-
IO.readlines(file).each.with_index { |line, i|
|
64
|
-
i += 1
|
65
|
-
if i < start_line
|
66
|
-
@initial_search_path = line if line =~ /^\s*set\s+search_path/
|
67
|
-
elsif i <= stop_line
|
68
|
-
lines << line
|
69
|
-
else
|
70
|
-
break
|
71
|
-
end
|
72
|
-
}
|
68
|
+
generate_drop_stmts
|
69
|
+
self
|
73
70
|
end
|
74
71
|
|
75
|
-
def
|
76
|
-
path = File.absolute_path(path)
|
77
|
-
while !File.exist?(File.join(path, "prick.yml"))
|
78
|
-
path != "/" or raise Error, "Can't find project directory"
|
79
|
-
path = File.dirname(path)
|
80
|
-
end
|
81
|
-
path
|
82
|
-
end
|
72
|
+
def self.parse(*args, **opts) self.new(*args, **opts).parse end
|
83
73
|
|
84
|
-
def
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
if path =~ /schema\/([^\/]+)/
|
89
|
-
schema = $1
|
90
|
-
else
|
91
|
-
schema != "" or raise Error, "Can't find schema from #{file}"
|
92
|
-
end
|
93
|
-
schema
|
74
|
+
def generate(interactive: false)
|
75
|
+
generate_search_path_stmt if @search_path != ""
|
76
|
+
generate_interactive_stmts if interactive
|
77
|
+
@stmts
|
94
78
|
end
|
95
79
|
|
96
|
-
def
|
97
|
-
|
98
|
-
stmts = []
|
80
|
+
def generate_drop_stmts
|
81
|
+
@stmts = []
|
99
82
|
for line in lines
|
100
83
|
case line
|
101
84
|
when /^\s*set\s+search_path/
|
102
85
|
sql = line
|
103
|
-
has_search_path = true if stmts.empty?
|
104
86
|
when /^\s*create\s+(.*)/
|
105
87
|
object = $1
|
106
88
|
case object
|
@@ -134,9 +116,68 @@ module Sqlsnip
|
|
134
116
|
else
|
135
117
|
next
|
136
118
|
end
|
137
|
-
stmts << sql
|
119
|
+
@stmts << sql
|
138
120
|
end
|
139
|
-
|
121
|
+
end
|
122
|
+
|
123
|
+
# Generate a 'set search_path' statement
|
124
|
+
def generate_search_path_stmt
|
125
|
+
if @search_path == ""
|
126
|
+
return @stmts
|
127
|
+
elsif @search_path_stmt
|
128
|
+
@stmts.unshift @search_path_stmt
|
129
|
+
else
|
130
|
+
schema = find_schema_from_file(file)
|
131
|
+
search_path = "set search_path to #{schema};"
|
132
|
+
@stmts.unshift search_path
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def generate_interactive_stmts
|
137
|
+
@stmts.unshift '\set ON_ERROR_STOP on'
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
private
|
142
|
+
attr_reader :search_path_stmt, :project_dir
|
143
|
+
|
144
|
+
def read_lines
|
145
|
+
IO.readlines(file).each.with_index { |line, i|
|
146
|
+
line.chomp!
|
147
|
+
i += 1
|
148
|
+
break if !stop_line.nil? && i > stop_line
|
149
|
+
next if line =~ /^\s*$/
|
150
|
+
if @lines.empty? && @search_path.nil? && line =~ /^\s*set\s+search_path/
|
151
|
+
@search_path_stmt = line
|
152
|
+
elsif !start_line.nil? && i < start_line
|
153
|
+
;
|
154
|
+
elsif stop_line.nil? || i <= stop_line
|
155
|
+
@lines << line
|
156
|
+
end
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
# Search upwards in the directory hierarchy for a prick project directory
|
161
|
+
def find_project_dir(path)
|
162
|
+
path = File.absolute_path(path)
|
163
|
+
while !File.exist?(File.join(path, "prick.yml"))
|
164
|
+
path != "/" or raise Error, "Can't find project directory"
|
165
|
+
path = File.dirname(path)
|
166
|
+
end
|
167
|
+
path
|
168
|
+
end
|
169
|
+
|
170
|
+
# Use the prick source directory structure to find the schema name
|
171
|
+
def find_schema_from_file(file)
|
172
|
+
path = File.dirname(file)
|
173
|
+
project_dir = find_project_dir(File.dirname(file))
|
174
|
+
path = path.delete_prefix(project_dir)
|
175
|
+
if path =~ /schema\/([^\/]+)/
|
176
|
+
schema = $1
|
177
|
+
else
|
178
|
+
schema != "" or raise Error, "Can't find schema from #{file}"
|
179
|
+
end
|
180
|
+
schema
|
140
181
|
end
|
141
182
|
end
|
142
183
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqlsnip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: indented_io
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: string-text
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: constrain
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
description: Gem sqlsnip
|
42
70
|
email:
|
43
71
|
- claus.l.rasmussen@gmail.com
|