-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Ismael GraHms
committed
Dec 11, 2023
1 parent
49bb7b7
commit 1a3c725
Showing
6 changed files
with
624 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
# xgor | ||
|
||
`xgor` is a library that extends [Gorm](https://gorm.io/) to provide additional functionalities for building robust database repositories with support for custom filters, transactions, and relationship handling. | ||
|
||
## Features | ||
|
||
- **Generic Repository:** Use generic repository patterns to handle common CRUD operations for your Gorm models. | ||
|
||
- **Custom Filters:** Easily filter entities based on custom conditions using a flexible and intuitive filter syntax. | ||
|
||
- **Transaction Support:** Perform operations within a transaction to ensure consistency and atomicity. | ||
|
||
- **Relationship Handling:** Simplify relationship management with built-in functions for clearing relationships. | ||
|
||
## Installation | ||
|
||
```bash | ||
go get -u github.com/grahms/xgor | ||
``` | ||
|
||
## Usage | ||
|
||
### Initializing a Repository | ||
|
||
```go | ||
import ( | ||
"gorm.io/gorm" | ||
"github.com/grahms/xgor" | ||
) | ||
|
||
// Initialize DB | ||
db, err := xgor.Open(...) | ||
|
||
// Create a new repository | ||
repo := xgor.New[BlogPost](db, errors.New("blog post not found")) | ||
|
||
// Or with relationships | ||
repoWithRelations := xgor.NewWithRelationships[BlogPost](db, errors.New("blog post not found"), "comments", "author") | ||
``` | ||
|
||
### Adding a Blog Post | ||
|
||
```go | ||
post := &BlogPost{ | ||
Title: "Introduction to xgor", | ||
Content: "Learn how to use xgor to supercharge your Gorm-based repositories.", | ||
AuthorID: 1, | ||
CategoryID: 2, | ||
PublishedAt: time.Now(), | ||
} | ||
err := repo.Add(post) | ||
``` | ||
|
||
### Querying Blog Posts with Custom Filters | ||
|
||
```go | ||
// Get all published posts in the "Technology" category written by a specific author | ||
filters := xgor.FilterType{ | ||
"published_at__lte": time.Now(), | ||
"category.name__eq": "Technology", | ||
"author.id__eq": 1, | ||
} | ||
posts, err := repo.GetAll(nil, nil, nil, filters) | ||
``` | ||
|
||
### Performing a Transaction | ||
|
||
```go | ||
err := repo.PerformTransaction(func(tx *gorm.DB) error { | ||
// Update the author's profile and add a new blog post within the same transaction | ||
author, err := authorRepo.GetByID(1) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
author.Name = "Updated Author Name" | ||
if err := authorRepo.Update(author); err != nil { | ||
return err | ||
} | ||
|
||
newPost := &BlogPost{ | ||
Title: "Advanced xgor Techniques", | ||
Content: "Explore advanced techniques for optimizing database queries with xgor.", | ||
AuthorID: 1, | ||
CategoryID: 3, | ||
PublishedAt: time.Now(), | ||
} | ||
|
||
return repo.Add(newPost) | ||
}) | ||
``` | ||
|
||
## Example Use Case: Blogging Application | ||
|
||
Let's consider a blogging application where `xgor` is used to manage blog posts. In this scenario, `xgor` simplifies the data access layer, allowing developers to focus on building features rather than dealing with intricate database operations. | ||
|
||
### Use Case Scenario | ||
|
||
- **Scenario:** The application needs to fetch all published blog posts in a specific category written by a particular author. | ||
|
||
- **Solution:** Utilize `xgor`'s custom filters to easily query the database and retrieve the required blog posts without the complexity of crafting intricate SQL queries. | ||
|
||
```go | ||
// Example: Get all published posts in the "Technology" category written by a specific author | ||
filters := xgor.FilterType{ | ||
"published_at__lte": time.Now(), | ||
"category.name__eq": "Technology", | ||
"author.id__eq": 1, | ||
} | ||
posts, err := repo.GetAll(nil, nil, nil, filters) | ||
``` | ||
## Example Use Case: Blogging Application (Pagination) | ||
|
||
### Use Case Scenario | ||
|
||
- **Scenario:** The blogging application needs to display a paginated list of blog posts on the homepage. | ||
|
||
- **Solution:** Utilize `xgor` to implement pagination and retrieve a subset of blog posts for display. | ||
|
||
```go | ||
// Example: Get paginated blog posts for the homepage | ||
limit := 10 // Number of posts per page | ||
page := 1 // Current page | ||
orderBy := "published_at desc" // Order posts by published date in descending order | ||
|
||
// Use xgor to get paginated blog posts | ||
paginationFilters := xgor.FilterType{"category_id__eq": 1} // Filter by category ID, if needed | ||
blogPosts, err := repo.GetAll(&limit, &page, &orderBy, paginationFilters) | ||
|
||
// Check for errors and handle the paginated blog posts | ||
if err != nil { | ||
// Handle error | ||
} else { | ||
// Access paginated results | ||
totalPosts := blogPosts.TotalCount | ||
currentPage := page | ||
postsPerPage := limit | ||
resultCount := blogPosts.ResultCount | ||
displayedPosts := *blogPosts.Items | ||
|
||
// Process and display paginated blog posts | ||
for _, post := range displayedPosts { | ||
// Process each blog post | ||
} | ||
} | ||
``` | ||
## Custom Filters | ||
|
||
Custom filters allow you to specify conditions for filtering entities. The filter syntax is based on the column name and a suffix that represents the condition. Here is a table of available filters: | ||
|
||
| Filter | Description | Example | | ||
|------------------|----------------------------------------------|-----------------------------------| | ||
| `__eq` | Equals | `"age__eq": 25` | | ||
| `__gt` | Greater Than | `"age__gt": 21` | | ||
| `__lt` | Less Than | `"age__lt": 30` | | ||
| `__gte` | Greater Than or Equal To | `"age__gte": 21` | | ||
| `__lte` | Less Than or Equal To | `"age__lte": 30` | | ||
| `__in` | In Array | `"age__in": []int{25, 30}` | | ||
| `__not` | Not Equal To | `"age__not": 25` | | ||
| `__not_in` | Not In Array | `"age__not_in": []int{25, 30}` | | ||
| `__like` | Like (substring match) | `"name__like": "John"` | | ||
|
||
Combine these filters to create powerful and flexible queries tailored to your application's needs. | ||
|
||
## Contributing | ||
|
||
Feel free to contribute by opening issues or submitting pull requests. Please follow the [Contributing Guidelines](CONTRIBUTING.md). | ||
|
||
## License | ||
|
||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"github.com/grahms/xgor" | ||
"gorm.io/driver/sqlite" | ||
) | ||
|
||
// Product Define a sample entity | ||
type Product struct { | ||
ID uint `gorm:"primaryKey"` | ||
Name string `gorm:"not null"` | ||
Price float64 | ||
} | ||
|
||
func main() { | ||
// Connect to an in-memory SQLite database | ||
db, err := xgor.Open(sqlite.Open("file::memory:")) | ||
if err != nil { | ||
fmt.Println("Error connecting to the database:", err) | ||
return | ||
} | ||
|
||
// Migrate the database schema | ||
err = db.AutoMigrate(&Product{}) | ||
if err != nil { | ||
fmt.Println("Error migrating database schema:", err) | ||
return | ||
} | ||
|
||
// Create a repository for the Product entity | ||
productRepo := xgor.New[Product](db, errors.New("product not found")) | ||
|
||
// Add a product | ||
newProduct := &Product{Name: "Laptop", Price: 999.99} | ||
err = productRepo.Add(newProduct) | ||
if err != nil { | ||
fmt.Println("Error adding product:", err) | ||
return | ||
} | ||
|
||
// Update the product | ||
updatedProduct := &Product{ID: newProduct.ID, Name: "Updated Laptop", Price: 1099.99} | ||
err = productRepo.Update(updatedProduct) | ||
if err != nil { | ||
fmt.Println("Error updating product:", err) | ||
return | ||
} | ||
|
||
// Retrieve a product by ID | ||
retrievedProduct, err := productRepo.GetByID(newProduct.ID) | ||
if err != nil { | ||
fmt.Println("Error getting product by ID:", err) | ||
return | ||
} | ||
fmt.Println("Retrieved Product:", retrievedProduct) | ||
|
||
// Use custom filters to get products with a specific condition | ||
filters := xgor.FilterType{"price__gt": 1000.0} | ||
highPricedProducts, err := productRepo.GetAll(nil, nil, nil, filters) | ||
if err != nil { | ||
fmt.Println("Error getting high-priced products:", err) | ||
return | ||
} | ||
fmt.Println("High-Priced Products:", highPricedProducts.Items) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,18 @@ | ||
module Rxgor | ||
module github.com/grahms/xgor | ||
|
||
go 1.20 | ||
|
||
require gorm.io/gorm v1.25.5 | ||
require ( | ||
github.com/stretchr/testify v1.8.4 | ||
gorm.io/driver/sqlite v1.5.4 | ||
gorm.io/gorm v1.25.5 | ||
) | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/jinzhu/inflection v1.0.0 // indirect | ||
github.com/jinzhu/now v1.1.5 // indirect | ||
github.com/mattn/go-sqlite3 v1.14.17 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,20 @@ | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= | ||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= | ||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= | ||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= | ||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= | ||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gorm.io/driver/sqlite v1.5.4 h1:IqXwXi8M/ZlPzH/947tn5uik3aYQslP9BVveoax0nV0= | ||
gorm.io/driver/sqlite v1.5.4/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4= | ||
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= | ||
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.