firefly-compiler 0.6.20 → 0.6.24

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.
Files changed (36) hide show
  1. package/.vscode/settings.json +1 -1
  2. package/compiler/Inference.ff +17 -1
  3. package/compiler/LspHook.ff +15 -5
  4. package/core/BuildSystem.ff +1 -1
  5. package/core/Ordering.ff +1 -1
  6. package/experimental/inceptron/Run.ff +47 -0
  7. package/experimental/mattis/Tree.ff +44 -0
  8. package/experimental/tests/TestListOrdering.ff +7 -0
  9. package/experimental/tests/TestOrder.ff +4 -0
  10. package/experimental/tests/TestSql.ff +18 -0
  11. package/lsp/.firefly/package.ff +1 -0
  12. package/lsp/CompletionHandler.ff +112 -6
  13. package/lsp/Handler.ff +205 -7
  14. package/lsp/LanguageServer.ff +5 -0
  15. package/lsp/SemanticTokenTypes.ff +62 -0
  16. package/lsp/Sql.ff +1395 -0
  17. package/lsp/SqlStatement.ff +34 -0
  18. package/lsp/SqlSuggestion.ff +295 -0
  19. package/output/js/ff/compiler/Builder.mjs +2 -2
  20. package/output/js/ff/compiler/Builder.mjs.map +1 -1
  21. package/output/js/ff/compiler/Dependencies.mjs +2 -2
  22. package/output/js/ff/compiler/Dependencies.mjs.map +1 -1
  23. package/output/js/ff/compiler/Inference.mjs +36 -16
  24. package/output/js/ff/compiler/Inference.mjs.map +4 -2
  25. package/output/js/ff/compiler/LspHook.mjs +10 -10
  26. package/output/js/ff/compiler/LspHook.mjs.map +4 -3
  27. package/output/js/ff/compiler/Main.mjs +4 -4
  28. package/output/js/ff/compiler/Main.mjs.map +1 -1
  29. package/output/js/ff/core/BuildSystem.mjs +2 -2
  30. package/output/js/ff/core/BuildSystem.mjs.map +3 -2
  31. package/output/js/ff/core/Ordering.mjs +2 -2
  32. package/output/js/ff/core/Ordering.mjs.map +1 -1
  33. package/package.json +1 -1
  34. package/postgresql/Pg.ff +49 -26
  35. package/vscode/client/src/extension.ts +5 -0
  36. package/vscode/package.json +7 -1
package/postgresql/Pg.ff CHANGED
@@ -1,5 +1,5 @@
1
1
  capability PgPool(jsValue: JsValue)
2
- capability PgConnection(jsValue: JsValue)
2
+ capability PgConnection(mutable jsValue: Option[JsValue], mutable internalInitializer: Option[Pair[PgPool, String]])
3
3
  capability PgRow(jsValue: JsValue) // TODO: Should be a sync class, make deriver not touch those
4
4
  capability PgStatement(sql: String, parameters: Map[String, JsValue], connection: Option[PgConnection])
