Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 8 additions & 12 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ linters:
- depguard
- dupl # cobra
- gofumpt
- err113
- exhaustruct
- gochecknoinits # cobra
- gochecknoglobals # cobra
Expand All @@ -18,27 +19,22 @@ linters:
- varnamelen

- forbidigo # todo
- wrapcheck # todo
- err113 # todo

- tenv # deprecated

fast: false
linters-settings:
revive:
rules:
- name: var-naming # todo
disabled: true

stylecheck:
checks:
- "-ST1003" # todo
- name: unused-parameter
arguments:
- allowRegex: "cmd||args"

issues:
exclude-files:
- extract.*
- constant/func.go
- cmd/dbgo_gen/run.go
- cmd/dbgo_query/template_merger.go
- cmd/dbgo_query/template_jet.go


- cmd/dbgo_query/schema_merger.go
- cmd/dbgo_query/schema_jet.go
- cmd/dbgo_query/schema_xstruct.go
682 changes: 661 additions & 21 deletions LICENSE

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions NOTICE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Copyright (C) 2025 SwitchUpCB

This file is part of dbgo.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses/.
38 changes: 22 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ _NOTE: You can read the [roadmap](/ROADMAP.md) for a list of implemented feature

## Why don't you use other database frameworks?

`dbgo` gives you the option to use domain models as a source of truth for optimized code, while other database frameworks generate unoptimized code based on the database as a source of truth.
`dbgo` lets you use domain models as a source of truth for optimized code, while other database frameworks generate unoptimized code based on the database as a source of truth.

**Here is an example of the difference between `dbgo` and other frameworks.**

Expand Down Expand Up @@ -136,43 +136,42 @@ custom:

Use the `dbgo query` manager to save customized type-safe SQL statements or generate them.

**1\)** Install the command line tool: `xstruct`.
```
go install github.com/switchupcb/xstruct@latest
```

**2\)** Install the command line tool: `sqlc`.
**1\)** Install the command line tool: `sqlc`.
```
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
```

**3\)** Install the command line tool: `dbgo`.
**2\)** Install the command line tool: `dbgo`.

```
go install github.com/switchupcb/dbgo@latest
```

**4\)** Run the executable with the following options to add SQL to the queries directory.
**3\)** Run the executable with the following options to add SQL to the queries directory.

| Command Line | Description |
| :---------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `db query schema -y path/to/yml` | Generates a `schema.sql` and `schema.go` file representing your database in the queries directory. |
| `db query gen -y path/to/yml` | Generates SQL queries for Read (Select) operations and Create (Insert), Update, Delete operations. |
| `db query template <name> -y path/to/yml` | Adds a `name` template to the queries `templates` directory. The template contains Go type database models you can use to return a type-safe SQL statement from the `SQL()` function in `name.go` which is called by `db query save`. |
| `db query save <name> -y path/to/yml` | Saves an SQL file _(with the same name as the template \[e.g., `name.sql`\])_ containing an SQL statement _(returned from the `SQL()` function in `name.go`)_ to the queries directory. |

_Here are additional usage notes._
_Here are additional command usage notes._

- _`-y`, `--yml`: The path to the YML file must be specified in reference to the current working directory._
- _`db query template`: Every template is updated when this command is executed without a specified template._
- _`db query save`: Every template is saved when this command is executed without a specified template._
- _`db query save`: You are not required to initialize a `go.mod` file to run templates, but using `go get github.com/switchupcb/jet/v2@dbgo` in a `go.mod` related to the template files helps you identify compiler errors in your template files._

#### How do you develop type-safe SQL?

