Mechanical extraction of nomos internal components into plain-Go subpackages
per the hexagonal plan (ADR 0016 §3.1 rule 3):
turngate/ — per-session turn serialization (plan 2026-08-03 F1)
retrycap/ — per-turn run retry cap (maxRunRetries=3)
messagequeue/ — operator-message queue for busy-turn re-entry (F2)
assent/ — chat-assent detection (isAssent, isTypedConfirmation,
ExtractPendingApprovals), decoupled from agent via
[]string input instead of persistedCall
session/ — store (chat sessions, plan execution, DB persistence),
migration runner + local emitEvent to break adapter
dependency
internal/migrate/ — shared migration runner extracted from postgres pool,
used by both the oikos postgres adapter and session tests.
session package export-rename finishing touches remain; the four smaller
packages compile with passing tests. Depguard rules and ADR-0016 leaf-note
update deferred to a followup. VERSION 0.35.1.
94 lines
2.2 KiB
Go
94 lines
2.2 KiB
Go
package migrate
|
|
|
|
import "strings"
|
|
|
|
// splitSQL splits a SQL string into individual statements.
|
|
// Handles $$ ... $$ dollar-quoted blocks, $tag$ ... $tag$ tagged quotes,
|
|
// -- line comments, /* ... */ block comments, and '...' string literals
|
|
// so that semicolons inside any of these constructs are not treated as
|
|
// statement boundaries.
|
|
func SplitSQL(sql string) []string {
|
|
var statements []string
|
|
var current strings.Builder
|
|
inDollarQuote := false
|
|
dollarTag := ""
|
|
|
|
i := 0
|
|
for i < len(sql) {
|
|
// Handle line comments (-- to end of line)
|
|
if !inDollarQuote && i+1 < len(sql) && sql[i] == '-' && sql[i+1] == '-' {
|
|
for i < len(sql) && sql[i] != '\n' {
|
|
current.WriteByte(sql[i])
|
|
i++
|
|
}
|
|
continue
|
|
}
|
|
|
|
// Handle block comments (/* ... */)
|
|
if !inDollarQuote && i+1 < len(sql) && sql[i] == '/' && sql[i+1] == '*' {
|
|
end := strings.Index(sql[i+2:], "*/")
|
|
if end >= 0 {
|
|
current.WriteString(sql[i : i+end+4])
|
|
i += end + 4
|
|
continue
|
|
}
|
|
}
|
|
|
|
// Handle single-quoted string literals ('...')
|
|
if !inDollarQuote && sql[i] == '\'' {
|
|
j := i + 1
|
|
for j < len(sql) {
|
|
if sql[j] == '\'' {
|
|
if j+1 < len(sql) && sql[j+1] == '\'' {
|
|
j += 2 // skip doubled quote ''
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
j++
|
|
}
|
|
current.WriteString(sql[i : j+1])
|
|
i = j + 1
|
|
continue
|
|
}
|
|
|
|
// Check for dollar-quote start/end
|
|
if !inDollarQuote && sql[i] == '$' {
|
|
j := i + 1
|
|
for j < len(sql) && (sql[j] == '_' || (sql[j] >= 'a' && sql[j] <= 'z') || (sql[j] >= 'A' && sql[j] <= 'Z') || (sql[j] >= '0' && sql[j] <= '9')) {
|
|
j++
|
|
}
|
|
if j < len(sql) && sql[j] == '$' {
|
|
dollarTag = sql[i : j+1]
|
|
current.WriteString(dollarTag)
|
|
inDollarQuote = true
|
|
i = j + 1
|
|
continue
|
|
}
|
|
}
|
|
if inDollarQuote && strings.HasPrefix(sql[i:], dollarTag) {
|
|
current.WriteString(dollarTag)
|
|
i += len(dollarTag)
|
|
inDollarQuote = false
|
|
dollarTag = ""
|
|
continue
|
|
}
|
|
|
|
if !inDollarQuote && sql[i] == ';' {
|
|
statements = append(statements, current.String())
|
|
current.Reset()
|
|
i++
|
|
continue
|
|
}
|
|
|
|
current.WriteByte(sql[i])
|
|
i++
|
|
}
|
|
|
|
if strings.TrimSpace(current.String()) != "" {
|
|
statements = append(statements, current.String())
|
|
}
|
|
|
|
return statements
|
|
}
|