Skip to content

Commit 9bb4dc4

Browse files
committed
Add more features
1 parent 6e5a932 commit 9bb4dc4

24 files changed

Lines changed: 3846 additions & 436 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ devenv.local.nix
99
.pre-commit-config.yaml
1010

1111
coverage.*
12-
bin/
12+
bin/
13+
codegen/test/

Readme.md

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,29 @@ MangoSQL is a fresh and juicy SQL code generator.
99
3. You write application code that calls the generated code
1010

1111
This is not an ORM, and you can easily inspect the code generated.
12-
This is inspired by [SQLC](https://github.com/sqlc-dev/sqlc) but pushes the idea farther by supporting relations and dynamic queries.
12+
This is inspired by [SQLC](https://github.com/sqlc-dev/sqlc) but pushes the idea farther by supporting batching, relations and dynamic queries.
1313

1414
## Features
1515

16-
* **Convenient**: Generate all the structs for you
16+
* **Convenient**: All the structs are generated for you, No need for manual DTO/PDO
17+
* **Time Saver**: All the basic queries (CRUD) are generated from your schema alone
18+
* **Developer Friendly**: The code generated contains comments, examples and is designed with IDE autocompletion in mind
1719
* **Flexible**: Provide a way to run dynamic queries (pagination, search, ...)
18-
* **Time Saver**: All the basic queries (CRUD) are auto-generated from your schema, nothing to declare
19-
* **Performant**: Support batching out of the box
20-
* **Safe**: All the SQL queries use prepared statement
21-
* **Consistency**: Easy to use transaction API
20+
* **Composable**: Use filters auto-generated or make your owns and reuse them across queries
21+
* **Safe**: All the SQL queries use prepared statement to avoid injection
22+
* **Consistent**: Easy to use transaction API to rollback when an error occurs
2223

2324
## Status
2425

25-
This is WIP, features are still not complete and may change
26+
This repostiroy is currently a WIP, features are still not complete and may likely change
2627

27-
Goals:
28-
* Handle custom relations (join, aggregations, ...)
29-
* Handle views
30-
* Support Mysql/MariaDB/Sqlite3
31-
* Better CLI
28+
Roadmap:
29+
* Handle custom queries for advanced relations (join, aggregations, ...)
30+
* Handle sql enums
31+
* Handle sql views
32+
* Support more types and custom types (cf ulid, ...)
33+
* Support more driver and database Mysql/MariaDB/Sqlite3
34+
* Write benchmark to compare performance with existing Golang ORM
3235

3336
## Example
3437

@@ -71,9 +74,16 @@ err := db.Transaction(func(tx *database.DBClient) error {
7174
// ...
7275
})
7376

74-
// Handle dynamic clauses (filters, pagination, ...)
75-
users, err := db.User.Where(func(cond database.SelectBuilder) database.SelectBuilder {
76-
return cond.Where("name ILIKE $1", "%user%").Offset(0).Limit(20)
77+
// Typed dynamic clauses (filters, pagination, ...) with typed helpers
78+
users, err := db.User.FindMany(
79+
db.User.Query.Name.Like("%user%"),
80+
db.User.Query.Amount.MoreThan(0),
81+
db.User.Query.Limit(20)
82+
)
83+
84+
// Raw dynamic clauses
85+
users, err := db.User.FindMany(func(query SelectBuilder) SelectBuilder {
86+
return query.Where("name ILIKE $1 OR name ILIKE $2", "%user1%", "%user2%")
7787
})
7888

7989
// Handle Batching
@@ -82,28 +92,45 @@ ids, err := db.User.UpsertMany([]database.UserUpdate{
8292
{Id: id, Email: "user1-updated", Name: "user1-updated"}, // this entry will be updated
8393
})
8494

95+
// Use Struct Helpers
96+
user, _ := db.User.FindById(id)
97+
user.name = "NewName"
98+
user.Save(db)
99+
85100
// ...
101+
86102
```
87103

88104
## API
89105

90106
Here is the list of all the auto-generated methods for your tables:
91107

92108
## Getters
93-
* db.{Table}.Count()
94-
* db.{Table}.CountWhere(condition)
95-
* db.{Table}.All(offset, limit)
96-
* db.{Table}.Where(condition)
97-
* db.{Table}.GetById(id)
109+
* db.{Table}.FindById(id) (*T, error)
110+
* db.{Table}.FindByIds(id) ([]T, error)
111+
* db.{Table}.FindUnique(...filters) (*T, error)
112+
* db.{Table}.FindMany(...filters) ([]T, error)
113+
* db.{Table}.Count(...filters) (int, error)
98114

99115
## Mutations
100-
* db.{Table}.Create(input)
101-
* db.{Table}.Update(input)
102-
* db.{Table}.Upsert(input)
116+
* db.{Table}.Create(input) (*T, error)
117+
* db.{Table}.CreateMany(inputs) ([]T, error)
118+
* db.{Table}.Update(input) (*T, error)
119+
* db.{Table}.UpdateMany(inputs) ([]T, error)
120+
* db.{Table}.Upsert(input) (*T, error)
121+
* db.{Table}.UpsertMany(inputs) ([]T, error)
103122
* db.{Table}.DeleteSoft(id)
104123
* db.{Table}.DeleteHard(id)
105124

106-
## Batch Mutations
107-
* db.{Table}.CreateMany(inputs)
108-
* db.{Table}.UpdateMany(inputs)
109-
* db.{Table}.UpsertMany(inputs)
125+
## Query Filters
126+
* db.{Table}.Query.{Field}.Equal(input)
127+
* db.{Table}.Query.{Field}.NotEqual(input)
128+
* db.{Table}.Query.{Field}.In(input)
129+
* db.{Table}.Query.{Field}.NotIn(input)
130+
* db.{Table}.Query.{Field}.Like(input)
131+
* db.{Table}.Query.{Field}.MoreThan(input)
132+
* db.{Table}.Query.{Field}.LessThan(input)
133+
* db.{Table}.Query.{Field}.Between(low, high)
134+
* db.{Table}.Query.Offset(offset)
135+
* db.{Table}.Query.Limit(limit)
136+
* db.{Table}.Query.OrderBy{Field}()

cmd/mangosql/mangosql.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,27 +61,45 @@ type GenerateOptions struct {
6161
}
6262

6363
func generate(opts GenerateOptions) error {
64-
stat, err := os.Stat(opts.Output)
64+
stat, err := os.Stat(opts.Src)
6565
if err != nil {
6666
return err
6767
}
6868

6969
var sql string
70+
var queriesFilePath string
71+
var queriesSql string
7072
if stat.IsDir() {
7173
sql = parseMigrationFolder(opts.Src)
74+
75+
queriesFilePath = path.Join(opts.Src, "queries.sql")
7276
} else {
7377
data, err := os.ReadFile(opts.Src)
7478
if err != nil {
7579
return err
7680
}
7781
sql = string(data)
82+
83+
queriesFilePath = path.Join(path.Dir(opts.Src), "queries.sql")
7884
}
7985

8086
schema, err := internal.ParseSchema(sql)
8187
if err != nil {
8288
return err
8389
}
8490

91+
if _, err = os.Stat(queriesFilePath); err == nil {
92+
data, err := os.ReadFile(queriesFilePath)
93+
if err != nil {
94+
return err
95+
}
96+
queriesSql = string(data)
97+
err = internal.ParseQueries(schema, queriesSql)
98+
if err != nil {
99+
return err
100+
}
101+
}
102+
85103
var b bytes.Buffer
86104
contents := bufio.NewWriter(&b)
87105

0 commit comments

Comments
 (0)