Running `db query template <name> -y path/to/yml` adds a `name.go` file with database models as Go types to your queries directory.
Running `db query template <name> -y path/to/yml` adds a `name.go` file with database models as Go types to your queries directory: You can use these Go types with [`jet`](https://github.com/go-jet/jet) to return an `stmt.Sql()` from `SQL()`, which cannot be interpreted unless the Go code referencing struct fields can be compiled.

Use these Go types with [`jet`](https://github.com/go-jet/jet) to return an `stmt.Sql()` from `SQL()`, which cannot be interpreted unless the Go code referencing struct fields can be compiled.
_Read <a href="https://github.com/go-jet/jet#how-quickly-bugs-are-found" target="_blank">"How quickly bugs are found"</a> for more information about writing type-safe SQL with Go._

_Read <a href="https://github.com/go-jet/jet#how-quickly-bugs-are-found" target="_blank">"How quickly bugs are found"</a> for more information._
You should consider these interpreter usage notes while using templates.
- You do not have to use `jet` to generate SQL programmatically.
- You are not required to initialize a `go.mod` file to run templates, but using `go get github.com/switchupcb/jet/v2@dbgo` in a `go.mod` related to the template files helps you identify compiler errors in your template files while using `jet`.
- `db query save <name>` interprets `schema.go` before `name.go`. So, do not reference declarations from `name.go` in `schema.go`.

### Step 6. Generate the database consumer package

Expand All @@ -194,11 +193,18 @@ _The path to the YML file must be specified in reference to the current working

## What is the License?

`dbgo` uses an [MIT License](https://opensource.org/license/mit).
`dbgo` uses a [AGPLv3 License](https://www.gnu.org/licenses/agpl-3.0.en.html).


### What can you do with this license?

Code generated by `dbgo` can be used without restriction (including proprietary and commercial usage). However, modifications to the `dbgo` Software Source Code or implementing `dbgo` in a larger work programmatically requires you to "include the copyright notice and permission notice in the license in all copies or substantial portions of the Software".
Code generated by `dbgo` can be used without restriction (including proprietary and commercial usage). However, modifications to the `dbgo` Software Source Code or implementing `dbgo` in a larger work programmatically requires you to to [adhere to the AGPLv3 License](https://www.gnu.org/licenses/gpl-faq.html).

### What is a license exception?

A license exception lets you modify and use `dbgo` **without restriction**.

You can receive a license exception for `dbgo` by contacting SwitchUpCB using the [`dbgo` License Exception Inquiry Form](https://switchupcb.com/dbgo-license-exception/).

## Contributing

Expand Down
20 changes: 16 additions & 4 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ Here is the feature release schedule for this software.

## Implemented

You can use `dbgo` with a PostreSQL database.

You can use the `dbgo query` manager to manage your SQL statements or generate them.
- `dbgo query gen`
- `dbgo query template`
- `dbgo query save`

## March 10, 2025: `dbgo gen` (without domain)


You can use `dbgo gen` to generate Database Driver Go code which calls your SQL queries based on the database as a single source of truth.

## March 17, 2025: `dbgo gen` (with domain)

You can use `dbgo gen` to generate Database Driver Go code which calls your SQL queries based on the domain as a single source of truth.

You can place a `_dbgo.sql` file in your queries directory to generate Go code without an SQL file combination operation when `dbgo gen` is called.

You can use options to only generate a `combined.SQL` file (currently output from the implemented `--keep` option) or only generate Database Driver Go code (from the `_dbgo.sql` file).

## March 24, 2025: `dbgo gen` (with .go templates)

You can use `dbgo gen` with `.go` files to customize the code generation algorithm, which will be updated to — by default — generate SQL statement-calling Go code for
Expand All @@ -33,4 +37,12 @@ Structural optimizations provided by the program are already implemented by Marc

## Future: Stored Procedures

You can use `dbgo` to add Stored Procedures to your database for Create (Insert), Read, and Update operations.
You can use `dbgo` to add Stored Procedures to your database for Create (Insert), Read, and Update operations.

## Future: Automatic sqlc Query Annotation Developer

You can use a customizable [sqlc Query Annotation](https://docs.sqlc.dev/en/stable/reference/query-annotations.html) developer to automatically add query annotations to your `dbgo gen` SQL file before Go code generation occurs.

## Future: Database Support

You can use `dbgo` with SQLITE3 and MySQL.
6 changes: 3 additions & 3 deletions cmd/config/yml.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ import (
func LoadYML(relativepath string) (*YML, error) {
file, err := os.ReadFile(relativepath)
if err != nil {
return nil, fmt.Errorf("the specified .yml filepath doesn't exist: %v\n%w", relativepath, err)
return nil, fmt.Errorf("yml read: %w", err)
}

yml := new(YML)
if err := yaml.Unmarshal(file, yml); err != nil {
return nil, fmt.Errorf("error occurred unmarshalling the .yml file\n%w", err)
return nil, fmt.Errorf("yml unmarshal: %w", err)
}

// determine the actual filepath of the setup file.
absloadpath, err := filepath.Abs(relativepath)
if err != nil {
return nil, fmt.Errorf("error occurred while determining the absolute file path of the setup file\n%v", relativepath)
return nil, fmt.Errorf("error determining the absolute file path of the setup file: %q\n%w", relativepath, err)
}

yml.abspath = absloadpath
Expand Down
53 changes: 0 additions & 53 deletions cmd/constant.go

This file was deleted.

25 changes: 25 additions & 0 deletions cmd/constant/external.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package constant

// Constants defined by an external entity.
const (
// OSExitCodeError represents a conventional Linux General Error Exit Code.
OSExitCodeError = 1

// FileModeWrite represents the file mode required to overwrite files.
FileModeWrite = 0644

// Newline represents a newline character.
Newline byte = '\n'

// Colon represents a colon character.
Colon byte = ':'

// Whitesoace represents a whitespace character.
Whitespace byte = ' '

// FileExtSQL represents an SQL file extension.
FileExtSQL = ".sql"

// FileExtGo represents a Go file extension.
FileExtGo = ".go"
)
24 changes: 24 additions & 0 deletions cmd/constant/func.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package constant

import (
"os"
"path/filepath"
)

// CopyFile copies a source file to a destination file.
func CopyFile(srcpath, dstpath string) error {
src, err := os.ReadFile(srcpath)
if err != nil {
return err
}

if err := os.MkdirAll(filepath.Dir(dstpath), FileModeWrite); err != nil {
return err
}

if err := os.WriteFile(dstpath, src, FileModeWrite); err != nil {
return err
}

return nil
}
31 changes: 31 additions & 0 deletions cmd/constant/internal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package constant

import "errors"

// Constants defined by the program.
const (
DatabaseConnectionEnvironmentVariableSymbol = '$'
DatabaseSchemaNameDefault = "public"

DirnameQueriesTemplates = "templates"
DirnameQueriesSchema = "schema"

DirnameTempQueriesGenerationGo = "dbgoquerygentempgo"
DirnameTempQueriesGenerationSQL = "dbgoquerygentempsql"
DirnameTempQueriesGenerationSQLC = "dbgoquerygentempsqlc"

FilenameTemplateSchemaGo = "schema.go"
FilenameQueriesSchemaSQL = "schema.sql"
FilenameQueriesCombinedSQL = "combined.sql"
FilenameQueriesCombinedSQLKept = "_dbgo.sql"

FilenameSQLConfig = "sqlc.yaml"

PkgNameSchemaGo = "sql"
)

// Variables defined by the program.
var (
// ErrYMLDatabaseUnspecified represents an error with the configuration file's database connection value.
ErrYMLDatabaseUnspecified = errors.New("you must specify a database connection ('dbc') in the .yml configuration file")
)
17 changes: 12 additions & 5 deletions cmd/dbgo.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ import (
"os"

"github.com/spf13/cobra"
"github.com/switchupcb/dbgo/cmd/constant"
)

const (
program_description = `dbgo generates a database consumer package for your database and domain models (i.e., Go types).`
programDescription = `dbgo generates a database consumer package for your database and domain models (i.e., Go types).`
)

// cmdDBGO represents the base command when called without any subcommands.
var cmdDBGO = &cobra.Command{
Use: "dbgo",
Short: program_description,
Long: program_description,
Short: programDescription,
Long: programDescription,
CompletionOptions: cobra.CompletionOptions{
DisableDefaultCmd: true,
DisableNoDescFlag: false,
Expand All @@ -31,11 +32,17 @@ var cmdDBGO = &cobra.Command{
// called by main.main() once.
func Execute() {
if err := cmdDBGO.Execute(); err != nil {
os.Exit(1)
os.Exit(constant.OSExitCodeError)
}
}

func init() {
// Persistent Flags work for this command and all subcommands.
cmdDBGO.PersistentFlags().StringVarP(ymlFlag, flag_yml_name, flag_yml_shorthand, "", flag_yml_usage)
cmdDBGO.PersistentFlags().StringVarP(
flagYML,
flagYMLName,
flagYMLShorthand,
"",
flagYMLUsage,
)
}
Loading