Skip to content

Commit 22327c2

Browse files
committed
fixed file creation path
1 parent cf3253d commit 22327c2

4 files changed

Lines changed: 189 additions & 41 deletions

File tree

store/README.md

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,25 @@ go install gofr.dev/cli/gofr@latest
1616

1717
1. **Initialize a store configuration:**
1818
```bash
19-
gofr store init
19+
gofr store init -name=user
2020
```
21-
This creates a `store.yaml` file with example configuration.
21+
This creates the following in `stores/user/`:
22+
- `store.yaml` — configuration template
23+
- `interface.go` — initial interface stub
24+
- `user.go` — initial implementation stub
2225

23-
2. **Edit `store.yaml`** with your models and queries (see Configuration Reference below).
26+
2. **Edit `stores/user/store.yaml`** with your models and queries (see Configuration Reference below).
2427

2528
3. **Generate the store code:**
2629
```bash
27-
gofr store generate
30+
gofr store generate -config=stores/user/store.yaml
2831
```
2932

3033
4. **Use in your application:**
3134
```go
3235
import "your-project/stores/user"
33-
34-
userStore := user.NewUser()
36+
37+
userStore := user.NewUserStore()
3538
result, err := userStore.GetUserByID(ctx, 123)
3639
```
3740

@@ -40,11 +43,16 @@ go install gofr.dev/cli/gofr@latest
4043
### Commands
4144

4245
```bash
43-
# Initialize a new store.yaml configuration file
44-
gofr store init
46+
# Initialize a new store directory and store.yaml configuration file
47+
# The -name flag is required
48+
gofr store init -name=<store-name>
4549

46-
# Generate store code from store.yaml
50+
# Generate store code from a store.yaml
51+
# Default config path: stores/store.yaml
4752
gofr store generate
53+
54+
# Generate store code from a specific config file
55+
gofr store generate -config=stores/user/store.yaml
4856
```
4957

5058
### Project Structure
@@ -53,11 +61,11 @@ After generation, your project will have:
5361

5462
```
5563
stores/
56-
├── all.go # Store registry (auto-generated)
57-
── user/
58-
├── interface.go # UserStore interface
59-
├── store.go # UserStore implementation
60-
└── user.go # User model (if generated)
64+
├── all.go # Store registry factory (auto-generated)
65+
── user/
66+
├── interface.go # UserStore interface
67+
├── userStore.go # userStore implementation boilerplate
68+
└── user.go # User model (if generated)
6169
```
6270

6371
### Using Generated Stores
@@ -66,19 +74,24 @@ stores/
6674
```go
6775
import "your-project/stores/user"
6876

69-
userStore := user.NewUser()
77+
userStore := user.NewUserStore()
7078
result, err := userStore.GetUserByID(ctx, id)
7179
```
7280

7381
**Option 2: Using the registry**
7482
```go
75-
import "your-project/stores"
83+
import (
84+
"your-project/stores"
85+
"your-project/stores/user"
86+
)
7687

77-
allStores := stores.All()
78-
userStore := stores.GetStore("user").(user.User)
88+
// GetStore returns a factory-created instance; cast to the correct interface
89+
userStore := stores.GetStore("user").(user.UserStore)
7990
result, err := userStore.GetUserByID(ctx, id)
8091
```
8192

93+
> **💡 Note:** `stores.All()` returns a `map[string]func() any` — a map of **factory functions**, not active instances. Use `stores.GetStore(name)` for convenient access.
94+
8295
### Integration Example
8396

