sqlsnip 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/sqlsnip +43 -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: 1c25a3eafcf25530a813f9b4c36b16e52d567f9ae945baed3f823642f5177555
|
4
|
+
data.tar.gz: 680fc3ba40fcbfcd945909ee9c994c267a2dbecea3baeb7c097b1e55e42bbe69
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d803dd650b36880b6b574d98271846a87000c4dc7baaa26b8cfb3309dc12e981dd7c78794073457272624207591ab020166f72765f1ce388594172668f8dbbff
|
7
|
+
data.tar.gz: a41b647dcfcb71e3653099158e037042ac8c65f20089ac719cdb665d86dafeccf5f502cd9bd2569da848115fdb3b90eeb6c1aff0994003980c026146ed2a8267
|
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,62 @@ 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
|
-
|
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
|
+
TODO
|
52
72
|
|
53
|
-
" CTRL-X - execute selected range
|
54
|
-
map <C-X> :call ExecuteSqlRange()<CR>
|
55
73
|
)
|
56
74
|
|
57
75
|
opts, args = ShellOpts.process(SPEC, ARGV)
|
58
|
-
file, start_line, stop_line = args.
|
59
|
-
start_line
|
60
|
-
stop_line
|
76
|
+
file, start_line, stop_line = args.expect(1..3)
|
77
|
+
start_line &&= start_line.to_i
|
78
|
+
stop_line &&= stop_line.to_i
|
79
|
+
|
80
|
+
search_path = opts.schema? ? opts.schema || "" : nil
|
81
|
+
|
82
|
+
source = Sqlsnip::Source.parse(file, start_line, stop_line, search_path: search_path)
|
83
|
+
puts source.generate(interactive: opts.interactive?)
|
61
84
|
|
62
|
-
|
63
|
-
|
85
|
+
if !opts.drop_only?
|
86
|
+
puts
|
87
|
+
puts source.lines
|
88
|
+
end
|
64
89
|
|
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
|
68
|
+
generate_drop_stmts
|
69
|
+
self
|
57
70
|
end
|
58
71
|
|
59
|
-
|
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
|
-
}
|
73
|
-
end
|
72
|
+
def self.parse(*args, **opts) self.new(*args, **opts).parse end
|
74
73
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
path = File.dirname(path)
|
80
|
-
end
|
81
|
-
path
|
82
|
-
end
|
83
|
-
|
84
|
-
def find_schema_from_file(file)
|
85
|
-
path = File.dirname(file)
|
86
|
-
project_dir = find_project_dir(File.dirname(file))
|
87
|
-
path = path.delete_prefix(project_dir)
|
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
|
+
if start_line.nil?
|
149
|
+
@lines << line
|
150
|
+
elsif i < start_line
|
151
|
+
@search_path_stmt = line if @search_path.nil? && line =~ /^\s*set\s+search_path/
|
152
|
+
elsif stop_line.nil? || i <= stop_line
|
153
|
+
@lines << line
|
154
|
+
else
|
155
|
+
break
|
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.
|
4
|
+
version: 0.2.0
|
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
|