plume 0.1.0 → 0.3.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 +506 -11
- data/lib/plume/analysis/resolver.rb +797 -0
- data/lib/plume/analysis.rb +211 -0
- data/lib/plume/ast/alter_table_statement.rb +40 -0
- data/lib/plume/ast/analyze_statement.rb +15 -0
- data/lib/plume/ast/assignment.rb +18 -0
- data/lib/plume/ast/attach_statement.rb +17 -0
- data/lib/plume/ast/begin_statement.rb +17 -0
- data/lib/plume/ast/binary_expression.rb +71 -0
- data/lib/plume/ast/case_condition.rb +29 -0
- data/lib/plume/ast/case_expression.rb +22 -0
- data/lib/plume/ast/cast_expression.rb +16 -0
- data/lib/plume/ast/check_column_constraint.rb +20 -0
- data/lib/plume/ast/check_table_constraint.rb +20 -0
- data/lib/plume/ast/collate_column_constraint.rb +19 -0
- data/lib/plume/ast/collation_expression.rb +26 -0
- data/lib/plume/ast/column_constraint.rb +7 -0
- data/lib/plume/ast/column_definition.rb +16 -0
- data/lib/plume/ast/column_name.rb +22 -0
- data/lib/plume/ast/column_type.rb +26 -0
- data/lib/plume/ast/commit_statement.rb +13 -0
- data/lib/plume/ast/common_table_expression.rb +31 -0
- data/lib/plume/ast/compound_select.rb +30 -0
- data/lib/plume/ast/conflict_clause.rb +22 -0
- data/lib/plume/ast/conflict_resolution.rb +20 -0
- data/lib/plume/ast/create_index_statement.rb +29 -0
- data/lib/plume/ast/create_table_statement.rb +47 -0
- data/lib/plume/ast/create_trigger_statement.rb +43 -0
- data/lib/plume/ast/create_view_statement.rb +30 -0
- data/lib/plume/ast/create_virtual_table_statement.rb +28 -0
- data/lib/plume/ast/default_column_constraint.rb +29 -0
- data/lib/plume/ast/deferrable_column_constraint.rb +20 -0
- data/lib/plume/ast/delete_statement.rb +28 -0
- data/lib/plume/ast/detach_statement.rb +13 -0
- data/lib/plume/ast/drop_statement.rb +21 -0
- data/lib/plume/ast/empty_function_argument.rb +6 -0
- data/lib/plume/ast/exists_expression.rb +15 -0
- data/lib/plume/ast/explain_statement.rb +15 -0
- data/lib/plume/ast/expression.rb +30 -0
- data/lib/plume/ast/foreign_key_action.rb +26 -0
- data/lib/plume/ast/foreign_key_clause.rb +50 -0
- data/lib/plume/ast/foreign_key_column_constraint.rb +16 -0
- data/lib/plume/ast/foreign_key_table_constraint.rb +20 -0
- data/lib/plume/ast/frame_boundary.rb +35 -0
- data/lib/plume/ast/frame_spec.rb +34 -0
- data/lib/plume/ast/function_arguments.rb +18 -0
- data/lib/plume/ast/function_reference.rb +29 -0
- data/lib/plume/ast/generated_as_column_constraint.rb +24 -0
- data/lib/plume/ast/indexed_column.rb +24 -0
- data/lib/plume/ast/insert_statement.rb +35 -0
- data/lib/plume/ast/join.rb +12 -0
- data/lib/plume/ast/join_clause.rb +15 -0
- data/lib/plume/ast/join_on_constraint.rb +12 -0
- data/lib/plume/ast/join_operator.rb +31 -0
- data/lib/plume/ast/join_using_constraint.rb +16 -0
- data/lib/plume/ast/like_expression.rb +19 -0
- data/lib/plume/ast/literal_expression.rb +29 -0
- data/lib/plume/ast/literal_false.rb +7 -0
- data/lib/plume/ast/literal_nil.rb +7 -0
- data/lib/plume/ast/literal_value.rb +18 -0
- data/lib/plume/ast/match_clause.rb +15 -0
- data/lib/plume/ast/node.rb +330 -0
- data/lib/plume/ast/noop_column_constraint.rb +15 -0
- data/lib/plume/ast/noop_table_constraint.rb +15 -0
- data/lib/plume/ast/not_like_expression.rb +7 -0
- data/lib/plume/ast/not_null_column_constraint.rb +17 -0
- data/lib/plume/ast/null_column_constraint.rb +17 -0
- data/lib/plume/ast/ordering_term.rb +32 -0
- data/lib/plume/ast/over_clause.rb +25 -0
- data/lib/plume/ast/parenthetical_expression.rb +37 -0
- data/lib/plume/ast/parenthetical_source.rb +19 -0
- data/lib/plume/ast/pragma_statement.rb +26 -0
- data/lib/plume/ast/primary_key_column_constraint.rb +23 -0
- data/lib/plume/ast/primary_key_table_constraint.rb +23 -0
- data/lib/plume/ast/raise_expression.rb +23 -0
- data/lib/plume/ast/reindex_statement.rb +15 -0
- data/lib/plume/ast/release_statement.rb +16 -0
- data/lib/plume/ast/result_column.rb +18 -0
- data/lib/plume/ast/returning_clause.rb +12 -0
- data/lib/plume/ast/rollback_statement.rb +19 -0
- data/lib/plume/ast/savepoint_statement.rb +16 -0
- data/lib/plume/ast/select_core.rb +27 -0
- data/lib/plume/ast/select_statement.rb +34 -0
- data/lib/plume/ast/star_function_argument.rb +6 -0
- data/lib/plume/ast/star_result_column.rb +16 -0
- data/lib/plume/ast/strict_table_option.rb +6 -0
- data/lib/plume/ast/subquery_expression.rb +14 -0
- data/lib/plume/ast/subquery_source.rb +19 -0
- data/lib/plume/ast/table_constraint.rb +7 -0
- data/lib/plume/ast/table_function.rb +28 -0
- data/lib/plume/ast/table_name.rb +28 -0
- data/lib/plume/ast/table_option.rb +7 -0
- data/lib/plume/ast/ternary_expression.rb +26 -0
- data/lib/plume/ast/token.rb +183 -0
- data/lib/plume/ast/unary_expression.rb +36 -0
- data/lib/plume/ast/unique_column_constraint.rb +17 -0
- data/lib/plume/ast/unique_table_constraint.rb +20 -0
- data/lib/plume/ast/update_statement.rb +35 -0
- data/lib/plume/ast/upsert_clause.rb +26 -0
- data/lib/plume/ast/vacuum_statement.rb +18 -0
- data/lib/plume/ast/values_clause.rb +12 -0
- data/lib/plume/ast/values_row.rb +13 -0
- data/lib/plume/ast/variable.rb +15 -0
- data/lib/plume/ast/window_definition.rb +26 -0
- data/lib/plume/ast/with_clause.rb +15 -0
- data/lib/plume/ast/without_rowid_table_option.rb +6 -0
- data/lib/plume/catalog.rb +276 -0
- data/lib/plume/comment.rb +73 -0
- data/lib/plume/dump.rb +143 -0
- data/lib/plume/fingerprint.rb +86 -0
- data/lib/plume/lexer.rb +640 -0
- data/lib/plume/literal_patches.rb +76 -0
- data/lib/plume/normalize.rb +65 -0
- data/lib/plume/parameters.rb +52 -0
- data/lib/plume/parser.rb +4064 -0
- data/lib/plume/pretty_printer.rb +202 -0
- data/lib/plume/printer.rb +525 -0
- data/lib/plume/sqlite_grammar.rb +86 -0
- data/lib/plume/truncate.rb +67 -0
- data/lib/plume/union.rb +28 -0
- data/lib/plume/version.rb +1 -1
- data/lib/plume.rb +274 -3
- metadata +176 -12
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
class OrderingTerm < Node
|
|
5
|
+
Direction = _Union(
|
|
6
|
+
:ASC, "ASC", :asc, "asc", :ASCENDING, "ASCENDING", :ascending, "ascending",
|
|
7
|
+
:DESC, "DESC", :desc, "desc", :DESCENDING, "DESCENDING", :descending, "descending",
|
|
8
|
+
)
|
|
9
|
+
Nulls = _Union(
|
|
10
|
+
:FIRST, "FIRST", :first, "first",
|
|
11
|
+
:LAST, "LAST", :last, "last",
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
token :collate_kw
|
|
15
|
+
token :collation_tk
|
|
16
|
+
token :direction_tk
|
|
17
|
+
token :nulls_kw
|
|
18
|
+
token :nulls_tk
|
|
19
|
+
|
|
20
|
+
node :expression, Expression
|
|
21
|
+
attribute :collation, Stringy
|
|
22
|
+
attribute :direction, Direction
|
|
23
|
+
attribute :nulls, Nulls
|
|
24
|
+
|
|
25
|
+
def self.new(*, **) = super
|
|
26
|
+
def self.concrete(*, **) = super
|
|
27
|
+
|
|
28
|
+
def collation = (@collation == LiteralNil) ? Node.collation_name(collation_tk_val) : @collation
|
|
29
|
+
def direction = (@direction == LiteralNil) ? direction_tk_val&.to_sym&.upcase : @direction
|
|
30
|
+
def nulls = (@nulls == LiteralNil) ? nulls_tk_val&.to_sym&.upcase : @nulls
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
class OverClause < Node
|
|
5
|
+
token :over_kw
|
|
6
|
+
token :window_lp
|
|
7
|
+
token :base_window_name_tk
|
|
8
|
+
token :partition_by_kw
|
|
9
|
+
token :order_by_kw
|
|
10
|
+
token :window_rp
|
|
11
|
+
token :window_name_tk
|
|
12
|
+
|
|
13
|
+
nodes :partitions, Expression
|
|
14
|
+
nodes :orderings, OrderingTerm
|
|
15
|
+
node :frame, FrameSpec
|
|
16
|
+
attribute :window_name, Stringy
|
|
17
|
+
attribute :base_window_name, Stringy
|
|
18
|
+
|
|
19
|
+
def self.new(*, **) = super
|
|
20
|
+
def self.concrete(*, over_kw:, **) = super
|
|
21
|
+
|
|
22
|
+
def window_name = (@window_name == LiteralNil) ? window_name_tk_val : @window_name
|
|
23
|
+
def base_window_name = (@base_window_name == LiteralNil) ? base_window_name_tk_val : @base_window_name
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
class ParentheticalExpression < Node
|
|
5
|
+
token :value_lp
|
|
6
|
+
token :value_tk
|
|
7
|
+
token :value_rp
|
|
8
|
+
|
|
9
|
+
# Hand-built trees may wrap plain Ruby values; a lambda keeps them out of the union's
|
|
10
|
+
# plain-value set, see Node.attribute
|
|
11
|
+
attribute :value, _Union(Expression, _Array(Expression), -> (v) { LiteralValue === v })
|
|
12
|
+
|
|
13
|
+
def self.new(*, value:, **) = super
|
|
14
|
+
def self.concrete(*, **) = super
|
|
15
|
+
|
|
16
|
+
# Parser may pass either tokens or attributes, so
|
|
17
|
+
# require none in `concrete` signature but ensure presence here.
|
|
18
|
+
def after_initialize
|
|
19
|
+
if @value == LiteralNil && @value_tk == LiteralNil
|
|
20
|
+
raise ArgumentError.new("missing either: :value, :value_tk")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# The child as stored - nil only for the empty list of `x IN ()`. Unlike `value`, a NULL
|
|
25
|
+
# literal stays a node, so it cannot be mistaken for that empty list
|
|
26
|
+
def contents = LiteralNil.equal?(@value) ? value_tk_val : @value
|
|
27
|
+
|
|
28
|
+
def value
|
|
29
|
+
case (v = contents)
|
|
30
|
+
when LiteralNil then nil
|
|
31
|
+
when LiteralFalse then false
|
|
32
|
+
when LiteralExpression then v.value
|
|
33
|
+
else v
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# A parenthesized join or source list used as a FROM source, like `(a JOIN b) AS ab`
|
|
5
|
+
class ParentheticalSource < Node
|
|
6
|
+
token :source_lp
|
|
7
|
+
token :source_rp
|
|
8
|
+
token :as_kw
|
|
9
|
+
token :alias_tk
|
|
10
|
+
|
|
11
|
+
node :source, _Any
|
|
12
|
+
attribute :alias, Stringy
|
|
13
|
+
|
|
14
|
+
def self.new(*, source:, **) = super
|
|
15
|
+
def self.concrete(*, source:, **) = super
|
|
16
|
+
|
|
17
|
+
def alias = (@alias == LiteralNil) ? alias_tk_val : @alias
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# **[SQLite Docs](https://www.sqlite.org/pragma.html)**
|
|
5
|
+
class PragmaStatement < Node
|
|
6
|
+
token :pragma_kw
|
|
7
|
+
token :schema_tk
|
|
8
|
+
token :dot_tk
|
|
9
|
+
token :name_tk
|
|
10
|
+
token :eq_tk # `=`, or the opening parenthesis of `PRAGMA name(value)`
|
|
11
|
+
token :value_tk
|
|
12
|
+
token :value_rp
|
|
13
|
+
|
|
14
|
+
attribute :schema, Stringy
|
|
15
|
+
attribute :name, Stringy
|
|
16
|
+
|
|
17
|
+
def self.new(*, name:, **) = super
|
|
18
|
+
def self.concrete(*, pragma_kw:, name_tk:, **) = super
|
|
19
|
+
|
|
20
|
+
def schema = (@schema == LiteralNil) ? schema_tk_val : @schema
|
|
21
|
+
def name = (@name == LiteralNil) ? name_tk_val : @name
|
|
22
|
+
|
|
23
|
+
# As written: numbers come out as numbers, keywords and names as strings
|
|
24
|
+
inspectable def value = value_tk_val
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
class PrimaryKeyColumnConstraint < ColumnConstraint
|
|
5
|
+
token :constraint_kw
|
|
6
|
+
token :name_tk
|
|
7
|
+
token :primary_key_kw
|
|
8
|
+
token :direction_tk
|
|
9
|
+
token :autoincrement_kw
|
|
10
|
+
|
|
11
|
+
attribute :name, Stringy
|
|
12
|
+
attribute :direction, Stringy
|
|
13
|
+
attribute :autoincrement, _Boolean
|
|
14
|
+
node :conflict_clause, ConflictClause
|
|
15
|
+
|
|
16
|
+
def self.new(*, **) = super
|
|
17
|
+
def self.concrete(*, primary_key_kw:, **) = super
|
|
18
|
+
|
|
19
|
+
def name = (@name == LiteralNil) ? name_tk_val : @name
|
|
20
|
+
def direction = (@direction == LiteralNil) ? direction_tk_val&.to_sym&.upcase : @direction
|
|
21
|
+
def autoincrement = (@autoincrement == LiteralNil) ? autoincrement_kw? : @autoincrement
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
class PrimaryKeyTableConstraint < TableConstraint
|
|
5
|
+
token :constraint_kw
|
|
6
|
+
token :name_tk
|
|
7
|
+
token :primary_key_kw
|
|
8
|
+
token :primary_key_lp
|
|
9
|
+
token :autoincrement_kw
|
|
10
|
+
token :primary_key_rp
|
|
11
|
+
|
|
12
|
+
attribute :name, Stringy
|
|
13
|
+
attribute :autoincrement, _Boolean
|
|
14
|
+
nodes :columns, IndexedColumn
|
|
15
|
+
node :conflict_clause, ConflictClause
|
|
16
|
+
|
|
17
|
+
def self.new(*, columns:, **) = super
|
|
18
|
+
def self.concrete(*, primary_key_kw:, columns:, **) = super
|
|
19
|
+
|
|
20
|
+
def name = (@name == LiteralNil) ? name_tk_val : @name
|
|
21
|
+
def autoincrement = (@autoincrement == LiteralNil) ? autoincrement_kw? : @autoincrement
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
class RaiseExpression < Node
|
|
5
|
+
Type = _Union(:IGNORE, :ROLLBACK, :ABORT, :FAIL)
|
|
6
|
+
|
|
7
|
+
token :raise_kw # required
|
|
8
|
+
token :raise_lp # required
|
|
9
|
+
token :type_kw # required
|
|
10
|
+
token :comma # maybe
|
|
11
|
+
token :error_message_tk # maybe
|
|
12
|
+
token :raise_rp # required
|
|
13
|
+
|
|
14
|
+
attribute :type, Type # required
|
|
15
|
+
attribute :error_message, Expression # maybe
|
|
16
|
+
|
|
17
|
+
def self.new(*, type:, **) = super
|
|
18
|
+
def self.concrete(*, raise_kw:, raise_lp:, type_kw:, raise_rp:, **) = super
|
|
19
|
+
|
|
20
|
+
def type = (@type == LiteralNil) ? type_kw_src.to_sym.upcase : @type
|
|
21
|
+
def error_message = (@error_message == LiteralNil) ? error_message_tk_val : @error_message
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# **[SQLite Docs](https://www.sqlite.org/lang_reindex.html)**
|
|
5
|
+
#
|
|
6
|
+
# `target` names a schema, table or index - SQLite works out which at run time
|
|
7
|
+
class ReindexStatement < Node
|
|
8
|
+
token :reindex_kw
|
|
9
|
+
|
|
10
|
+
node :target, TableName
|
|
11
|
+
|
|
12
|
+
def self.new(*, **) = super
|
|
13
|
+
def self.concrete(*, reindex_kw:, **) = super
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# **[SQLite Docs](https://www.sqlite.org/lang_savepoint.html)**
|
|
5
|
+
class ReleaseStatement < Node
|
|
6
|
+
token :release_kw # RELEASE or RELEASE SAVEPOINT
|
|
7
|
+
token :name_tk
|
|
8
|
+
|
|
9
|
+
attribute :name, Stringy
|
|
10
|
+
|
|
11
|
+
def self.new(*, name:, **) = super
|
|
12
|
+
def self.concrete(*, release_kw:, name_tk:, **) = super
|
|
13
|
+
|
|
14
|
+
def name = (@name == LiteralNil) ? name_tk_val : @name
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
class ResultColumn < Node
|
|
5
|
+
token :as_kw
|
|
6
|
+
token :alias_tk
|
|
7
|
+
token :result_tk
|
|
8
|
+
|
|
9
|
+
node :result, Expression
|
|
10
|
+
attribute :alias, Stringy
|
|
11
|
+
|
|
12
|
+
def self.new(*, result:, **) = super
|
|
13
|
+
def self.concrete(*, **) = super
|
|
14
|
+
|
|
15
|
+
def result = (@result == LiteralNil) ? result_tk_val : @result
|
|
16
|
+
def alias = (@alias == LiteralNil) ? alias_tk_val : @alias
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
class ReturningClause < Node
|
|
5
|
+
token :returning_kw
|
|
6
|
+
|
|
7
|
+
nodes :columns, _Union(ResultColumn, StarResultColumn)
|
|
8
|
+
|
|
9
|
+
def self.new(*, columns:, **) = super
|
|
10
|
+
def self.concrete(*, returning_kw:, columns:, **) = super
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# **[SQLite Docs](https://www.sqlite.org/lang_transaction.html)**
|
|
5
|
+
class RollbackStatement < Node
|
|
6
|
+
token :rollback_kw
|
|
7
|
+
token :transaction_kw
|
|
8
|
+
token :name_tk
|
|
9
|
+
token :to_kw # TO or TO SAVEPOINT
|
|
10
|
+
token :savepoint_tk
|
|
11
|
+
|
|
12
|
+
attribute :savepoint, Stringy
|
|
13
|
+
|
|
14
|
+
def self.new(*, **) = super
|
|
15
|
+
def self.concrete(*, rollback_kw:, **) = super
|
|
16
|
+
|
|
17
|
+
def savepoint = (@savepoint == LiteralNil) ? savepoint_tk_val : @savepoint
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# **[SQLite Docs](https://www.sqlite.org/lang_savepoint.html)**
|
|
5
|
+
class SavepointStatement < Node
|
|
6
|
+
token :savepoint_kw
|
|
7
|
+
token :name_tk
|
|
8
|
+
|
|
9
|
+
attribute :name, Stringy
|
|
10
|
+
|
|
11
|
+
def self.new(*, name:, **) = super
|
|
12
|
+
def self.concrete(*, savepoint_kw:, name_tk:, **) = super
|
|
13
|
+
|
|
14
|
+
def name = (@name == LiteralNil) ? name_tk_val : @name
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# A single `SELECT … FROM … WHERE … GROUP BY … HAVING … WINDOW …`, without the
|
|
5
|
+
# statement-level `WITH`, `ORDER BY` and `LIMIT`
|
|
6
|
+
class SelectCore < Node
|
|
7
|
+
token :select_kw
|
|
8
|
+
token :type_tk
|
|
9
|
+
token :from_kw
|
|
10
|
+
token :where_kw
|
|
11
|
+
token :group_by_kw
|
|
12
|
+
token :having_kw
|
|
13
|
+
token :window_kw
|
|
14
|
+
|
|
15
|
+
nodes :columns, _Union(ResultColumn, StarResultColumn)
|
|
16
|
+
node :source, _Any
|
|
17
|
+
node :condition, Expression
|
|
18
|
+
nodes :groupings, Expression
|
|
19
|
+
node :having, Expression
|
|
20
|
+
nodes :windows, WindowDefinition
|
|
21
|
+
|
|
22
|
+
def self.new(*, columns:, **) = super
|
|
23
|
+
def self.concrete(*, select_kw:, columns:, **) = super
|
|
24
|
+
|
|
25
|
+
inspectable def distinct = type_tk_tok == :DISTINCT
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# **[SQLite Docs](https://www.sqlite.org/lang_select.html)**
|
|
5
|
+
#
|
|
6
|
+
# ```sql
|
|
7
|
+
# with t as (select 1) select * from t union select 2 order by 1 limit 1
|
|
8
|
+
# ```
|
|
9
|
+
#
|
|
10
|
+
# `body` is a `SelectCore`, a `ValuesClause`, or a `CompoundSelect` of those.
|
|
11
|
+
# `ORDER BY` and `LIMIT` belong to the statement as a whole, not to its last core.
|
|
12
|
+
class SelectStatement < Node
|
|
13
|
+
token :order_by_kw
|
|
14
|
+
token :limit_kw
|
|
15
|
+
token :offset_tk # OFFSET keyword, or the comma in `LIMIT offset, limit`
|
|
16
|
+
|
|
17
|
+
node :with_clause, _Any
|
|
18
|
+
node :body, _Any
|
|
19
|
+
nodes :orderings, OrderingTerm
|
|
20
|
+
node :limit, Expression
|
|
21
|
+
node :offset, Expression
|
|
22
|
+
|
|
23
|
+
def self.new(*, body:, **) = super
|
|
24
|
+
def self.concrete(*, body:, **) = super
|
|
25
|
+
|
|
26
|
+
# Every `SelectCore` and `ValuesClause` making up the body, left to right
|
|
27
|
+
def cores
|
|
28
|
+
case body
|
|
29
|
+
when CompoundSelect then body.cores
|
|
30
|
+
else [body]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
class StarResultColumn < Node
|
|
5
|
+
token :table_tk
|
|
6
|
+
token :dot_tk
|
|
7
|
+
token :star_tk
|
|
8
|
+
|
|
9
|
+
attribute :table, Stringy
|
|
10
|
+
|
|
11
|
+
def self.new(*, **) = super
|
|
12
|
+
def self.concrete(*, star_tk:, **) = super
|
|
13
|
+
|
|
14
|
+
def table = (@table == LiteralNil) ? table_tk_val : @table
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# A scalar subquery `(SELECT …)`, also the right side of `x IN (SELECT …)`
|
|
5
|
+
class SubqueryExpression < Node
|
|
6
|
+
token :select_lp
|
|
7
|
+
token :select_rp
|
|
8
|
+
|
|
9
|
+
node :select, SelectStatement
|
|
10
|
+
|
|
11
|
+
def self.new(*, select:, **) = super
|
|
12
|
+
def self.concrete(*, select:, **) = super
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# A parenthesized select used as a FROM source, like `(SELECT …) AS s`
|
|
5
|
+
class SubquerySource < Node
|
|
6
|
+
token :select_lp
|
|
7
|
+
token :select_rp
|
|
8
|
+
token :as_kw
|
|
9
|
+
token :alias_tk
|
|
10
|
+
|
|
11
|
+
node :select, SelectStatement
|
|
12
|
+
attribute :alias, Stringy
|
|
13
|
+
|
|
14
|
+
def self.new(*, select:, **) = super
|
|
15
|
+
def self.concrete(*, select:, **) = super
|
|
16
|
+
|
|
17
|
+
def alias = (@alias == LiteralNil) ? alias_tk_val : @alias
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# A table-valued function used as a FROM source, like `json_each(doc) AS j`
|
|
5
|
+
class TableFunction < Node
|
|
6
|
+
token :schema_tk
|
|
7
|
+
token :dot_tk
|
|
8
|
+
token :function_tk
|
|
9
|
+
token :arguments_lp
|
|
10
|
+
token :arguments_rp
|
|
11
|
+
token :as_kw
|
|
12
|
+
token :alias_tk
|
|
13
|
+
|
|
14
|
+
attribute :schema, Stringy
|
|
15
|
+
attribute :function, Stringy
|
|
16
|
+
nodes :arguments, Expression
|
|
17
|
+
attribute :alias, Stringy
|
|
18
|
+
|
|
19
|
+
def self.new(*, function:, **) = super
|
|
20
|
+
def self.concrete(*, function_tk:, **) = super
|
|
21
|
+
|
|
22
|
+
def schema = (@schema == LiteralNil) ? schema_tk_val : @schema
|
|
23
|
+
def function = (@function == LiteralNil) ? function_tk_val : @function
|
|
24
|
+
def alias = (@alias == LiteralNil) ? alias_tk_val : @alias
|
|
25
|
+
|
|
26
|
+
alias_method :name, :function
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
class TableName < Node
|
|
5
|
+
token :schema_tk
|
|
6
|
+
token :dot_tk
|
|
7
|
+
token :table_tk
|
|
8
|
+
token :as_kw
|
|
9
|
+
token :alias_tk
|
|
10
|
+
token :indexed_kw # INDEXED BY, or NOT INDEXED
|
|
11
|
+
token :index_tk
|
|
12
|
+
|
|
13
|
+
attribute :schema, Stringy
|
|
14
|
+
attribute :table, Stringy
|
|
15
|
+
attribute :alias, Stringy
|
|
16
|
+
|
|
17
|
+
def self.new(*, table:, **) = super
|
|
18
|
+
def self.concrete(*, table_tk:, **) = super
|
|
19
|
+
|
|
20
|
+
def schema = (@schema == LiteralNil) ? schema_tk_val : @schema
|
|
21
|
+
def table = (@table == LiteralNil) ? table_tk_val : @table
|
|
22
|
+
def alias = (@alias == LiteralNil) ? alias_tk_val : @alias
|
|
23
|
+
def indexed_by = index_tk_val
|
|
24
|
+
def not_indexed = indexed_kw_tok == [:NOT, :INDEXED]
|
|
25
|
+
|
|
26
|
+
alias_method :name, :table
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plume
|
|
4
|
+
# `left [NOT] BETWEEN middle AND right`
|
|
5
|
+
class TernaryExpression < Node
|
|
6
|
+
TOKEN_TO_OPERATOR = {
|
|
7
|
+
:BETWEEN => :BETWEEN,
|
|
8
|
+
[:BETWEEN].freeze => :BETWEEN,
|
|
9
|
+
[:NOT, :BETWEEN].freeze => :NOT_BETWEEN,
|
|
10
|
+
}.freeze
|
|
11
|
+
Operator = _Union(*TOKEN_TO_OPERATOR.values)
|
|
12
|
+
|
|
13
|
+
token :operator_tk
|
|
14
|
+
token :and_kw
|
|
15
|
+
|
|
16
|
+
attribute :operator, Operator
|
|
17
|
+
node :left, Expression
|
|
18
|
+
node :middle, Expression
|
|
19
|
+
node :right, Expression
|
|
20
|
+
|
|
21
|
+
def self.new(*, operator:, left:, middle:, right:, **) = super
|
|
22
|
+
def self.concrete(*, operator_tk:, left:, middle:, right:, **) = super
|
|
23
|
+
|
|
24
|
+
def operator = (@operator == LiteralNil) ? TOKEN_TO_OPERATOR[operator_tk_tok] : @operator
|
|
25
|
+
end
|
|
26
|
+
end
|