jade-sql 0.7.0 → 0.9.0
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/README.md +16 -10
- data/docs/building.md +411 -113
- data/docs/running.md +103 -18
- data/exe/jade-sql +37 -9
- data/lib/jade-sql/bin/generate_schema.rb +702 -44
- data/lib/jade-sql/compiler/assignable.rb +146 -0
- data/lib/jade-sql/compiler/columns.rb +220 -0
- data/lib/jade-sql/compiler/errors.rb +82 -0
- data/lib/jade-sql/compiler.rb +32 -0
- data/lib/jade-sql/runtime.rb +74 -23
- data/lib/jade-sql/schema_drift.rb +115 -0
- data/lib/jade-sql/sql/expr.jd +65 -0
- data/lib/jade-sql/sql/json.jd +154 -0
- data/lib/jade-sql/sql/query.jd +309 -93
- data/lib/jade-sql/sql/write.jd +618 -0
- data/lib/jade-sql/sql.jd +389 -103
- data/lib/jade-sql/tasks.rake +41 -8
- data/lib/jade-sql/version.rb +1 -1
- data/lib/jade-sql.rb +92 -14
- metadata +15 -8
- data/lib/jade-sql/sql/mutation.jd +0 -464
data/lib/jade-sql/tasks.rake
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'jade-sql/bin/generate_schema'
|
|
2
|
+
require 'jade-sql/schema_drift'
|
|
2
3
|
|
|
3
4
|
namespace :jade do
|
|
4
5
|
desc "Generate schema.jd from db/structure.sql (INPUT, OUTPUT, TABLES, COLUMNS, MODULE)"
|
|
@@ -9,15 +10,47 @@ namespace :jade do
|
|
|
9
10
|
columns = parse_columns_env(ENV['COLUMNS'])
|
|
10
11
|
module_name = ENV['MODULE'] || 'Schema'
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
output,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
JadeSql::SchemaGenerator
|
|
14
|
+
.generate(File.read(input), tables:, columns:, module_name:)
|
|
15
|
+
.map { |name, source| write_module(output, module_name, name, source) }
|
|
16
|
+
.then { puts "wrote #{it.join(', ')}" }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Every module the generator would write, read back if it is there. A file
|
|
20
|
+
# left behind for a module no longer generated is not found this way, which
|
|
21
|
+
# is the lesser problem: a missing one breaks the build, a stale one is dead
|
|
22
|
+
# code the compiler still reads.
|
|
23
|
+
def on_disk_modules(generated, root_module, output)
|
|
24
|
+
generated.keys.to_h do |name|
|
|
25
|
+
JadeSql::SchemaGenerator
|
|
26
|
+
.module_path(root_module, name, output)
|
|
27
|
+
.then { [name, File.exist?(it) ? File.read(it) : nil] }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def write_module(output, root_module, name, source)
|
|
32
|
+
JadeSql::SchemaGenerator
|
|
33
|
+
.module_path(root_module, name, output)
|
|
34
|
+
.tap { FileUtils.mkdir_p(File.dirname(it)) }
|
|
35
|
+
.tap { File.write(it, source) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
namespace :schema do
|
|
39
|
+
desc "Fail if schema.jd no longer matches db/structure.sql (INPUT, OUTPUT, TABLES, COLUMNS, MODULE)"
|
|
40
|
+
task :check do
|
|
41
|
+
input = ENV['INPUT'] || 'db/structure.sql'
|
|
42
|
+
output = ENV['OUTPUT'] || 'app/jade/schema.jd'
|
|
43
|
+
tables = ENV['TABLES']&.split(',')&.map(&:strip)&.reject(&:empty?)
|
|
44
|
+
columns = parse_columns_env(ENV['COLUMNS'])
|
|
45
|
+
module_name = ENV['MODULE'] || 'Schema'
|
|
46
|
+
|
|
47
|
+
abort "#{output} does not exist. Generate it with `rake jade:schema`." unless File.exist?(output)
|
|
19
48
|
|
|
20
|
-
|
|
49
|
+
JadeSql::SchemaGenerator
|
|
50
|
+
.generate(File.read(input), tables:, columns:, module_name:)
|
|
51
|
+
.then { JadeSql::SchemaDrift.between(it, on_disk_modules(it, module_name, output)) }
|
|
52
|
+
.then { it.any? ? abort(it.to_s) : puts("#{output} matches #{input}.") }
|
|
53
|
+
end
|
|
21
54
|
end
|
|
22
55
|
|
|
23
56
|
# COLUMNS="patients:id,age;visits:id,seen_on" — tables separated by `;`,
|
data/lib/jade-sql/version.rb
CHANGED
data/lib/jade-sql.rb
CHANGED
|
@@ -4,6 +4,7 @@ require_relative 'jade-sql/version'
|
|
|
4
4
|
|
|
5
5
|
Jade.extension(__FILE__)
|
|
6
6
|
|
|
7
|
+
require_relative 'jade-sql/compiler'
|
|
7
8
|
require_relative 'jade-sql/uuid_runtime'
|
|
8
9
|
|
|
9
10
|
# Encoded `Sql.SqlError` values (the `[tag, ...args]` shape produced
|
|
@@ -11,29 +12,92 @@ require_relative 'jade-sql/uuid_runtime'
|
|
|
11
12
|
# across the port boundary, and by anyone stubbing the ports in tests.
|
|
12
13
|
module JadeSql
|
|
13
14
|
module SqlErrors
|
|
14
|
-
NOT_FOUND
|
|
15
|
-
|
|
15
|
+
NOT_FOUND = ["NotFound"].freeze
|
|
16
|
+
TOO_MANY_ROWS = ["TooManyRows"].freeze
|
|
17
|
+
DEADLOCK = ["Deadlock"].freeze
|
|
18
|
+
SERIALIZATION_FAILURE = ["SerializationFailure"].freeze
|
|
19
|
+
STATEMENT_TIMEOUT = ["StatementTimeout"].freeze
|
|
20
|
+
LOCK_TIMEOUT = ["LockTimeout"].freeze
|
|
16
21
|
|
|
17
|
-
def self.db_error(msg)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
def self.db_error(msg)
|
|
23
|
+
["DbError", msg]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.not_found
|
|
27
|
+
NOT_FOUND
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.too_many_rows
|
|
31
|
+
TOO_MANY_ROWS
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.unique_violation(name)
|
|
35
|
+
["UniqueViolation", name]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.foreign_key_violation(name)
|
|
39
|
+
["ForeignKeyViolation", name]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.check_violation(name)
|
|
43
|
+
["CheckViolation", name]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.exclusion_violation(name)
|
|
47
|
+
["ExclusionViolation", name]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.not_null_violation(column)
|
|
51
|
+
["NotNullViolation", column]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.deadlock
|
|
55
|
+
DEADLOCK
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.serialization_failure
|
|
59
|
+
SERIALIZATION_FAILURE
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.statement_timeout
|
|
63
|
+
STATEMENT_TIMEOUT
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def self.lock_timeout
|
|
67
|
+
LOCK_TIMEOUT
|
|
68
|
+
end
|
|
21
69
|
end
|
|
22
70
|
end
|
|
23
71
|
|
|
24
72
|
module Sql
|
|
25
73
|
module Errors
|
|
26
74
|
class Error < StandardError; end
|
|
27
|
-
class DbError
|
|
28
|
-
class NotFound
|
|
29
|
-
class
|
|
30
|
-
class
|
|
75
|
+
class DbError < Error; end
|
|
76
|
+
class NotFound < Error; end
|
|
77
|
+
class TooManyRows < Error; end
|
|
78
|
+
class UniqueViolation < Error; end
|
|
79
|
+
class ForeignKeyViolation < Error; end
|
|
80
|
+
class CheckViolation < Error; end
|
|
81
|
+
class ExclusionViolation < Error; end
|
|
82
|
+
class NotNullViolation < Error; end
|
|
83
|
+
class Deadlock < Error; end
|
|
84
|
+
class SerializationFailure < Error; end
|
|
85
|
+
class StatementTimeout < Error; end
|
|
86
|
+
class LockTimeout < Error; end
|
|
31
87
|
|
|
32
88
|
BY_TAG = {
|
|
33
|
-
"DbError"
|
|
34
|
-
"NotFound"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
89
|
+
"DbError" => DbError,
|
|
90
|
+
"NotFound" => NotFound,
|
|
91
|
+
"TooManyRows" => TooManyRows,
|
|
92
|
+
"UniqueViolation" => UniqueViolation,
|
|
93
|
+
"ForeignKeyViolation" => ForeignKeyViolation,
|
|
94
|
+
"CheckViolation" => CheckViolation,
|
|
95
|
+
"ExclusionViolation" => ExclusionViolation,
|
|
96
|
+
"NotNullViolation" => NotNullViolation,
|
|
97
|
+
"Deadlock" => Deadlock,
|
|
98
|
+
"SerializationFailure" => SerializationFailure,
|
|
99
|
+
"StatementTimeout" => StatementTimeout,
|
|
100
|
+
"LockTimeout" => LockTimeout,
|
|
37
101
|
}.freeze
|
|
38
102
|
end
|
|
39
103
|
|
|
@@ -42,4 +106,18 @@ module Sql
|
|
|
42
106
|
klass = Errors::BY_TAG.fetch(type, Errors::Error)
|
|
43
107
|
raise klass, message
|
|
44
108
|
end
|
|
109
|
+
|
|
110
|
+
# The boundary hands back `["ok", value]` or `["err", encoded]`, and the
|
|
111
|
+
# generated `fn!` raises `Jade::Interop::TaskError` for every failure alike.
|
|
112
|
+
# A controller cannot route that: `rescue_from Sql::Errors::NotFound` needs
|
|
113
|
+
# the variant. This raises the variant instead, so one `rescue_from` turns a
|
|
114
|
+
# missing row into a 404 the way `ActiveRecord::RecordNotFound` does.
|
|
115
|
+
#
|
|
116
|
+
# patient = Sql.unwrap!(App.find(id))
|
|
117
|
+
def self.unwrap!(result)
|
|
118
|
+
case result
|
|
119
|
+
in ["ok", value] then value
|
|
120
|
+
in ["err", encoded] then raise_typed!(encoded)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
45
123
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jade-sql
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- agustin
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-09-17 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: jade-lang
|
|
@@ -15,17 +15,17 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.12.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
26
|
-
description: Query and
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
version: 0.12.0
|
|
26
|
+
description: Query and write builders, schema generation from db/structure.sql, and
|
|
27
|
+
an ActiveRecord-backed runtime for the Jade language. Renders typed queries to (String,
|
|
28
|
+
List(Value)) and decodes rows into Jade structs.
|
|
29
29
|
email:
|
|
30
30
|
- agustincornu@fastmail.com
|
|
31
31
|
executables:
|
|
@@ -40,12 +40,19 @@ files:
|
|
|
40
40
|
- exe/jade-sql
|
|
41
41
|
- lib/jade-sql.rb
|
|
42
42
|
- lib/jade-sql/bin/generate_schema.rb
|
|
43
|
+
- lib/jade-sql/compiler.rb
|
|
44
|
+
- lib/jade-sql/compiler/assignable.rb
|
|
45
|
+
- lib/jade-sql/compiler/columns.rb
|
|
46
|
+
- lib/jade-sql/compiler/errors.rb
|
|
43
47
|
- lib/jade-sql/runtime.rb
|
|
48
|
+
- lib/jade-sql/schema_drift.rb
|
|
44
49
|
- lib/jade-sql/sql.jd
|
|
50
|
+
- lib/jade-sql/sql/expr.jd
|
|
51
|
+
- lib/jade-sql/sql/json.jd
|
|
45
52
|
- lib/jade-sql/sql/loader.jd
|
|
46
|
-
- lib/jade-sql/sql/mutation.jd
|
|
47
53
|
- lib/jade-sql/sql/query.jd
|
|
48
54
|
- lib/jade-sql/sql/uuid.jd
|
|
55
|
+
- lib/jade-sql/sql/write.jd
|
|
49
56
|
- lib/jade-sql/tasks.rake
|
|
50
57
|
- lib/jade-sql/uuid_runtime.rb
|
|
51
58
|
- lib/jade-sql/version.rb
|