firefly-compiler 0.6.27 → 0.6.30

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.
@@ -1,34 +0,0 @@
1
- import Syntax from ff:compiler
2
-
3
- data SqlParameter(name: String, sqlType: String)
4
- data SqlStatement(termAt: Location, at: Location, string: String, parameters: Option[List[SqlParameter]])
5
-
6
- extractStatements(terms: List[Term]): List[SqlStatement] {
7
- let statements = terms.collect {extract(_, None)}
8
- let sorted = statements.sortBy {-_.parameters.map {_.size()}.else {-1}}
9
- sorted.map {s => Pair(s.termAt, s)}.group().values().map {_.grabFirst()}
10
- }
11
-
12
- extract(term: Term, parameters: Option[List[SqlParameter]]): Option[SqlStatement] {
13
- | ECall(_, StaticCall s, _, _, [_, Argument(_, _, EString(at, value)), ...], _), _ {s.name == "ff:postgresql/Pg.PgConnection_statement"} =>
14
- let prefix = if(value.startsWith("\"\"\"")) {3} else {1}
15
- Some(SqlStatement(
16
- termAt = at
17
- at = at.Location(column = at.column + prefix)
18
- string = value.dropFirst(prefix).dropLast(prefix) // TODO
19
- parameters
20
- ))
21
- | ECall(_, StaticCall s, _, _, [a1, Argument(_, _, EString(_, n)), ...], _), _ {s.name.removeFirst("ff:postgresql/Pg.PgStatement_with") | Some(t)} =>
22
- let sqlType = t.{
23
- | "String" => "text"
24
- | "Int" => "bigint"
25
- | _ => "text"
26
- }
27
- let prefix = if(n.startsWith("\"\"\"")) {3} else {1}
28
- let parameter = SqlParameter(n.dropFirst(prefix).dropLast(prefix), sqlType)
29
- extract(a1.value, Some([...parameters.toList().flatten(), parameter]))
30
- | ECall(_, _, _, _, [a, ...], _), _ =>
31
- extract(a.value, parameters)
32
- | _, _ =>
33
- None
34
- }
@@ -1,295 +0,0 @@
1
- import Sql
2
-
3
- data SqlSuggestion {
4
- SqlSuggestionRegular(label: String, display: String, documentation: String)
5
- SqlSuggestionFunction(label: String, signature: String, documentation: String)
6
- SqlSuggestionJoin(label: String, schema: String, snippet: String)
7
- SqlSuggestionColumnNames(required: Bool, columns: List[Pair[String, String]])
8
- SqlSuggestionColumnSetters(columns: List[Pair[String, String]])
9
- }
10
-
11
- extend self: SqlSuggestion {
12
- secondarySort(): Int {
13
- self.{
14
- | SqlSuggestionFunction(_, _, _) => 8
15
- | SqlSuggestionJoin(_, _, _) => 1
16
- | SqlSuggestionColumnSetters(columns) => 4
17
- | SqlSuggestionColumnNames(required, columns) =>
18
- if(required) {1} elseIf {columns.size() > 1} {9} else {4}
19
- | SqlSuggestionRegular(l, display, documentation) =>
20
- if(display.endsWith(" table") || display.endsWith(" tables")) {
21
- if(l.startsWith("pg_") || l == "information_schema") {7} else {6}
22
- } else:
23
- if(display.startsWith("(") || display.contains(".")) {5} else:
24
- if(display.endsWith(" null") || display.endsWith(" key")) {4} else:
25
- if(documentation.startsWith("-- view")) {2} else:
26
- 3
27
- }
28
- }
29
- }
30
-
31
- suggest(data: SqlData, tokens: List[SqlToken], line: Int, column: Int): Pair[List[SqlSuggestion], Bool] {
32
- let scope = Sql.completionScope(tokens, line, column)
33
- let suggestTable = scope.expectingTable && !scope.avoidTables
34
- let searchPathSchemas = data.searchPathSchemas.filter {_ != "pg_catalog"}.toSet()
35
- let suggestions = do {
36
- scope.expectingColumnNames.map {seen =>
37
- sqlColumnNameSuggestions(scope, data, seen)
38
- } else:
39
- scope.expectingColumnSetters.map {seen =>
40
- sqlColumnSetterSuggestions(scope, data, seen)
41
- } else:
42
- scope.beforeDot.map {beforeDot =>
43
- sqlBeforeDotSuggestions(beforeDot, scope, data, suggestTable)
44
- }.elseIf {scope.expectingTable} {
45
- sqlExpectingTableSuggestions(scope, data, searchPathSchemas, suggestTable)
46
- } else {
47
- sqlColumnSuggestions(scope, data)
48
- }.addAll(if(!scope.beforeDot.isEmpty()) {[]} else {
49
- sqlSchemaSuggestions(data)
50
- }).addAll(if(!scope.expectingJoin) {[]} else {
51
- sqlJoinSuggestions(scope, data, searchPathSchemas)
52
- })
53
- }
54
- Pair(suggestions, scope.inQuotes)
55
- }
56
-
57
- showSqlColumnType(column: SqlColumn): String {
58
- column.type.replace("\"", "") + " " +
59
- if(column.primaryKey) {"primary key"} elseIf {column.notNull} {"not null"} else {"null"}
60
- }
61
-
62
- showSqlColumn(column: SqlColumn): String {
63
- Sql.quote(column.name, True) + " " + showSqlColumnType(column) +
64
- column.default.map {" default " + _}.else {""}
65
- }
66
-
67
- showSqlForeignKeys(schema: String, table: String, column: String, data: SqlData): String {
68
- data.foreignKeys.filter {k =>
69
- k.schema == schema && k.name == table && k.columns.any {_.first == column}
70
- }.map {k =>
71
- if(k.columns.size() == 1) {""} else {"(" + k.columns.map {Sql.quote(_.first)}.join(", ") + ") "} +
72
- "references " +
73
- if(k.foreignSchema != schema) {Sql.quote(k.foreignSchema) + "."} else {""} +
74
- if(k.foreignName != table) {Sql.quote(k.foreignName)} else {""} +
75
- "(" + k.columns.map {_.second}.map {Sql.quote(_)}.join(", ") + ")"
76
- }.sortBy {t => Pair(if(t.startsWith("references ")) {1} else {2}, t)}.map {"\n" + _}.join() +
77
- data.foreignKeys.filter {k =>
78
- k.foreignSchema == schema && k.foreignName == table && k.columns.any {_.second == column}
79
- }.map {k =>
80
- if(k.schema != schema) {Sql.quote(k.schema) + "."} else {""} +
81
- if(k.name != table) {Sql.quote(k.name)} else {""} +
82
- "(" + k.columns.map {_.first}.map {Sql.quote(_)}.join(", ") + ") " +
83
- "references " +
84
- "(" + k.columns.map {_.second}.map {Sql.quote(_)}.join(", ") + ")"
85
- }.sort().map {"\n" + _}.join()
86
- }
87
-
88
- showSqlView(r: SqlRelation): String {
89
- if(r.kind != "v") {""} else:
90
- "-- view" + r.simpleView.map {v =>
91
- " of " + v.schema.map {Sql.quote(_) + "."}.else {""} + Sql.quote(v.table) +
92
- "(" + [...v.columns.map {Sql.quote(_)}, "..."].join(", ") + ")"
93
- }.else {""}
94
- }
95
-
96
- documentSqlFunction(f: SqlFunction): String {
97
- let names = f.argumentNames.pairs().filter {_.second != ""}.toMap()
98
- f.description.map {_.lines().map {("-- " + _).trim() + "\n"}.join()}.else {""} +
99
- f.kind + " " + f.schema + "." + f.name + "(" +
100
- f.argumentTypes.pairs().map {| Pair(i, t) =>
101
- "\n " + names.get(i).map {Sql.quote(_, True) + " "}.else {""} + t
102
- }.join(",") + "\n) " + f.returnType
103
- }
104
-
105
- sqlBeforeDotSuggestions(
106
- beforeDot: String
107
- scope: SqlCompletionScope
108
- data: SqlData
109
- suggestTable: Bool
110
- ): List[SqlSuggestion] {
111
- function suggestColumns(relation: SqlRelation): List[SqlSuggestion] {
112
- relation.columns.map {c =>
113
- let description =
114
- c.description.map {_.lines().map {("-- " + _).trim() + "\n"}.join()}.else {""}
115
- let foreignKeys = if(relation.kind == "v") {
116
- relation.simpleView.flatMap {v =>
117
- v.schema.map {showSqlForeignKeys(_, v.table, c.name, data)}
118
- }.else {""}
119
- } else {showSqlForeignKeys(relation.schema, relation.name, c.name, data)}
120
- SqlSuggestionRegular(c.name, showSqlColumnType(c), description + showSqlColumn(c) + foreignKeys)
121
- }
122
- }
123
- scope.symbols.flatMap {
124
- | SqlTable(Some(alias), schema, table) {!scope.expectingTable && alias == beforeDot} =>
125
- data.relations.filter {r => schema.all {_ == r.schema} && r.name == table}.flatMap {r =>
126
- suggestColumns(r)
127
- }
128
- | SqlQuery(alias, columns) {!scope.expectingTable && alias == beforeDot} =>
129
- columns.map {c => SqlSuggestionRegular(c, "from subquery", c)}
130
- | _ =>
131
- []
132
- }.addAll(
133
- if(!suggestTable) {
134
- if(scope.targetTable.isEmpty() || (beforeDot != "old" && beforeDot != "new")) {[]} else:
135
- let aliases = scope.symbols.collect {_.{
136
- | SqlQuery(alias, _) => Some(alias)
137
- | SqlTable(alias, _, _) => alias
138
- }}
139
- if(aliases.any {_ == beforeDot}) {[]} else:
140
- let table = scope.targetTable.grab()
141
- data.relations.filter {r => table.first.all {_ == r.schema} && r.name == table.second}.flatMap {r =>
142
- suggestColumns(r)
143
- }
144
- } else {
145
- data.relations.filter {r =>
146
- let kindName = r.kindName()
147
- r.schema == beforeDot && (kindName.contains("table") || kindName.contains("view"))
148
- }.map {r =>
149
- SqlSuggestionRegular(r.name, r.schema, showSqlView(r) + r.columns.map {showSqlColumn(_)}.join("\n"))
150
- }
151
- }
152
- ).addAll(data.functions.filter {_.schema == beforeDot}.map {f =>
153
- SqlSuggestionFunction(f.name, "(" + f.argumentTypes.join(", ") + ") " + f.returnType, documentSqlFunction(f))
154
- })
155
- }
156
-
157
- sqlExpectingTableSuggestions(
158
- scope: SqlCompletionScope
159
- data: SqlData
160
- searchPathSchemas: Set[String]
161
- suggestTable: Bool
162
- ): List[SqlSuggestion] {
163
- if(!suggestTable) {[]} else:
164
- scope.symbols.flatMap {
165
- | SqlQuery(alias, columns) =>
166
- [SqlSuggestionRegular(alias, "(" + columns.join(", ") + ")", "(" + columns.join(", ") + ")")]
167
- | _ =>
168
- []
169
- }.addAll(
170
- data.relations.filter {r => searchPathSchemas.contains(r.schema) && r.tableLike()}.map {r =>
171
- SqlSuggestionRegular(r.name, r.schema, showSqlView(r) + r.columns.map {showSqlColumn(_)}.join("\n"))
172
- }
173
- )
174
- }
175
-
176
- sqlColumnNameSuggestions(scope: SqlCompletionScope, data: SqlData, seen: Set[String]): List[SqlSuggestion] {
177
- scope.targetTable.toList().flatMap {| Pair(schema, table) =>
178
- let relation = data.relations.filter {
179
- r => schema.all {_ == r.schema} && table == r.name
180
- }
181
- let requiredColumns = relation.flatMap {_.columns.filter {c =>
182
- c.notNull && c.default.isEmpty() && c.type != "bigserial" && c.type != "serial"
183
- }}.filter {!seen.contains(_.name)}
184
- let allColumns = relation.flatMap {_.columns}.filter {!seen.contains(_.name)}
185
- [
186
- SqlSuggestionColumnNames(True, requiredColumns.map {c => Pair(c.name, showSqlColumn(c))})
187
- ...if(allColumns != requiredColumns) {[
188
- SqlSuggestionColumnNames(False, allColumns.map {c => Pair(c.name, showSqlColumn(c))})
189
- ]} else {[]}
190
- ...if(allColumns.size() > 1) {
191
- allColumns.map {c => SqlSuggestionColumnNames(False, [Pair(c.name, showSqlColumn(c))])}
192
- } else {[]}
193
- ]
194
- }
195
- }
196
-
197
- sqlColumnSetterSuggestions(scope: SqlCompletionScope, data: SqlData, seen: Set[String]): List[SqlSuggestion] {
198
- scope.targetTable.toList().flatMap {| Pair(schema, table) =>
199
- let allColumns = data.relations.filter {
200
- r => schema.all {_ == r.schema} && table == r.name
201
- }.flatMap {_.columns}.filter {!seen.contains(_.name)}
202
- allColumns.map {c => SqlSuggestionColumnSetters([Pair(c.name, showSqlColumn(c))])}
203
- }
204
- }
205
-
206
- sqlColumnSuggestions(scope: SqlCompletionScope, data: SqlData): List[SqlSuggestion] {
207
- scope.symbols.flatMap {
208
- | SqlQuery(alias, columns) =>
209
- [SqlSuggestionRegular(alias, "(" + columns.join(", ") + ")", "(" + columns.join(", ") + ")")]
210
- | SqlTable(Some(alias), schema, table) =>
211
- let tableText = data.relations.filter {
212
- r => schema.all {_ == r.schema} && table == r.name
213
- }.flatMap {_.columns.map {showSqlColumn(_)}}.join("\n")
214
- [SqlSuggestionRegular(alias, schema.map {_ + "."}.else {""} + table, tableText)]
215
- | SqlTable(None, schema, table) =>
216
- data.relations.filter {r => schema.all {_ == r.schema} && table == r.name}.flatMap {r =>
217
- r.columns.map {c =>
218
- let foreignKeys = if(r.kind == "v") {
219
- r.simpleView.flatMap {v => v.schema.map {showSqlForeignKeys(_, v.table, c.name, data)}}.else {""}
220
- } else {showSqlForeignKeys(r.schema, r.name, c.name, data)}
221
- SqlSuggestionRegular(c.name, showSqlColumnType(c), showSqlColumn(c) + foreignKeys)
222
- }
223
- }
224
- | _ =>
225
- []
226
- }.addAll(data.functions.filter {f => data.searchPathSchemas.any {_ == f.schema}}.map {f =>
227
- SqlSuggestionFunction(f.name, "(" + f.argumentTypes.join(", ") + ") " + f.returnType, documentSqlFunction(f))
228
- })
229
- }
230
-
231
- sqlSchemaSuggestions(data: SqlData): List[SqlSuggestion] {
232
- data.relations.map {r => Pair(r.schema, r)}.group().toList().map {| Pair(schema, rs) =>
233
- let ordered = rs.sortBy {r =>
234
- let kindName = r.kindName()
235
- if(kindName.contains("table")) {1} elseIf {kindName.contains("view")} {2} elseIf {kindName.contains("index")} {3} else {4}
236
- }
237
- let tables = ordered.count {r => r.kindName().contains("table")}
238
- let text = if(tables == 1) {tables + " table"} else {tables + " tables"}
239
- let documentation = ordered.map {r => r.kindName() + " " + Sql.quote(r.name, True)}.join("\n")
240
- let functionCount = data.functions.count {_.schema == schema}
241
- let functions = if(functionCount == 1) {functionCount + " function"} else {functionCount + " functions"}
242
- SqlSuggestionRegular(schema, text, documentation + "\n-- and " + functions)
243
- }
244
- }
245
-
246
- sqlJoinSuggestions(
247
- scope: SqlCompletionScope
248
- data: SqlData
249
- searchPathSchemas: Set[String]
250
- ): List[SqlSuggestion] {
251
- function showJoin(alias: Option[String], key: SqlForeignKey): SqlSuggestion {
252
- let schemaPrefix = scope.beforeDot.isEmpty() && !searchPathSchemas.contains(key.foreignSchema)
253
- let newAlias = alias.flatMap {_ => key.foreignName.first()}.map {_.toString().lower()}
254
- let snippet =
255
- if(!schemaPrefix) {""} else {Sql.quote(key.foreignSchema) + "."} +
256
- Sql.quote(key.foreignName) + newAlias.map {" ${1:" + _ + "}"}.else {""} +
257
- " on " + key.columns.map {c =>
258
- newAlias.map {"${1:" + _ + "}."}.else {""} + Sql.quote(c.second) +
259
- " = " + alias.map {Sql.quote(_) + "."}.else {""} + Sql.quote(c.first)
260
- }.join(" and ")
261
- let label = key.foreignName + " on " + key.columns.map {c =>
262
- c.second + " = " + alias.map {_ + "."}.else {""} + c.first
263
- }.join(" and ")
264
- SqlSuggestionJoin(label, key.foreignSchema, snippet)
265
- }
266
- let symbols = scope.symbols.collect {
267
- | SqlTable(alias, schema, name) =>
268
- data.relations.find {r => schema.all {_ == r.schema} && r.name == name}.flatMap {r =>
269
- if(r.kind == "v") {
270
- r.simpleView.flatMap {v => v.schema.map {Pair(Pair(_, v.table), alias)}}
271
- } else {
272
- Some(Pair(Pair(r.schema, name), alias))
273
- }
274
- }
275
- | _ => None
276
- }.toMap()
277
- let views = data.relations.collect {r => r.simpleView.flatMap {v => v.schema.map {
278
- Pair(Pair(_, v.table), r)
279
- }}}.toMap()
280
- data.foreignKeys.flatMap {k =>
281
- symbols.get(Pair(k.schema, k.name)).filter {_ =>
282
- scope.beforeDot.all {_ == k.foreignSchema}
283
- }.toList().flatMap {alias =>
284
- [...views.get(Pair(k.foreignSchema, k.foreignName)).map {r =>
285
- showJoin(alias, k.SqlForeignKey(foreignSchema = r.schema, foreignName = r.name))
286
- }.toList(), showJoin(alias, k)]
287
- }.addAll(symbols.get(Pair(k.foreignSchema, k.foreignName)).filter {_ =>
288
- scope.beforeDot.all {_ == k.schema}
289
- }.toList().flatMap {alias =>
290
- [...views.get(Pair(k.schema, k.name)).map {r =>
291
- showJoin(alias, k.SqlForeignKey(schema = r.schema, name = r.name).swap())
292
- }.toList(), showJoin(alias, k.swap())]
293
- })
294
- }
295
- }