Skip to content

Commit e12c0b1

Browse files
ajitpratap0Ajit Pratap Singhclaude
authored
refactor(parser): deprecate token shims, collapse duplicate functions (#322) (#416)
* refactor(parser): deprecate backward-compat shims, collapse duplicate functions - Deprecate Parse([]token.Token) with migration note to ParseFromModelTokens - Collapse ParseFromModelTokensWithPositions to delegate to ParseFromModelTokens - Deprecate ConversionResult.PositionMapping (always nil) Part of #322 cleanup — unification was completed in preprocess.go rewrite. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(lint): update callers of deprecated parser shims - linter.go: use ParseFromModelTokens instead of deprecated ParseFromModelTokensWithPositions - distinct_on_example.go: nolint staticcheck for intentional backward-compat demo Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(examples): replace deprecated parser API with gosqlx.Parse - Refactor distinct_on_example.go to use gosqlx.Parse(sql) instead of the deprecated p.Parse([]token.Token) API; removes manual token-slice construction and the now-unnecessary token/models/parser imports - Fix positions_test.go to call ParseFromModelTokens instead of the deprecated ParseFromModelTokensWithPositions Eliminates the last two SA1019 violations caught by standalone staticcheck in CI, unblocking PR #416. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Ajit Pratap Singh <ajitpratapsingh@Ajits-Mac-mini-2655.local> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent e664751 commit e12c0b1

File tree

4 files changed

+29
-78
lines changed

4 files changed

+29
-78
lines changed

examples/distinct_on_example.go

Lines changed: 14 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -19,97 +19,43 @@ import (
1919
"fmt"
2020
"log"
2121

22-
"github.com/ajitpratap0/GoSQLX/pkg/models"
22+
"github.com/ajitpratap0/GoSQLX/pkg/gosqlx"
2323
"github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
24-
"github.com/ajitpratap0/GoSQLX/pkg/sql/parser"
25-
"github.com/ajitpratap0/GoSQLX/pkg/sql/token"
2624
)
2725

2826
func main() {
2927
fmt.Println("PostgreSQL DISTINCT ON Clause Example")
3028
fmt.Println("=====================================")
3129

3230
// Example 1: Basic DISTINCT ON with single column
33-
example1 := []token.Token{
34-
{Type: models.TokenTypeSelect, Literal: "SELECT"},
35-
{Type: models.TokenTypeDistinct, Literal: "DISTINCT"},
36-
{Type: models.TokenTypeOn, Literal: "ON"},
37-
{Type: models.TokenTypeLParen, Literal: "("},
38-
{Type: models.TokenTypeIdentifier, Literal: "dept_id"},
39-
{Type: models.TokenTypeRParen, Literal: ")"},
40-
{Type: models.TokenTypeIdentifier, Literal: "dept_id"},
41-
{Type: models.TokenTypeComma, Literal: ","},
42-
{Type: models.TokenTypeIdentifier, Literal: "name"},
43-
{Type: models.TokenTypeComma, Literal: ","},
44-
{Type: models.TokenTypeIdentifier, Literal: "salary"},
45-
{Type: models.TokenTypeFrom, Literal: "FROM"},
46-
{Type: models.TokenTypeIdentifier, Literal: "employees"},
47-
{Type: models.TokenTypeOrder, Literal: "ORDER"},
48-
{Type: models.TokenTypeBy, Literal: "BY"},
49-
{Type: models.TokenTypeIdentifier, Literal: "dept_id"},
50-
{Type: models.TokenTypeComma, Literal: ","},
51-
{Type: models.TokenTypeIdentifier, Literal: "salary"},
52-
{Type: models.TokenTypeDesc, Literal: "DESC"},
53-
}
54-
31+
sql1 := "SELECT DISTINCT ON (dept_id) dept_id, name, salary FROM employees ORDER BY dept_id, salary DESC"
5532
fmt.Println("Example 1: Basic DISTINCT ON")
56-
fmt.Println("SQL: SELECT DISTINCT ON (dept_id) dept_id, name, salary FROM employees ORDER BY dept_id, salary DESC")
57-
parseAndDisplay(example1)
33+
fmt.Printf("SQL: %s\n", sql1)
34+
parseAndDisplay(sql1)
5835

5936
// Example 2: DISTINCT ON with multiple columns
60-
example2 := []token.Token{
61-
{Type: models.TokenTypeSelect, Literal: "SELECT"},
62-
{Type: models.TokenTypeDistinct, Literal: "DISTINCT"},
63-
{Type: models.TokenTypeOn, Literal: "ON"},
64-
{Type: models.TokenTypeLParen, Literal: "("},
65-
{Type: models.TokenTypeIdentifier, Literal: "user_id"},
66-
{Type: models.TokenTypeComma, Literal: ","},
67-
{Type: models.TokenTypeIdentifier, Literal: "category"},
68-
{Type: models.TokenTypeRParen, Literal: ")"},
69-
{Type: models.TokenTypeAsterisk, Literal: "*"},
70-
{Type: models.TokenTypeFrom, Literal: "FROM"},
71-
{Type: models.TokenTypeIdentifier, Literal: "purchases"},
72-
{Type: models.TokenTypeOrder, Literal: "ORDER"},
73-
{Type: models.TokenTypeBy, Literal: "BY"},
74-
{Type: models.TokenTypeIdentifier, Literal: "user_id"},
75-
{Type: models.TokenTypeComma, Literal: ","},
76-
{Type: models.TokenTypeIdentifier, Literal: "category"},
77-
}
78-
37+
sql2 := "SELECT DISTINCT ON (user_id, category) * FROM purchases ORDER BY user_id, category"
7938
fmt.Println("\nExample 2: DISTINCT ON with Multiple Columns")
80-
fmt.Println("SQL: SELECT DISTINCT ON (user_id, category) * FROM purchases ORDER BY user_id, category")
81-
parseAndDisplay(example2)
39+
fmt.Printf("SQL: %s\n", sql2)
40+
parseAndDisplay(sql2)
8241

8342
// Example 3: Regular DISTINCT (should still work)
84-
example3 := []token.Token{
85-
{Type: models.TokenTypeSelect, Literal: "SELECT"},
86-
{Type: models.TokenTypeDistinct, Literal: "DISTINCT"},
87-
{Type: models.TokenTypeIdentifier, Literal: "country"},
88-
{Type: models.TokenTypeFrom, Literal: "FROM"},
89-
{Type: models.TokenTypeIdentifier, Literal: "customers"},
90-
}
91-
43+
sql3 := "SELECT DISTINCT country FROM customers"
9244
fmt.Println("\nExample 3: Regular DISTINCT (backward compatibility)")
93-
fmt.Println("SQL: SELECT DISTINCT country FROM customers")
94-
parseAndDisplay(example3)
45+
fmt.Printf("SQL: %s\n", sql3)
46+
parseAndDisplay(sql3)
9547
}
9648

97-
func parseAndDisplay(tokens []token.Token) {
98-
p := parser.NewParser()
99-
100-
astObj, err := p.Parse(tokens)
49+
func parseAndDisplay(sql string) {
50+
astObj, err := gosqlx.Parse(sql)
10151
if err != nil {
102-
p.Release()
10352
log.Fatalf("Parse error: %v", err)
10453
}
10554

106-
displayAST(p, astObj)
55+
displayAST(astObj)
10756
}
10857

109-
func displayAST(p *parser.Parser, astObj *ast.AST) {
110-
defer p.Release()
111-
defer ast.ReleaseAST(astObj)
112-
58+
func displayAST(astObj *ast.AST) {
11359
if len(astObj.Statements) == 0 {
11460
fmt.Println("No statements parsed")
11561
return

pkg/linter/linter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ func (l *Linter) LintString(sql string, filename string) FileResult {
164164
// Attempt parsing with position tracking (best effort - some rules are token-only)
165165
p := parser.NewParser()
166166
defer p.Release()
167-
astObj, parseErr := p.ParseFromModelTokensWithPositions(tokens)
167+
astObj, parseErr := p.ParseFromModelTokens(tokens)
168168
ctx.WithAST(astObj, parseErr)
169169
}
170170

pkg/sql/ast/positions_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func parseWithPositions(t *testing.T, sql string) *ast.AST {
4444
p := parser.GetParser()
4545
defer parser.PutParser(p)
4646

47-
result, err := p.ParseFromModelTokensWithPositions(tokens)
47+
result, err := p.ParseFromModelTokens(tokens)
4848
if err != nil {
4949
t.Fatalf("parse failed: %v", err)
5050
}

pkg/sql/parser/parser.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ import (
3434
// After the token-type unification (#322) the Tokens field holds
3535
// []models.TokenWithSpan directly; span information is no longer stripped.
3636
type ConversionResult struct {
37-
Tokens []models.TokenWithSpan
38-
PositionMapping []TokenPosition // Deprecated: always nil - positions are now embedded in TokenWithSpan.Start/End fields
37+
Tokens []models.TokenWithSpan
38+
// Deprecated: PositionMapping is always nil. Position information is now embedded
39+
// directly in models.TokenWithSpan.Start and .End fields.
40+
PositionMapping []TokenPosition
3941
}
4042

4143
// TokenPosition maps a parser token back to its original source position.
@@ -232,6 +234,10 @@ type Parser struct {
232234
dialect string // SQL dialect for dialect-aware parsing (default: "postgresql")
233235
}
234236

237+
// Deprecated: Parse is provided for backward compatibility only. Use ParseFromModelTokens
238+
// with a []models.TokenWithSpan slice from the tokenizer instead. This shim wraps each
239+
// token.Token into a zero-span models.TokenWithSpan and has no position information.
240+
//
235241
// Parse parses a slice of token.Token into an AST.
236242
//
237243
// This API is preserved for backward compatibility. Prefer ParseFromModelTokens
@@ -323,13 +329,12 @@ func (p *Parser) ParseFromModelTokens(tokens []models.TokenWithSpan) (*ast.AST,
323329
return p.parseTokens(preprocessed)
324330
}
325331

326-
// ParseFromModelTokensWithPositions parses tokenizer output with position tracking
327-
// for enhanced error reporting. Since models.TokenWithSpan already carries span
328-
// information, this is now equivalent to ParseFromModelTokens but also populates
329-
// the ConversionResult position mapping for callers that need it.
332+
// ParseFromModelTokensWithPositions is identical to ParseFromModelTokens.
333+
// Position information is embedded in every models.TokenWithSpan.
334+
//
335+
// Deprecated: Use ParseFromModelTokens directly.
330336
func (p *Parser) ParseFromModelTokensWithPositions(tokens []models.TokenWithSpan) (*ast.AST, error) {
331-
preprocessed := preprocessTokens(tokens)
332-
return p.parseTokens(preprocessed)
337+
return p.ParseFromModelTokens(tokens)
333338
}
334339

335340
// ParseContextFromModelTokens parses tokenizer output with context support for cancellation.

0 commit comments

Comments
 (0)