8497
```go
@@ -91,7 +104,7 @@ import (
91104

92105
func main() {
93106
app := gofr.New()
94-
userStore := user.NewUser()
107+
userStore := user.NewUserStore()
95108

96109
app.GET("/users/{id}", func(ctx *gofr.Context) (interface{}, error) {
97110
id, _ := strconv.ParseInt(ctx.PathParam("id"), 10, 64)
@@ -113,7 +126,7 @@ stores:
113126
- name: "user"
114127
package: "user"
115128
output_dir: "stores/user"
116-
interface: "User"
129+
interface: "UserStore"
117130
implementation: "userStore"
118131
queries:
119132
- name: "GetUserByID"
@@ -146,10 +159,12 @@ models:
146159
| `name` | Store identifier (used in registry) | Yes |
147160
| `package` | Go package name | Yes |
148161
| `output_dir` | Directory for generated files | Yes |
149-
| `interface` | Interface name (e.g., "User") | Yes |
150-
| `implementation` | Implementation struct name | Yes |
162+
| `interface` | Interface name — **recommended: `<Name>Store`** (e.g., `UserStore`) | Yes |
163+
| `implementation` | Implementation struct name (e.g., `userStore`) | Yes |
151164
| `queries` | Array of database queries | Yes |
152165

166+
> **⚠️ Naming Convention:** The registry (`stores/all.go`) automatically appends `"Store"` when building constructor calls. To avoid compilation errors, always name your interface as `<Name>Store` (e.g., `UserStore`) and the generated constructor will be `New<Name>Store()`.
167+
153168
### Models
154169

155170
**Generate a new model:**
@@ -185,10 +200,10 @@ models:
185200
- `delete` - DELETE queries
186201

187202
**Return Types:**
188-
- `single` - Returns a single model instance
189-
- `multiple` - Returns a slice of models
190-
- `count` - Returns `int64` count
191-
- `custom` - Returns `interface{}`
203+
- `single` - Returns `(*Model, error)`
204+
- `multiple` - Returns `([]Model, error)`
205+
- `count` - Returns `(int64, error)`
206+
- `custom` - Returns `(any, error)`
192207

193208
**Example Query:**
194209
```yaml
@@ -206,21 +221,23 @@ queries:
206221

207222
### Multiple Stores
208223

224+
You can define multiple stores in a single YAML file. Each store gets its own directory and the registry (`stores/all.go`) tracks all of them.
225+
209226
```yaml
210227
version: "1.0"
211228
212229
stores:
213230
- name: "user"
214231
package: "user"
215232
output_dir: "stores/user"
216-
interface: "User"
233+
interface: "UserStore"
217234
implementation: "userStore"
218235
queries: [...]
219236
220237
- name: "product"
221238
package: "product"
222239
output_dir: "stores/product"
223-
interface: "Product"
240+
interface: "ProductStore"
224241
implementation: "productStore"
225242
queries: [...]
226243
@@ -231,6 +248,12 @@ models:
231248
fields: [...]
232249
```
233250

251+
**Accessing multiple stores from the registry:**
252+
```go
253+
userStore := stores.GetStore("user").(user.UserStore)
254+
productStore := stores.GetStore("product").(product.ProductStore)
255+
```
256+
234257
## Generated Code Examples
235258

