Skip to content

Commit 2599040

Browse files
feat: add support for collection information in SQL to MongoDB conversion and enhance documentation
1 parent d425c8d commit 2599040

9 files changed

Lines changed: 342 additions & 28 deletions

File tree

README.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,4 +331,55 @@ zero-sql/
331331
└── README.md # This file
332332
```
333333

334-
The converter package is the heart of the application, handling the conversion from SQL Abstract Syntax Trees (AST) to MongoDB aggregation pipelines.
334+
The converter package is the heart of the application, handling the conversion from SQL Abstract Syntax Trees (AST) to MongoDB aggregation pipelines.
335+
336+
## Usage
337+
338+
```bash
339+
# Basic usage
340+
zero-sql "SELECT name, age FROM users WHERE age > 18"
341+
342+
# With collection information (helps avoid MongoDB namespace errors)
343+
zero-sql --include-collection "SELECT name, age FROM users WHERE age > 18 LIMIT 5"
344+
345+
# Pretty print JSON output
346+
zero-sql --pretty "SELECT * FROM products"
347+
348+
# Verbose mode
349+
zero-sql --verbose "SELECT name FROM users"
350+
```
351+
352+
## Troubleshooting
353+
354+
### MongoDB Aggregation Namespace Error
355+
356+
If you encounter an error like `(InvalidNamespace) {aggregate: 1} is not valid for '$limit'; a collection is required`, this means that when executing the generated aggregation pipeline in MongoDB, the collection name is not being specified correctly.
357+
358+
**Solution**: Use the `--include-collection` flag to get both the collection name and the pipeline:
359+
360+
```bash
361+
# This outputs collection name and pipeline
362+
zero-sql --include-collection "SELECT name FROM users LIMIT 10"
363+
```
364+
365+
**Output**:
366+
```json
367+
{
368+
"collection": "users",
369+
"pipeline": [
370+
{
371+
"$limit": 10
372+
}
373+
]
374+
}
375+
```
376+
377+
Then, in your MongoDB client/driver, use the collection name when executing the aggregation:
378+
379+
```javascript
380+
// MongoDB shell
381+
db.users.aggregate([{"$limit": 10}])
382+
383+
// Node.js with MongoDB driver
384+
await db.collection("users").aggregate([{"$limit": 10}]).toArray()
385+
```

RELEASE_NOTES_v0.1.3.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Zero-SQL v0.1.3 Release Notes
2+
3+
## 🎉 New Features
4+
5+
### MongoDB Collection Information Support
6+
- **Collection Extraction**: New `--include-collection` CLI flag that outputs both collection name and aggregation pipeline
7+
- **Enhanced API**: Added `ConvertSQLToMongoWithCollection()` method to the public API
8+
- **Structured Output**: New `ConversionResult` struct containing collection name and pipeline stages
9+
- **Namespace Error Fix**: Solves MongoDB `(InvalidNamespace) {aggregate: 1} is not valid for '$limit'; a collection is required` errors
10+
11+
### CLI Enhancements
12+
- **New Flag**: `--include-collection` / `-c` flag for collection-aware output
13+
- **Better Help**: Updated help documentation with collection information examples
14+
- **Backward Compatibility**: Existing behavior unchanged when flag is not used
15+
16+
## 🔧 API Changes
17+
18+
### New Public Methods
19+
```go
20+
// New method that returns collection name and pipeline
21+
result, err := conv.ConvertSQLToMongoWithCollection(sqlQuery)
22+
fmt.Printf("Collection: %s\n", result.Collection)
23+
fmt.Printf("Pipeline: %v\n", result.Pipeline)
24+
```
25+
26+
### New Types
27+
```go
28+
// ConversionResult holds both collection name and pipeline
29+
type ConversionResult struct {
30+
Collection string `json:"collection"`
31+
Pipeline []map[string]interface{} `json:"pipeline"`
32+
}
33+
```
34+
35+
## 🚀 Usage Examples
36+
37+
### CLI Usage
38+
```bash
39+
# Traditional output (pipeline only)
40+
zero-sql "SELECT name FROM users LIMIT 10"
41+
42+
# New collection-aware output
43+
zero-sql --include-collection "SELECT name FROM users LIMIT 10"
44+
```
45+
46+
### API Usage
47+
```go
48+
import "github.com/synehq/zero-sql/pkg/zerosql"
49+
50+
conv := zerosql.New(&zerosql.Options{Verbose: false})
51+
52+
// Get collection and pipeline together
53+
result, err := conv.ConvertSQLToMongoWithCollection("SELECT * FROM users LIMIT 5")
54+
if err != nil {
55+
return err
56+
}
57+
58+
// Execute in MongoDB with proper collection
59+
// db.collection(result.Collection).aggregate(result.Pipeline)
60+
```
61+
62+
## 🐛 Bug Fixes
63+
64+
### MongoDB Namespace Errors
65+
- **Issue**: Generated pipelines caused `InvalidNamespace` errors when executed in MongoDB
66+
- **Root Cause**: MongoDB aggregation requires explicit collection specification
67+
- **Solution**: Extract collection name from SQL FROM clause and provide it alongside pipeline
68+
- **Impact**: Eliminates common MongoDB execution errors when using generated pipelines
69+
70+
## 🔄 Troubleshooting
71+
72+
### MongoDB Aggregation Errors
73+
If you encounter namespace errors like:
74+
```
75+
(InvalidNamespace) {aggregate: 1} is not valid for '$limit'; a collection is required
76+
```
77+
78+
**Solution**: Use the new `--include-collection` flag:
79+
```bash
80+
zero-sql --include-collection "SELECT name FROM users LIMIT 10"
81+
```
82+
83+
This outputs:
84+
```json
85+
{
86+
"collection": "users",
87+
"pipeline": [{"$limit": 10}]
88+
}
89+
```
90+
91+
Then execute in MongoDB:
92+
```javascript
93+
// MongoDB shell
94+
db.users.aggregate([{"$limit": 10}])
95+
96+
// Node.js with MongoDB driver
97+
await db.collection("users").aggregate([{"$limit": 10}]).toArray()
98+
```
99+
100+
## 📝 Documentation Updates
101+
102+
- **README**: Added troubleshooting section for MongoDB namespace errors
103+
- **CLI Help**: Updated examples to include new `--include-collection` flag
104+
- **Usage Guide**: Added collection-aware execution examples
105+
106+
## ⚡ Performance & Compatibility
107+
108+
- **Zero Breaking Changes**: All existing functionality remains unchanged
109+
- **Backward Compatible**: Existing scripts and integrations continue to work
110+
- **Optional Feature**: Collection information is opt-in via flag or method choice
111+
- **Same Performance**: No performance impact on existing workflows
112+
113+
---
114+
115+
**Full Changelog**: https://github.com/synehq/zero-sql/compare/v0.0.2...v0.1.3
File renamed without changes.

changelogs/RELEASE_NOTES_v0.0.2.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Zero-SQL v0.0.2 Release Notes
2+
3+
## 🎉 New Features
4+
5+
### Public API Package
6+
- **Public Converter Package**: Introduced `pkg/zerosql` package to expose converter functionality publicly
7+
- **External Integration**: The converter can now be imported and used by external Go modules
8+
- **Simplified API**: Clean and simple API with `zerosql.New()` and `zerosql.Options{}`
9+
10+
## 🔧 Breaking Changes
11+
12+
### Import Path Changes
13+
- **Old**: `github.com/synehq/zero-sql/internal/converter` (internal package)
14+
- **New**: `github.com/synehq/zero-sql/pkg/zerosql` (public package)
15+
16+
### Usage Changes
17+
```go
18+
// Before (internal package - not accessible externally)
19+
conv := converter.New(&converter.Options{
20+
Verbose: true,
21+
})
22+
23+
// After (public package)
24+
conv := zerosql.New(&zerosql.Options{
25+
Verbose: true,
26+
})
27+
```
28+
29+
## 🚀 Improvements
30+
31+
- **Better Modularity**: Clear separation between internal implementation and public API
32+
- **External Usage**: Can now be integrated into other Go projects as a dependency
33+
- **Maintained Functionality**: All existing converter features remain unchanged
34+
35+
## 📦 Installation
36+
37+
For external projects, you can now import and use zero-sql as a library:
38+
39+
```go
40+
import "github.com/synehq/zero-sql/pkg/zerosql"
41+
42+
conv := zerosql.New(&zerosql.Options{
43+
Verbose: true,
44+
})
45+
pipeline, err := conv.ConvertSQLToMongo("SELECT * FROM users WHERE age > 18")
46+
```
47+
48+
## 🔄 Migration Guide
49+
50+
If you were using the internal package (which wasn't officially supported):
51+
52+
1. Update import: `github.com/synehq/zero-sql/internal/converter``github.com/synehq/zero-sql/pkg/zerosql`
53+
2. Update constructor: `converter.New()``zerosql.New()`
54+
3. Update options: `converter.Options{}``zerosql.Options{}`
55+
56+
---
57+
58+
**Full Changelog**: https://github.com/synehq/zero-sql/compare/v0.0.1...v0.0.2

cmd/root.go

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ import (
66
"os"
77
"strings"
88

9-
"github.com/synehq/zero-sql/internal/converter"
9+
"github.com/synehq/zero-sql/pkg/zerosql"
1010

1111
"github.com/spf13/cobra"
1212
)
1313

1414
var (
15-
outputFormat string
16-
prettyPrint bool
17-
verbose bool
15+
outputFormat string
16+
prettyPrint bool
17+
verbose bool
18+
includeCollection bool
1819
)
1920

2021
// rootCmd represents the base command when called without any subcommands
@@ -39,7 +40,8 @@ Examples:
3940
zero-sql "SELECT u.name, p.title FROM users u JOIN posts p ON u.id = p.user_id WHERE u.active = true"
4041
zero-sql "SELECT u.name, p.title, c.name FROM users u JOIN posts p ON u.id = p.user_id JOIN categories c ON p.category_id = c.id"
4142
zero-sql "SELECT u.name, p.title FROM users u LEFT JOIN posts p ON u.id = p.user_id"
42-
zero-sql --format=json --pretty "SELECT COUNT(*) as total FROM orders GROUP BY status"`,
43+
zero-sql --format=json --pretty "SELECT COUNT(*) as total FROM orders GROUP BY status"
44+
zero-sql --include-collection "SELECT name FROM users LIMIT 10"`,
4345
Args: cobra.ExactArgs(1),
4446
RunE: runConvert,
4547
}
@@ -53,6 +55,7 @@ func init() {
5355
rootCmd.Flags().StringVarP(&outputFormat, "format", "f", "json", "Output format (json, bson)")
5456
rootCmd.Flags().BoolVarP(&prettyPrint, "pretty", "p", true, "Pretty print the output")
5557
rootCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Verbose output")
58+
rootCmd.Flags().BoolVarP(&includeCollection, "include-collection", "c", false, "Include collection information in the output")
5659
}
5760

5861
// runConvert is the main execution function for the convert command
@@ -68,18 +71,25 @@ func runConvert(cmd *cobra.Command, args []string) error {
6871
}
6972

7073
// Create converter with options
71-
conv := converter.New(&converter.Options{
74+
conv := zerosql.New(&zerosql.Options{
7275
Verbose: verbose,
7376
})
7477

75-
// Convert SQL to MongoDB pipeline
76-
pipeline, err := conv.ConvertSQLToMongo(sqlQuery)
77-
if err != nil {
78-
return fmt.Errorf("conversion failed: %w", err)
78+
if includeCollection {
79+
// Convert SQL to MongoDB pipeline with collection info
80+
result, err := conv.ConvertSQLToMongoWithCollection(sqlQuery)
81+
if err != nil {
82+
return fmt.Errorf("conversion failed: %w", err)
83+
}
84+
return outputResultWithCollection(result)
85+
} else {
86+
// Convert SQL to MongoDB pipeline
87+
pipeline, err := conv.ConvertSQLToMongo(sqlQuery)
88+
if err != nil {
89+
return fmt.Errorf("conversion failed: %w", err)
90+
}
91+
return outputResult(pipeline)
7992
}
80-
81-
// Output the result
82-
return outputResult(pipeline)
8393
}
8494

8595
// outputResult formats and outputs the MongoDB pipeline
@@ -119,3 +129,34 @@ func outputBSON(pipeline []map[string]interface{}) error {
119129
// In a more robust implementation, this could use the official MongoDB Go driver's BSON package
120130
return outputJSON(pipeline)
121131
}
132+
133+
// outputResultWithCollection formats and outputs the MongoDB pipeline with collection information
134+
func outputResultWithCollection(result *zerosql.ConversionResult) error {
135+
switch strings.ToLower(outputFormat) {
136+
case "json":
137+
return outputJSONWithCollection(result)
138+
case "bson":
139+
return outputJSONWithCollection(result) // BSON uses same format for now
140+
default:
141+
return fmt.Errorf("unsupported output format: %s", outputFormat)
142+
}
143+
}
144+
145+
// outputJSONWithCollection outputs the result with collection information as JSON
146+
func outputJSONWithCollection(result *zerosql.ConversionResult) error {
147+
var output []byte
148+
var err error
149+
150+
if prettyPrint {
151+
output, err = json.MarshalIndent(result, "", " ")
152+
} else {
153+
output, err = json.Marshal(result)
154+
}
155+
156+
if err != nil {
157+
return fmt.Errorf("failed to marshal JSON: %w", err)
158+
}
159+
160+
fmt.Println(string(output))
161+
return nil
162+
}

examples.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ echo
55

66
echo "1. Simple SELECT with WHERE clause:"
77
./zero-sql "SELECT name, age FROM users WHERE age > 18"
8+
89
echo
910

1011
echo "2. SELECT with LIKE pattern matching:"

0 commit comments

Comments
 (0)