Skip to content

Commit 93ada1c

Browse files
emickleiCopilot
andauthored
use table definition cache (#12)
* use table definition cache * test cache in test * Update cmd/pgtalk-gen/main.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update cmd/pgtalk-gen/main.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update cmd/pgtalk-gen/main.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * update readme, changes, dependencies --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 6ddfb3a commit 93ada1c

File tree

7 files changed

+87
-27
lines changed

7 files changed

+87
-27
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.vscode
22
cmd/pgtalk-gen/pgtalk-gen
33
test/gen.sh
4+
test/pgtalk-tables-cache.json

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [v1.13.0] - 2025-08-19
6+
7+
- add option `-cache` to store table definitions in JSON for generation without db server.
8+
59
## [v1.12.1] - 2025-05-25
610

711
- add Stringer to QuerySet and MutationSet, update deps

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,4 +246,13 @@ The configuration for this mapping is:
246246
}
247247
}
248248

249+
## cache table definitions read from database
250+
251+
If you do not want to add generated sources to your SCM (source code management system e.g. git) then build systems and other developers need to re-generated them.
252+
The `pgtalk-gen` uses table definitions from an active database server to generate Go table types.
253+
With the `-cache` option, this tool can store those definitions in a JSON file which then can be used instead and you add that file to your SCM.
254+
It is the responsibility of the developer to update it (by deleting it) upon each table definition change in the database.
255+
See the `test` folder for an example; just run all the tasks in the `Makefile`.
256+
257+
249258
(c) 2025, https://ernestmicklei.com. MIT License.

cmd/pgtalk-gen/main.go

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"encoding/json"
56
"flag"
67
"fmt"
78
"log"
@@ -17,23 +18,52 @@ var (
1718
oViews = flag.Bool("views", false, "generated from views, default is false = use tables")
1819
oVerbose = flag.Bool("v", false, "use verbose logging")
1920
oIncludePatterns = flag.String("include", ".*", "comma separated list of regexp for tables to include")
20-
oExludePatterns = flag.String("exclude", "", "comma separated list of regexp for tables to exclude")
21+
oExcludePatterns = flag.String("exclude", "", "comma separated list of regexp for tables to exclude")
2122
oMapping = flag.String("mapping", "", "mapping file for undefined pg data types")
23+
oCache = flag.String("cache", "", "use cache file for table metadata if present")
2224
)
2325

2426
func main() {
2527
flag.Parse()
26-
connectionString := os.Getenv("PGTALK_CONN")
27-
if len(connectionString) == 0 {
28-
fmt.Fprintf(os.Stderr, "Missing value of environment variable PGTALK_CONN\n")
29-
os.Exit(1)
30-
}
31-
3228
if err := applyConfiguredMappings(*oMapping); err != nil {
3329
fmt.Fprintf(os.Stderr, "Unable to process custom mappings: %v\n", err)
3430
os.Exit(1)
3531
}
32+
var tables []PgTable
33+
if *oCache != "" {
34+
if result, err := loadPgTablesFromCache(*oCache); err != nil {
35+
fmt.Fprintf(os.Stderr, "unable to load cache file: %v\ncontinue using database connection", err)
36+
} else {
37+
tables = result
38+
}
39+
}
40+
if len(tables) == 0 {
41+
tables = fetchPgTables()
42+
if *oCache != "" {
43+
if err := savePgTablesToCache(*oCache, tables); err != nil {
44+
fmt.Fprintf(os.Stderr, "unable to save cache file: %v\n", err)
45+
}
46+
}
47+
}
48+
filter := NewTableFilter(*oIncludePatterns, *oExcludePatterns)
49+
for _, each := range tables {
50+
if filter.Includes(each.Name) {
51+
if *oDryrun {
52+
log.Println("[-dry] would generate", each.Name)
53+
} else {
54+
generateFromTable(each, *oViews)
55+
}
56+
}
57+
}
58+
}
3659

60+
func fetchPgTables() []PgTable {
61+
connectionString := os.Getenv("PGTALK_CONN")
62+
if len(connectionString) == 0 {
63+
fmt.Fprintf(os.Stderr, "Missing value of environment variable PGTALK_CONN\n")
64+
os.Exit(1)
65+
}
66+
log.Println("fetching tables from database")
3767
conn, err := pgx.Connect(context.Background(), connectionString)
3868
if err != nil {
3969
fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
@@ -53,14 +83,30 @@ func main() {
5383
log.Fatal(err)
5484
}
5585
}
56-
filter := NewTableFilter(*oIncludePatterns, *oExludePatterns)
57-
for _, each := range all {
58-
if filter.Includes(each.Name) {
59-
if *oDryrun {
60-
log.Println("[DRYRUN] would generate", each.Name)
61-
} else {
62-
generateFromTable(each, *oViews)
63-
}
64-
}
86+
return all
87+
}
88+
89+
func loadPgTablesFromCache(cacheFile string) ([]PgTable, error) {
90+
log.Printf("loading tables from cache: %s", cacheFile)
91+
data, err := os.ReadFile(cacheFile)
92+
if err != nil {
93+
return nil, fmt.Errorf("unable to read cache file: %w", err)
94+
}
95+
var tables []PgTable
96+
if err := json.Unmarshal(data, &tables); err != nil {
97+
return nil, fmt.Errorf("unable to unmarshal cache file: %w", err)
98+
}
99+
return tables, nil
100+
}
101+
102+
func savePgTablesToCache(cacheFile string, tables []PgTable) error {
103+
log.Printf("saving tables to cache: %s", cacheFile)
104+
data, err := json.MarshalIndent(tables, "", " ")
105+
if err != nil {
106+
return fmt.Errorf("unable to marshal tables to JSON: %w", err)
107+
}
108+
if err := os.WriteFile(cacheFile, data, 0644); err != nil {
109+
return fmt.Errorf("unable to write cache file: %w", err)
65110
}
111+
return nil
66112
}

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ require (
1313
require (
1414
github.com/jackc/pgpassfile v1.0.0 // indirect
1515
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
16-
golang.org/x/crypto v0.40.0 // indirect
17-
golang.org/x/text v0.27.0 // indirect
16+
golang.org/x/crypto v0.41.0 // indirect
17+
golang.org/x/text v0.28.0 // indirect
1818
)

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
2424
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
2525
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
2626
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
27-
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
28-
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
27+
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
28+
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
2929
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
3030
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
31-
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
32-
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
31+
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
32+
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
3333
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3434
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
3535
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

test/Makefile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
rmdb:
2-
docker rm -f pgtalk-srv
3-
41
dbsrv:
52
docker run --name pgtalk-srv -e POSTGRES_PASSWORD=pgtalk -p 5432:5432 -d postgres
63

@@ -9,8 +6,11 @@ db:
96

107
gen:
118
cd ../cmd/pgtalk-gen && go install
12-
PGTALK_CONN=postgres://postgres:pgtalk@localhost:5432/pgtalk-db pgtalk-gen -v -o . -include things,products,categories -mapping types/mapping.json
9+
PGTALK_CONN=postgres://postgres:pgtalk@localhost:5432/pgtalk-db pgtalk-gen -v -o . -include things,products,categories -mapping types/mapping.json -cache pgtalk-tables-cache.json
1310
# gofmt -w .
1411

1512
test:
16-
PGTALK_CONN=postgres://postgres:pgtalk@localhost:5432/pgtalk-db go test ${FLAGS}
13+
PGTALK_CONN=postgres://postgres:pgtalk@localhost:5432/pgtalk-db go test ${FLAGS}
14+
15+
rmdb:
16+
docker rm -f pgtalk-srv

0 commit comments

Comments
 (0)