-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdialect.go
More file actions
183 lines (143 loc) · 5.45 KB
/
dialect.go
File metadata and controls
183 lines (143 loc) · 5.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package scaf
// Dialect represents a query language (cypher, sql).
// It provides static analysis of queries without requiring a database connection.
type Dialect interface {
// Name returns the dialect identifier (e.g., "cypher", "sql").
Name() string
// Analyze extracts metadata from a query string.
Analyze(query string) (*QueryMetadata, error)
}
var dialects = make(map[string]Dialect)
// RegisterDialect registers a dialect instance by name.
func RegisterDialect(d Dialect) {
dialects[d.Name()] = d
}
// GetDialect returns a dialect by name.
// Returns nil if no dialect is registered with that name.
func GetDialect(name string) Dialect { //nolint:ireturn
return dialects[name]
}
// RegisteredDialects returns the names of all registered dialects.
func RegisteredDialects() []string {
names := make([]string, 0, len(dialects))
for name := range dialects {
names = append(names, name)
}
return names
}
// QueryAnalyzer provides static analysis of queries for IDE features.
// This interface exists for backwards compatibility with LSP and language packages.
type QueryAnalyzer interface {
// AnalyzeQuery extracts metadata from a query string.
AnalyzeQuery(query string) (*QueryMetadata, error)
}
// QueryAnalyzerFactory creates a QueryAnalyzer for a dialect.
type QueryAnalyzerFactory func() QueryAnalyzer
var analyzers = make(map[string]QueryAnalyzerFactory)
// RegisterAnalyzer registers a query analyzer factory by dialect name.
// Dialects should call this in their init() function.
func RegisterAnalyzer(dialectName string, factory QueryAnalyzerFactory) {
analyzers[dialectName] = factory
}
// GetAnalyzer returns a QueryAnalyzer for the given dialect name.
// Returns nil if no analyzer is registered for that dialect.
// Prefers explicitly registered analyzers over dialect adapters,
// as they may implement additional interfaces like SchemaAwareAnalyzer.
func GetAnalyzer(dialectName string) QueryAnalyzer { //nolint:ireturn
// First check explicit analyzer registry (may implement more interfaces)
if factory, ok := analyzers[dialectName]; ok {
return factory()
}
// Fall back to dialect adapter
if d := GetDialect(dialectName); d != nil {
return &dialectAnalyzerAdapter{d}
}
return nil
}
// dialectAnalyzerAdapter adapts a Dialect to the QueryAnalyzer interface.
type dialectAnalyzerAdapter struct {
dialect Dialect
}
func (a *dialectAnalyzerAdapter) AnalyzeQuery(query string) (*QueryMetadata, error) {
return a.dialect.Analyze(query)
}
// RegisteredAnalyzers returns the names of all registered analyzers.
func RegisteredAnalyzers() []string {
names := make([]string, 0, len(analyzers))
for name := range analyzers {
names = append(names, name)
}
return names
}
// MarkdownLanguage returns the markdown language identifier for a dialect.
// Used for syntax highlighting in IDE hover/completion documentation.
func MarkdownLanguage(dialectName string) string {
// Common dialect name to markdown language mapping
switch dialectName {
case DialectCypher, DatabaseNeo4j:
return DialectCypher
case DatabasePostgres, "postgresql", DatabaseMySQL, DatabaseSQLite, DialectSQL:
return DialectSQL
default:
return dialectName
}
}
// QueryMetadata holds extracted information about a query.
type QueryMetadata struct {
// Parameters are the $-prefixed parameters used in the query.
Parameters []ParameterInfo
// Returns are the fields returned by the query.
Returns []ReturnInfo
// Bindings maps variable names to their bound types from pattern matching.
// E.g., for "MATCH (u:User)", Bindings["u"] = ["User"].
// Used for hover information when the variable itself isn't returned.
Bindings map[string][]string
// ReturnsOne indicates the query returns at most one row.
// When false (default), the query may return multiple rows (slice).
// Set to true when the query filters on a unique field with equality,
// uses LIMIT 1, or is otherwise guaranteed to return a single row.
ReturnsOne bool
}
// ParameterInfo describes a query parameter.
type ParameterInfo struct {
// Name is the parameter name (without $ prefix).
Name string
// Type is the inferred type, if known.
Type *Type
// Position is the character offset in the query.
Position int
// Line is the 1-indexed line number in the query.
Line int
// Column is the 1-indexed column in the query.
Column int
// Length is the length of the parameter reference in characters.
Length int
// Count is how many times this parameter appears.
Count int
}
// ReturnInfo describes a returned field.
type ReturnInfo struct {
// Name is the field name or alias.
Name string
// Type is the inferred type, if known.
Type *Type
// Expression is the original expression text.
Expression string
// Alias is the explicit alias if AS keyword was used, empty otherwise.
// When Alias is set, the database column name is Alias.
// When Alias is empty, the database column name is Expression.
Alias string
// IsAggregate indicates this is an aggregate function result.
IsAggregate bool
// IsWildcard indicates this is a wildcard (*) return.
IsWildcard bool
// Required indicates whether the field is required (non-nullable) in the schema.
// When false, code generators should use pointer types to represent nil values.
Required bool
// Line is the 1-indexed line number in the query where this return field appears.
Line int
// Column is the 1-indexed column in the query where this return field starts.
Column int
// Length is the length of the return field expression in characters.
Length int
}