236259
### Interface
@@ -240,8 +263,8 @@ package user
240263
241264
import "gofr.dev/pkg/gofr"
242265
243-
type User interface {
244-
GetUserByID(ctx *gofr.Context, id int64) (User, error)
266+
type UserStore interface {
267+
GetUserByID(ctx *gofr.Context, id int64) (*User, error)
245268
GetAllUsers(ctx *gofr.Context) ([]User, error)
246269
}
247270
```
@@ -253,16 +276,18 @@ package user
253276
254277
type userStore struct{}
255278
256-
func NewUser() User {
279+
func NewUserStore() UserStore {
257280
return &userStore{}
258281
}
259282
260-
func (s *userStore) GetUserByID(ctx *gofr.Context, id int64) (User, error) {
283+
func (s *userStore) GetUserByID(ctx *gofr.Context, id int64) (*User, error) {
261284
// TODO: Implement query using ctx.SQL()
262-
return User{}, nil
285+
return &User{}, nil
263286
}
264287
```
265288

289+
> **💡 Note:** The generator creates method **signatures and boilerplate only**. You must implement the actual SQL execution in the `// TODO` sections using `ctx.SQL()` methods.
290+
266291
### Model
267292
```go
268293
// Code generated by gofr.dev/cli/gofr. DO NOT EDIT.
@@ -277,4 +302,13 @@ type User struct {
277302
func (User) TableName() string {
278303
return "user"
279304
}
280-
```
305+
```
306+
307+
## Best Practices
308+
309+
1. **Never Edit Generated Files**: Files marked `DO NOT EDIT` (`interface.go`, `all.go`) are overwritten on every generation. Keep custom SQL logic in your implementation file (e.g., `userStore.go`).
310+
2. **Use `<Name>Store` Interface Names**: This ensures the registry and constructor align correctly.
311+
3. **Commit your YAML**: Treat `store.yaml` as source of truth. Re-run `gofr store generate` after every change.
312+
4. **Reference Existing Models**: If you already have model structs, use the `path` + `package` fields to avoid duplication.
313+
314+
For a complete working example, see [`store/example.yaml`](./example.yaml).

store/generator.go

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func InitStore(ctx *gofr.Context) (any, error) {
141141
return nil, fmt.Errorf("failed to create store directory: %w", err)
142142
}
143143

144-
if err := generateStoreConfig(ctx, storeName, storeDir); err != nil {
144+
if err := generateStoreConfig(ctx, storeName, "stores"); err != nil {
145145
return nil, fmt.Errorf("failed to generate store config: %w", err)
146146
}
147147

@@ -196,10 +196,15 @@ func GenerateStore(ctx *gofr.Context) (any, error) {
196196

197197
newStores := make([]Entry, 0, len(cfg.Stores))
198198
for i := range cfg.Stores {
199+
interfaceName := cfg.Stores[i].Interface
200+
if interfaceName == "" {
201+
interfaceName = cases.Title(language.English).String(cfg.Stores[i].Name) + "Store"
202+
}
203+
199204
newStores = append(newStores, Entry{
200205
Name: cfg.Stores[i].Name,
201-
PackageName: strings.ToLower(cfg.Stores[i].Name),
202-
InterfaceName: cases.Title(language.English).String(cfg.Stores[i].Name) + "Store",
206+
PackageName: cfg.Stores[i].Package,
207+
InterfaceName: interfaceName,
203208
})
204209
}
205210

@@ -652,9 +657,15 @@ func generateModelFile(ctx *gofr.Context, modelFile string, store *Info, model *
652657
return nil
653658
}
654659

655-
// generateStoreConfig creates the initial store.yaml configuration file.
656-
func generateStoreConfig(ctx *gofr.Context, storeName, storeDir string) error {
657-
configFile := filepath.Join(storeDir, "store.yaml")
660+
// generateStoreConfig creates the initial store.yaml configuration file or appends to an existing one.
661+
func generateStoreConfig(ctx *gofr.Context, storeName, storesDir string) error {
662+
configFile := filepath.Join(storesDir, "store.yaml")
663+
storeDir := fmt.Sprintf("stores/%s", strings.ToLower(storeName))
664+
665+
// If file exists, append to it
666+
if _, err := os.Stat(configFile); err == nil {
667+
return appendToStoreConfig(ctx, configFile, storeName, storeDir)
668+
}
658669

659670
t, err := template.New("config").Parse(StoreConfigTemplate)
660671
if err != nil {
@@ -668,11 +679,13 @@ func generateStoreConfig(ctx *gofr.Context, storeName, storeDir string) error {
668679
defer file.Close()
669680

670681
data := struct {
682+
StoreName string
671683
PackageName string
672684
OutputDir string
673685
InterfaceName string
674686
ImplementationName string
675687
}{
688+
StoreName: storeName,
676689
PackageName: strings.ToLower(storeName),
677690
OutputDir: storeDir,
678691
InterfaceName: cases.Title(language.English).String(storeName) + "Store",
@@ -688,6 +701,44 @@ func generateStoreConfig(ctx *gofr.Context, storeName, storeDir string) error {
688701
return nil
689702
}
690703

704+
// appendToStoreConfig appends a new store to the existing store.yaml.
705+
func appendToStoreConfig(ctx *gofr.Context, configFile, storeName, storeDir string) error {
706+
cfg, err := parseConfigFile(ctx, configFile)
707+
if err != nil {
708+
return err
709+
}
710+
711+
// Check if store already exists
712+
for _, s := range cfg.Stores {
713+
if s.Name == storeName {
714+
return nil // Already exists
715+
}
716+
}
717+
718+
newStore := Info{
719+
Name: storeName,
720+
Package: strings.ToLower(storeName),
721+
OutputDir: storeDir,
722+
Interface: cases.Title(language.English).String(storeName) + "Store",
723+
Implementation: strings.ToLower(storeName),
724+
}
725+
726+
cfg.Stores = append(cfg.Stores, newStore)
727+
728+
data, err := yaml.Marshal(cfg)
729+
if err != nil {
730+
return fmt.Errorf("failed to marshal config: %w", err)
731+
}
732+
733+
if err := os.WriteFile(configFile, data, defaultFilePerm); err != nil {
734+
return fmt.Errorf("failed to write config file: %w", err)
735+
}
736+
737+
ctx.Logger.Infof("Appended store %s to config file: %s", storeName, configFile)
738+
739+
return nil
740+
}
741+
691742
// generateInitialInterface creates the initial interface.go file.
692743
func generateInitialInterface(ctx *gofr.Context, storeName, storeDir string) error {
693744
interfaceFile := filepath.Join(storeDir, "interface.go")

0 commit comments

Comments
 (0)