5
5
  data PgLevel {
@@ -61,13 +61,14 @@ internalTypeParsers(pg: JsValue) {
61
61
  types->setTypeParser(types->builtins->TIMESTAMPTZ, Js->{v =>
62
62
  Date(Js->Temporal->Instant->from(v)->toZonedDateTimeISO("UTC"))
63
63
  })
64
+ types->setTypeParser(1003, types->getTypeParser(1009)) // handle name[]
64
65
  }
65
66
 
66
67
  extend self: PgPool {
67
68
 
68
69
  connect(): PgConnection {
69
70
  Js.throwIfCancelled()
70
- PgConnection(Js.await(self.jsValue->connect()))
71
+ PgConnection(Some(Js.await(self.jsValue->connect())), None)
71
72
  }
72
73
 
73
74
  close(): Unit {
@@ -86,22 +87,33 @@ extend self: PgPool {
86
87
  self.jsValue->waitingCount.grabInt()
87
88
  }
88
89
 
89
- transaction[T](body: PgConnection => T, level: PgLevel = PgReadCommitted): T {
90
- let connection = self.connect()
90
+ transaction[T](
91
+ body: PgConnection => T
92
+ level: PgLevel = PgReadCommitted
93
+ readOnly: Bool = False
94
+ deferrable: Bool = False
95
+ eager: Bool = False
96
+ ): T {
97
+ let connection = PgConnection(None, None)
91
98
  mutable done = False
92
99
  try {
93
- connection.statement("begin").run()
94
- level.{
95
- | PgReadCommitted => 0 // Default level in PostgreSQL
96
- | PgRepeatableRead => connection.statement("set transaction isolation level repeatable read").run()
97
- | PgSerializable => connection.statement("set transaction isolation level serializable").run()
98
- }
100
+ let transactionMode = [
101
+ Some(level.{
102
+ | PgReadCommitted => " isolation level read committed"
103
+ | PgRepeatableRead => " isolation level repeatable read"
104
+ | PgSerializable => " isolation level serializable"
105
+ })
106
+ if(readOnly) {Some(" read only")} else {Some(" read write")}
107
+ if(deferrable) {" deferrable"}
108
+ ].collect {_}.join(",")
109
+ connection.internalInitializer = Some(Pair(self, "begin" + transactionMode))
110
+ if(eager) {internalEnsureConnected(connection)}
99
111
  let result = body(connection)
100
112
  done = True
101
- connection.statement("commit").run()
113
+ if(!connection.jsValue.isEmpty()) {connection.statement("commit").run()}
102
114
  result
103
115
  } finally {
104
- if(!done) {connection.statement("rollback").run()}
116
+ if(!done && !connection.jsValue.isEmpty()) {connection.statement("rollback").run()}
105
117
  connection.release()
106
118
  }
107
119
  }
@@ -112,10 +124,12 @@ extend self: PgConnection {
112
124
 
113
125
  release(): Unit {
114
126
  if(Js.cancelled()) {
115
- self.jsValue->release(True)
127
+ self.jsValue.each {_->release(True)}
116
128
  } else {
117
- self.jsValue->release()
129
+ self.jsValue.each {_->release()}
118
130
  }
131
+ self.jsValue = None
132
+ self.internalInitializer = None
119
133
  }
120
134
 
121
135
  statement(sql: String): PgStatement {
@@ -350,11 +364,21 @@ internalGet[T](row: PgRow, name: String, lower: Bool, body: JsValue => T): Optio
350
364
  if(!value.isNull()) {Some(body(value))} else {None}
351
365
  }
352
366
 
367
+ internalEnsureConnected(connection: PgConnection) {
368
+ connection.internalInitializer.each {| Pair(pool, start) =>
369
+ connection.internalInitializer = None
370
+ connection.jsValue = Some(Js.await(pool.jsValue->connect()))
371
+ connection.jsValue.grab()->query(start)
372
+ }
373
+ }
374
+
353
375
  internalRunStatement(statement: PgStatement, body: Option[PgRow => Bool]): Int {
354
376
  Js.throwIfCancelled()
355
377
  let pair = internalParseParameters(statement.sql)
356
378
  let parameters = internalCheckParameters(pair.second, statement.parameters)
357
- let result = Js.await(statement.connection.grab().jsValue->query(pair.first, parameters))
379
+ let connection = statement.connection.grab()
380
+ internalEnsureConnected(connection)
381
+ let result = Js.await(connection.jsValue.grab()->query(pair.first, parameters))
358
382
  body.{
359
383
  | None =>
360
384
  if(!result.get("rowCount").isNullOrUndefined()) {result.get("rowCount").grabInt()} else {-1}
@@ -384,6 +408,7 @@ internalBatchStatements(
384
408
  }
385
409
  Pair(sql, (newSql = pair.first, parameterNames = pair.second, prepared = prepared))
386
410
  }
411
+ if(!statements.isEmpty()) {internalEnsureConnected(connection)}
387
412
  let promises = statements.map {statement =>
388
413
  Js.throwIfCancelled()
389
414
  let record = sqlCache.grab(statement.sql)
@@ -391,7 +416,7 @@ internalBatchStatements(
391
416
  let query = Js.object()
392
417
  .with("text", record.newSql)
393
418
  .with("values", parameters)
394
- connection.jsValue->query(record.prepared.map {query.with("name", _)}.else {query})
419
+ connection.jsValue.grab()->query(record.prepared.map {query.with("name", _)}.else {query})
395
420
  }
396
421
  let results = promises.map {promise =>
397
422
  Js.throwIfCancelled()
@@ -431,7 +456,7 @@ internalParseParameters(statementSql: String): Pair[String, List[String]] {
431
456
  mutable last = 0
432
457
  mutable sql = ""
433
458
  while {i < statementSql.size()} {
434
- if(statementSql.grab(i) == '$') {
459
+ if(statementSql.grab(i) == '$' && i + 1 < statementSql.size() && statementSql.grab(i + 1).isAsciiLetter()) {
435
460
  sql = sql + statementSql.slice(last, i)
436
461
  i += 1
437
462
  last = i
@@ -442,16 +467,14 @@ internalParseParameters(statementSql: String): Pair[String, List[String]] {
442
467
  i += 1
443
468
  }
444
469
  let name = statementSql.slice(last, i)
445
- if(name != "") {
446
- let index = parameterIndexes.get(name).else {
447
- let newIndex = parameterIndexes.size() + 1
448
- parameterIndexes = parameterIndexes.add(name, newIndex)
449
- parameters = [name, ...parameters]
450
- newIndex
451
- }
452
- sql = sql + "$" + index
453
- last = i
470
+ let index = parameterIndexes.get(name).else {
471
+ let newIndex = parameterIndexes.size() + 1
472
+ parameterIndexes = parameterIndexes.add(name, newIndex)
473
+ parameters = [name, ...parameters]
474
+ newIndex
454
475
  }
476
+ sql = sql + "$" + index
477
+ last = i
455
478
  }
456
479
  } else {
457
480
  i += 1
@@ -67,8 +67,13 @@ export function activate(context: vscode.ExtensionContext) {
67
67
  debug: runOrDebug
68
68
  };
69
69
 
70
+ const sqlConnectionString = vscode.workspace.getConfiguration('firefly').get<string>('sqlConnectionString', '');
71
+
70
72
  const clientOptions: LanguageClientOptions = {
71
73
  documentSelector: [{ scheme: 'file', language: 'firefly' }],
74
+ initializationOptions: {
75
+ sqlConnectionString
76
+ },
72
77
  synchronize: {
73
78
  // It would be more portable to send a client/registerCapability from the server for this
74
79
  fileEvents: vscode.workspace.createFileSystemWatcher('**/*.ff')
@@ -4,7 +4,7 @@
4
4
  "description": "Firefly language support",
5
5
  "author": "Firefly team",
6
6
  "license": "MIT",
7
- "version": "0.6.20",
7
+ "version": "0.6.24",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "https://github.com/Ahnfelt/firefly-boot"
@@ -133,6 +133,12 @@
133
133
  "type": "string",
134
134
  "default": "charts.blue",
135
135
  "description": "The color used for Firefly folder decorations."
136
+ },
137
+ "firefly.sqlConnectionString": {
138
+ "type": "string",
139
+ "default": "",
140
+ "scope": "resource",
141
+ "description": "PostgreSQL connection string for SQL diagnostics and completion (e.g. postgres://user:pass@localhost:5432/mydb)."
136
142
  }
137
143
  }
138
144
  },