initial commit

This commit is contained in:
2025-05-22 19:39:08 +08:00
commit 531bb42d01
103 changed files with 10291 additions and 0 deletions

View File

@ -0,0 +1,13 @@
package config
import "github.com/zeromicro/go-zero/zrpc"
type Config struct {
zrpc.RpcServerConf
DB struct {
DataSource string
MaxOpenConns int
MaxIdleConns int
ConnMaxLifetime int
}
}

View File

@ -0,0 +1,31 @@
package logic
import (
"context"
"godemo/category/category"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type BatchCreateCategoriesLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewBatchCreateCategoriesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchCreateCategoriesLogic {
return &BatchCreateCategoriesLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// 批量操作
func (l *BatchCreateCategoriesLogic) BatchCreateCategories(in *category.BatchCreateRequest) (*category.BatchCreateResponse, error) {
// todo: add your logic here and delete this line
return &category.BatchCreateResponse{}, nil
}

View File

@ -0,0 +1,30 @@
package logic
import (
"context"
"godemo/category/category"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type BatchUpdateCategoriesLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewBatchUpdateCategoriesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchUpdateCategoriesLogic {
return &BatchUpdateCategoriesLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *BatchUpdateCategoriesLogic) BatchUpdateCategories(in *category.BatchUpdateRequest) (*category.BatchUpdateResponse, error) {
// todo: add your logic here and delete this line
return &category.BatchUpdateResponse{}, nil
}

View File

@ -0,0 +1,30 @@
package logic
import (
"context"
"godemo/category/category"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type CheckAliasLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewCheckAliasLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CheckAliasLogic {
return &CheckAliasLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *CheckAliasLogic) CheckAlias(in *category.CheckAliasRequest) (*category.CheckAliasResponse, error) {
// todo: add your logic here and delete this line
return &category.CheckAliasResponse{}, nil
}

View File

@ -0,0 +1,118 @@
package logic
import (
"context"
"database/sql"
"errors"
"time"
"godemo/category/category"
"godemo/category/internal/model"
"godemo/category/internal/svc"
"github.com/google/uuid"
"github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type CreateCategoryLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewCreateCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateCategoryLogic {
return &CreateCategoryLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *CreateCategoryLogic) CreateCategory(in *category.CreateCategoryRequest) (*category.CategoryInfoResponse, error) {
// 参数校验
if in.SystemId == "" || in.Name == "" {
return nil, status.Error(codes.InvalidArgument, "system_id 和 name 不能为空")
}
// 检查唯一性
exists, err := l.checkCategoryExists(in)
if err != nil {
logx.Error("唯一性检查失败: ", err)
return nil, status.Error(codes.Internal, "内部错误")
}
if exists {
return nil, status.Error(codes.AlreadyExists, "分类已存在")
}
// 构建模型
newCategory := &model.Categories{
Id: uuid.New().String(),
SystemId: in.SystemId,
Name: in.Name,
Alias: toNullString(in.Alias),
ParentId: toNullString(in.ParentId),
Description: toNullString(in.Description),
CreatedAt: time.Now(),
UpdatedAt: sql.NullTime{Time: time.Now(), Valid: true},
}
// 插入数据库
if _, err := l.svcCtx.CategoryModel.Insert(l.ctx, newCategory); err != nil {
logx.Error("插入失败: ", err)
return nil, status.Error(codes.Internal, "创建分类失败")
}
// 返回响应
return &category.CategoryInfoResponse{
Category: &category.CategoryInfo{
Id: newCategory.Id,
SystemId: newCategory.SystemId,
Name: newCategory.Name,
Alias: in.Alias,
ParentId: in.ParentId,
Description: in.Description,
CreatedAt: newCategory.CreatedAt.Unix(),
UpdatedAt: newCategory.UpdatedAt.Time.Unix(),
},
}, nil
}
// 空字符串转换为 sql.NullString
func toNullString(s string) sql.NullString {
return sql.NullString{String: s, Valid: s != ""}
}
// 唯一性检查逻辑
func (l *CreateCategoryLogic) checkCategoryExists(in *category.CreateCategoryRequest) (bool, error) {
// 检查名称唯一性
_, err := l.svcCtx.CategoryModel.FindBySystemParentName(
l.ctx,
in.SystemId,
in.ParentId,
in.Name,
)
if err == nil {
return true, nil
} else if !errors.Is(err, model.ErrNotFound) {
return false, err
}
// 检查别名唯一性(如果提供了别名)
if in.Alias != "" {
_, err := l.svcCtx.CategoryModel.FindBySystemParentAlias(
l.ctx,
in.SystemId,
in.ParentId,
in.Alias,
)
if err == nil {
return true, nil
} else if !errors.Is(err, model.ErrNotFound) {
return false, err
}
}
return false, nil
}

View File

@ -0,0 +1,91 @@
package logic
import (
"context"
"errors"
"fmt"
"godemo/category/category"
"godemo/category/internal/model"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type DeleteCategoryLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewDeleteCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteCategoryLogic {
return &DeleteCategoryLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *DeleteCategoryLogic) DeleteCategory(in *category.DeleteCategoryRequest) (*category.DeleteResponse, error) {
// 1. 参数校验
if in.Id == "" {
return nil, status.Error(codes.InvalidArgument, "分类ID不能为空")
}
// 2. 检查分类是否存在
_, err := l.svcCtx.CategoryModel.FindOne(l.ctx, in.Id)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return nil, status.Error(codes.NotFound, "分类不存在")
}
l.Logger.Errorf("查询分类失败: %v", err)
return nil, status.Error(codes.Internal, "内部错误")
}
// 3. 开启事务执行删除
err = l.svcCtx.CategoryModel.Transact(l.ctx, func(ctx context.Context, session sqlx.Session) error {
// 3.1 处理子分类根据外键约束自动级联删除或设为NULL
if err := l.handleChildren(ctx, session, in.Id); err != nil {
return err
}
// 3.2 删除主分类
if err := l.svcCtx.CategoryModel.WithSession(session).Delete(ctx, in.Id); err != nil {
return fmt.Errorf("删除分类失败: %w", err)
}
return nil
})
if err != nil {
l.Logger.Errorf("删除分类事务失败: %v", err)
return nil, status.Error(codes.Internal, "删除分类失败")
}
return &category.DeleteResponse{
Success: true,
}, nil
}
// handleChildren 处理子分类(根据外键约束配置决定行为)
func (l *DeleteCategoryLogic) handleChildren(ctx context.Context, session sqlx.Session, parentID string) error {
// 如果外键是 ON DELETE SET NULL需要显式更新子分类
if l.needUpdateChildren() {
query := "UPDATE categories SET parent_id = NULL WHERE parent_id = $1"
if _, err := session.ExecCtx(ctx, query, parentID); err != nil {
return fmt.Errorf("更新子分类失败: %w", err)
}
}
// 如果是 ON DELETE CASCADE 则无需额外处理
return nil
}
// needUpdateChildren 根据配置决定是否需要更新子分类
func (l *DeleteCategoryLogic) needUpdateChildren() bool {
// 这里根据实际数据库外键约束配置返回
// 可以在 config 中添加配置项控制行为
return false // 默认假设是 ON DELETE CASCADE
}

View File

@ -0,0 +1,30 @@
package logic
import (
"context"
"godemo/category/category"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type GetAncestorPathLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetAncestorPathLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAncestorPathLogic {
return &GetAncestorPathLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *GetAncestorPathLogic) GetAncestorPath(in *category.GetAncestorPathRequest) (*category.CategoryPathResponse, error) {
// todo: add your logic here and delete this line
return &category.CategoryPathResponse{}, nil
}

View File

@ -0,0 +1,85 @@
package logic
import (
"context"
"errors"
"godemo/category/category"
"godemo/category/internal/model"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type GetCategoryLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCategoryLogic {
return &GetCategoryLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *GetCategoryLogic) GetCategory(in *category.GetCategoryRequest) (*category.CategoryInfoResponse, error) {
// 1. 参数校验
if in.Id == "" {
return nil, status.Error(codes.InvalidArgument, "分类ID不能为空")
}
// 2. 查询数据库
categoryData, err := l.svcCtx.CategoryModel.FindOne(l.ctx, in.Id)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
l.Logger.Errorf("分类不存在, ID: %s", in.Id)
return nil, status.Error(codes.NotFound, "分类不存在")
}
l.Logger.Errorf("数据库查询失败: %v", err)
return nil, status.Error(codes.Internal, "内部错误")
}
// 3. 转换响应格式
return l.convertToResponse(categoryData), nil
}
func (l *GetCategoryLogic) convertToResponse(c *model.Categories) *category.CategoryInfoResponse {
// 处理可能为空的字段
var alias, parentID, description string
if c.Alias.Valid {
alias = c.Alias.String
}
if c.ParentId.Valid {
parentID = c.ParentId.String
}
if c.Description.Valid {
description = c.Description.String
}
// 处理时间戳
var updatedAt int64
if c.UpdatedAt.Valid {
updatedAt = c.UpdatedAt.Time.Unix()
} else {
updatedAt = c.CreatedAt.Unix() // 如果未更新过,使用创建时间
}
return &category.CategoryInfoResponse{
Category: &category.CategoryInfo{
Id: c.Id,
SystemId: c.SystemId,
Name: c.Name,
Alias: alias,
ParentId: parentID,
Description: description,
CreatedAt: c.CreatedAt.Unix(),
UpdatedAt: updatedAt,
},
}
}

View File

@ -0,0 +1,31 @@
package logic
import (
"context"
"godemo/category/category"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type GetChildrenLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetChildrenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetChildrenLogic {
return &GetChildrenLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// 层级结构操作
func (l *GetChildrenLogic) GetChildren(in *category.GetChildrenRequest) (*category.CategoryListResponse, error) {
// todo: add your logic here and delete this line
return &category.CategoryListResponse{}, nil
}

View File

@ -0,0 +1,30 @@
package logic
import (
"context"
"godemo/category/category"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type GetTreeLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewGetTreeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetTreeLogic {
return &GetTreeLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *GetTreeLogic) GetTree(in *category.GetTreeRequest) (*category.CategoryTreeResponse, error) {
// todo: add your logic here and delete this line
return &category.CategoryTreeResponse{}, nil
}

View File

@ -0,0 +1,31 @@
package logic
import (
"context"
"godemo/category/category"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type ListCategoriesLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewListCategoriesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListCategoriesLogic {
return &ListCategoriesLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// 查询过滤
func (l *ListCategoriesLogic) ListCategories(in *category.ListCategoryRequest) (*category.CategoryListResponse, error) {
// todo: add your logic here and delete this line
return &category.CategoryListResponse{}, nil
}

View File

@ -0,0 +1,30 @@
package logic
import (
"context"
"godemo/category/category"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type MoveCategoryLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewMoveCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MoveCategoryLogic {
return &MoveCategoryLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *MoveCategoryLogic) MoveCategory(in *category.MoveCategoryRequest) (*category.CategoryInfoResponse, error) {
// todo: add your logic here and delete this line
return &category.CategoryInfoResponse{}, nil
}

View File

@ -0,0 +1,31 @@
package logic
import (
"context"
"godemo/category/category"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
)
type PingLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewPingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PingLogic {
return &PingLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
// 健康检查
func (l *PingLogic) Ping(in *category.PingRequest) (*category.PingResponse, error) {
// todo: add your logic here and delete this line
return &category.PingResponse{}, nil
}

View File

@ -0,0 +1,218 @@
package logic
import (
"context"
"database/sql"
"errors"
"fmt"
"time"
"godemo/category/category"
"godemo/category/internal/model"
"godemo/category/internal/svc"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type UpdateCategoryLogic struct {
ctx context.Context
svcCtx *svc.ServiceContext
logx.Logger
}
func NewUpdateCategoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateCategoryLogic {
return &UpdateCategoryLogic{
ctx: ctx,
svcCtx: svcCtx,
Logger: logx.WithContext(ctx),
}
}
func (l *UpdateCategoryLogic) UpdateCategory(in *category.UpdateCategoryRequest) (*category.CategoryInfoResponse, error) {
// 1. 参数校验
if err := l.validateRequest(in); err != nil {
return nil, err
}
// 2. 获取现有分类
existing, err := l.svcCtx.CategoryModel.FindOne(l.ctx, in.Id)
if err != nil {
return l.handleFindError(err, in.Id)
}
// 3. 检查更新后的名称/别名是否冲突
if err := l.checkUniqueness(in, existing); err != nil {
return nil, err
}
// 4. 构建更新模型
updatedCategory := l.buildUpdatedModel(in, existing)
// 5. 事务更新
if err := l.updateWithTransaction(updatedCategory); err != nil {
return nil, err
}
// 6. 清理缓存
// 7. 返回更新后的数据
return l.buildResponse(updatedCategory), nil
}
// 参数校验
func (l *UpdateCategoryLogic) validateRequest(in *category.UpdateCategoryRequest) error {
if in.Id == "" {
return status.Error(codes.InvalidArgument, "分类ID不能为空")
}
if in.Name == "" && in.Alias == "" && in.ParentId == "" && in.Description == "" {
return status.Error(codes.InvalidArgument, "至少需要提供一个更新字段")
}
return nil
}
// 处理查询错误
func (l *UpdateCategoryLogic) handleFindError(err error, id string) (*category.CategoryInfoResponse, error) {
if errors.Is(err, model.ErrNotFound) {
l.Logger.Errorf("分类不存在, ID: %s", id)
return nil, status.Error(codes.NotFound, "分类不存在")
}
l.Logger.Errorf("查询分类失败: %v", err)
return nil, status.Error(codes.Internal, "内部错误")
}
// 检查名称/别名唯一性
func (l *UpdateCategoryLogic) checkUniqueness(in *category.UpdateCategoryRequest, existing *model.Categories) error {
// 如果名称有修改,检查新名称是否冲突
if in.Name != "" && in.Name != existing.Name {
parentID := existing.ParentId
if in.ParentId != "" {
parentID = sql.NullString{String: in.ParentId, Valid: true}
}
_, err := l.svcCtx.CategoryModel.FindBySystemParentName(
l.ctx,
existing.SystemId,
parentID.String,
in.Name,
)
if err == nil {
return status.Error(codes.AlreadyExists, "分类名称已存在")
} else if !errors.Is(err, model.ErrNotFound) {
l.Logger.Errorf("名称唯一性检查失败: %v", err)
return status.Error(codes.Internal, "内部错误")
}
}
// 如果别名有修改,检查新别名是否冲突
if in.Alias != "" && in.Alias != existing.Alias.String {
parentID := existing.ParentId
if in.ParentId != "" {
parentID = sql.NullString{String: in.ParentId, Valid: true}
}
_, err := l.svcCtx.CategoryModel.FindBySystemParentAlias(
l.ctx,
existing.SystemId,
parentID.String,
in.Alias,
)
if err == nil {
return status.Error(codes.AlreadyExists, "分类别名已存在")
} else if !errors.Is(err, model.ErrNotFound) {
l.Logger.Errorf("别名唯一性检查失败: %v", err)
return status.Error(codes.Internal, "内部错误")
}
}
return nil
}
// 构建更新后的模型
func (l *UpdateCategoryLogic) buildUpdatedModel(in *category.UpdateCategoryRequest, existing *model.Categories) *model.Categories {
updated := *existing // 复制原有值
// 只更新提供的字段
if in.Name != "" {
updated.Name = in.Name
}
if in.Alias != "" {
updated.Alias = sql.NullString{String: in.Alias, Valid: true}
} else if in.Alias == "" && existing.Alias.Valid {
// 明确传递空字符串表示清空别名
updated.Alias = sql.NullString{Valid: false}
}
if in.ParentId != "" {
if in.ParentId == "NULL" { // 特殊值表示设为NULL
updated.ParentId = sql.NullString{Valid: false}
} else {
updated.ParentId = sql.NullString{String: in.ParentId, Valid: true}
}
}
if in.Description != "" {
updated.Description = sql.NullString{String: in.Description, Valid: true}
} else if in.Description == "" && existing.Description.Valid {
// 明确传递空字符串表示清空描述
updated.Description = sql.NullString{Valid: false}
}
updated.UpdatedAt = sql.NullTime{Time: time.Now(), Valid: true}
return &updated
}
// 事务更新
func (l *UpdateCategoryLogic) updateWithTransaction(updated *model.Categories) error {
return l.svcCtx.CategoryModel.Transact(l.ctx, func(ctx context.Context, session sqlx.Session) error {
// 检查父分类是否存在(如果修改了父分类)
if updated.ParentId.Valid && updated.ParentId.String != "" {
if _, err := l.svcCtx.CategoryModel.WithSession(session).FindOne(ctx, updated.ParentId.String); err != nil {
if errors.Is(err, model.ErrNotFound) {
return status.Error(codes.InvalidArgument, "指定的父分类不存在")
}
return fmt.Errorf("查询父分类失败: %w", err)
}
}
// 执行更新
if err := l.svcCtx.CategoryModel.WithSession(session).Update(ctx, updated); err != nil {
return fmt.Errorf("更新分类失败: %w", err)
}
return nil
})
}
// 构建响应
func (l *UpdateCategoryLogic) buildResponse(c *model.Categories) *category.CategoryInfoResponse {
resp := &category.CategoryInfoResponse{
Category: &category.CategoryInfo{
Id: c.Id,
SystemId: c.SystemId,
Name: c.Name,
CreatedAt: c.CreatedAt.Unix(),
},
}
// 处理可能为空的字段
if c.Alias.Valid {
resp.Category.Alias = c.Alias.String
}
if c.ParentId.Valid {
resp.Category.ParentId = c.ParentId.String
}
if c.Description.Valid {
resp.Category.Description = c.Description.String
}
if c.UpdatedAt.Valid {
resp.Category.UpdatedAt = c.UpdatedAt.Time.Unix()
} else {
resp.Category.UpdatedAt = c.CreatedAt.Unix()
}
return resp
}

View File

@ -0,0 +1,74 @@
package model
import (
"context"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var _ CategoriesModel = (*customCategoriesModel)(nil)
type (
// CategoriesModel is an interface to be customized, add more methods here,
// and implement the added methods in customCategoriesModel.
CategoriesModel interface {
categoriesModel
WithSession(session sqlx.Session) CategoriesModel
Transact(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error
FindBySystemParentName(ctx context.Context, systemID string, parentID string, name string) (*Categories, error)
FindBySystemParentAlias(ctx context.Context, systemID string, parentID string, alias string) (*Categories, error)
}
customCategoriesModel struct {
*defaultCategoriesModel
}
)
// NewCategoriesModel returns a model for the database table.
func NewCategoriesModel(conn sqlx.SqlConn) CategoriesModel {
return &customCategoriesModel{
defaultCategoriesModel: newCategoriesModel(conn),
}
}
func (m *customCategoriesModel) WithSession(session sqlx.Session) CategoriesModel {
return NewCategoriesModel(sqlx.NewSqlConnFromSession(session))
}
func (m *customCategoriesModel) Transact(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error {
return m.conn.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
return fn(ctx, session)
})
}
// 根据 system_id + parent_id + name 查询
func (m *customCategoriesModel) FindBySystemParentName(ctx context.Context, systemID string, parentID string, name string) (*Categories, error) {
query := `
SELECT * FROM categories
WHERE system_id = $1
AND COALESCE(parent_id, '') = COALESCE($2, '')
AND name = $3
`
var resp Categories
err := m.conn.QueryRowCtx(ctx, &resp, query, systemID, parentID, name)
if err != nil {
return nil, err
}
return &resp, nil
}
// 根据 system_id + parent_id + alias 查询
func (m *customCategoriesModel) FindBySystemParentAlias(ctx context.Context, systemID string, parentID string, alias string) (*Categories, error) {
query := `
SELECT * FROM categories
WHERE system_id = $1
AND COALESCE(parent_id, '') = COALESCE($2, '')
AND alias = $3
`
var resp Categories
err := m.conn.QueryRowCtx(ctx, &resp, query, systemID, parentID, alias)
if err != nil {
return nil, err
}
return &resp, nil
}

View File

@ -0,0 +1,122 @@
// Code generated by goctl. DO NOT EDIT.
// versions:
// goctl version: 1.8.3
package model
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/stringx"
)
var (
categoriesFieldNames = builder.RawFieldNames(&Categories{}, true)
categoriesRows = strings.Join(categoriesFieldNames, ",")
categoriesRowsExpectAutoSet = strings.Join(stringx.Remove(categoriesFieldNames, "create_at", "create_time", "created_at", "update_at", "update_time", "updated_at"), ",")
categoriesRowsWithPlaceHolder = builder.PostgreSqlJoin(stringx.Remove(categoriesFieldNames, "id", "create_at", "create_time", "created_at", "update_at", "update_time", "updated_at"))
)
type (
categoriesModel interface {
Insert(ctx context.Context, data *Categories) (sql.Result, error)
FindOne(ctx context.Context, id string) (*Categories, error)
FindOneBySystemIdParentIdAlias(ctx context.Context, systemId string, parentId sql.NullString, alias sql.NullString) (*Categories, error)
FindOneBySystemIdParentIdName(ctx context.Context, systemId string, parentId sql.NullString, name string) (*Categories, error)
Update(ctx context.Context, data *Categories) error
Delete(ctx context.Context, id string) error
}
defaultCategoriesModel struct {
conn sqlx.SqlConn
table string
}
Categories struct {
Id string `db:"id"`
SystemId string `db:"system_id"`
Name string `db:"name"`
Alias sql.NullString `db:"alias"`
ParentId sql.NullString `db:"parent_id"`
Description sql.NullString `db:"description"`
CreatedAt time.Time `db:"created_at"`
UpdatedAt sql.NullTime `db:"updated_at"`
}
)
func newCategoriesModel(conn sqlx.SqlConn) *defaultCategoriesModel {
return &defaultCategoriesModel{
conn: conn,
table: `"public"."categories"`,
}
}
func (m *defaultCategoriesModel) Delete(ctx context.Context, id string) error {
query := fmt.Sprintf("delete from %s where id = $1", m.table)
_, err := m.conn.ExecCtx(ctx, query, id)
return err
}
func (m *defaultCategoriesModel) FindOne(ctx context.Context, id string) (*Categories, error) {
query := fmt.Sprintf("select %s from %s where id = $1 limit 1", categoriesRows, m.table)
var resp Categories
err := m.conn.QueryRowCtx(ctx, &resp, query, id)
switch err {
case nil:
return &resp, nil
case sqlx.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultCategoriesModel) FindOneBySystemIdParentIdAlias(ctx context.Context, systemId string, parentId sql.NullString, alias sql.NullString) (*Categories, error) {
var resp Categories
query := fmt.Sprintf("select %s from %s where system_id = $1 and parent_id = $2 and alias = $3 limit 1", categoriesRows, m.table)
err := m.conn.QueryRowCtx(ctx, &resp, query, systemId, parentId, alias)
switch err {
case nil:
return &resp, nil
case sqlx.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultCategoriesModel) FindOneBySystemIdParentIdName(ctx context.Context, systemId string, parentId sql.NullString, name string) (*Categories, error) {
var resp Categories
query := fmt.Sprintf("select %s from %s where system_id = $1 and parent_id = $2 and name = $3 limit 1", categoriesRows, m.table)
err := m.conn.QueryRowCtx(ctx, &resp, query, systemId, parentId, name)
switch err {
case nil:
return &resp, nil
case sqlx.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultCategoriesModel) Insert(ctx context.Context, data *Categories) (sql.Result, error) {
query := fmt.Sprintf("insert into %s (%s) values ($1, $2, $3, $4, $5, $6)", m.table, categoriesRowsExpectAutoSet)
ret, err := m.conn.ExecCtx(ctx, query, data.Id, data.SystemId, data.Name, data.Alias, data.ParentId, data.Description)
return ret, err
}
func (m *defaultCategoriesModel) Update(ctx context.Context, newData *Categories) error {
query := fmt.Sprintf("update %s set %s where id = $1", m.table, categoriesRowsWithPlaceHolder)
_, err := m.conn.ExecCtx(ctx, query, newData.Id, newData.SystemId, newData.Name, newData.Alias, newData.ParentId, newData.Description)
return err
}
func (m *defaultCategoriesModel) tableName() string {
return m.table
}

View File

@ -0,0 +1,5 @@
package model
import "github.com/zeromicro/go-zero/core/stores/sqlx"
var ErrNotFound = sqlx.ErrNotFound

View File

@ -0,0 +1,94 @@
// Code generated by goctl. DO NOT EDIT.
// goctl 1.8.3
// Source: category.proto
package server
import (
"context"
"godemo/category/category"
"godemo/category/internal/logic"
"godemo/category/internal/svc"
)
type CategoryServer struct {
svcCtx *svc.ServiceContext
category.UnimplementedCategoryServer
}
func NewCategoryServer(svcCtx *svc.ServiceContext) *CategoryServer {
return &CategoryServer{
svcCtx: svcCtx,
}
}
// 健康检查
func (s *CategoryServer) Ping(ctx context.Context, in *category.PingRequest) (*category.PingResponse, error) {
l := logic.NewPingLogic(ctx, s.svcCtx)
return l.Ping(in)
}
// 分类基础操作
func (s *CategoryServer) CreateCategory(ctx context.Context, in *category.CreateCategoryRequest) (*category.CategoryInfoResponse, error) {
l := logic.NewCreateCategoryLogic(ctx, s.svcCtx)
return l.CreateCategory(in)
}
func (s *CategoryServer) UpdateCategory(ctx context.Context, in *category.UpdateCategoryRequest) (*category.CategoryInfoResponse, error) {
l := logic.NewUpdateCategoryLogic(ctx, s.svcCtx)
return l.UpdateCategory(in)
}
func (s *CategoryServer) DeleteCategory(ctx context.Context, in *category.DeleteCategoryRequest) (*category.DeleteResponse, error) {
l := logic.NewDeleteCategoryLogic(ctx, s.svcCtx)
return l.DeleteCategory(in)
}
func (s *CategoryServer) GetCategory(ctx context.Context, in *category.GetCategoryRequest) (*category.CategoryInfoResponse, error) {
l := logic.NewGetCategoryLogic(ctx, s.svcCtx)
return l.GetCategory(in)
}
// 层级结构操作
func (s *CategoryServer) GetChildren(ctx context.Context, in *category.GetChildrenRequest) (*category.CategoryListResponse, error) {
l := logic.NewGetChildrenLogic(ctx, s.svcCtx)
return l.GetChildren(in)
}
func (s *CategoryServer) GetTree(ctx context.Context, in *category.GetTreeRequest) (*category.CategoryTreeResponse, error) {
l := logic.NewGetTreeLogic(ctx, s.svcCtx)
return l.GetTree(in)
}
func (s *CategoryServer) MoveCategory(ctx context.Context, in *category.MoveCategoryRequest) (*category.CategoryInfoResponse, error) {
l := logic.NewMoveCategoryLogic(ctx, s.svcCtx)
return l.MoveCategory(in)
}
func (s *CategoryServer) GetAncestorPath(ctx context.Context, in *category.GetAncestorPathRequest) (*category.CategoryPathResponse, error) {
l := logic.NewGetAncestorPathLogic(ctx, s.svcCtx)
return l.GetAncestorPath(in)
}
// 批量操作
func (s *CategoryServer) BatchCreateCategories(ctx context.Context, in *category.BatchCreateRequest) (*category.BatchCreateResponse, error) {
l := logic.NewBatchCreateCategoriesLogic(ctx, s.svcCtx)
return l.BatchCreateCategories(in)
}
func (s *CategoryServer) BatchUpdateCategories(ctx context.Context, in *category.BatchUpdateRequest) (*category.BatchUpdateResponse, error) {
l := logic.NewBatchUpdateCategoriesLogic(ctx, s.svcCtx)
return l.BatchUpdateCategories(in)
}
// 查询过滤
func (s *CategoryServer) ListCategories(ctx context.Context, in *category.ListCategoryRequest) (*category.CategoryListResponse, error) {
l := logic.NewListCategoriesLogic(ctx, s.svcCtx)
return l.ListCategories(in)
}
func (s *CategoryServer) CheckAlias(ctx context.Context, in *category.CheckAliasRequest) (*category.CheckAliasResponse, error) {
l := logic.NewCheckAliasLogic(ctx, s.svcCtx)
return l.CheckAlias(in)
}

View File

@ -0,0 +1,22 @@
package svc
import (
"godemo/category/internal/config"
"godemo/category/internal/model"
_ "github.com/lib/pq"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type ServiceContext struct {
Config config.Config
CategoryModel model.CategoriesModel
}
func NewServiceContext(c config.Config) *ServiceContext {
conn := sqlx.NewSqlConn("postgres", c.DB.DataSource)
return &ServiceContext{
Config: c,
CategoryModel: model.NewCategoriesModel(conn),
}
}