diff --git a/repository/region.go b/repository/region.go new file mode 100644 index 0000000..70785db --- /dev/null +++ b/repository/region.go @@ -0,0 +1,111 @@ +package repository + +import ( + "electricity_bill_calc/cache" + "electricity_bill_calc/global" + "electricity_bill_calc/logger" + "electricity_bill_calc/model" + + "github.com/doug-martin/goqu/v9" + _ "github.com/doug-martin/goqu/v9/dialect/postgres" + "github.com/georgysavva/scany/v2/pgxscan" + "go.uber.org/zap" +) + +type _RegionRepository struct { + log *zap.Logger + ds goqu.DialectWrapper +} + +var RegionRepository = _RegionRepository{ + log: logger.Named("Repository", "Region"), + ds: goqu.Dialect("postgres"), +} + +// 获取指定行政区划下所有直接子级行政区划 +func (r *_RegionRepository) FindSubRegions(parent string) ([]model.Region, error) { + r.log.Info("获取指定行政区划下所有直接子级行政区划", zap.String("parent", parent)) + cacheConditions := []string{ + "parent", parent, + } + if regions, err := cache.RetrieveSearch[[]model.Region]("region", cacheConditions...); err == nil && regions != nil { + r.log.Info("已经从缓存获取到了指定的子级行政区划。") + return *regions, nil + } + + ctx, cancel := global.TimeoutContext() + defer cancel() + + var regions []model.Region + regionQuerySql, regionParams, _ := r.ds. + From("region"). + Where(goqu.Ex{"parent": parent}). + Prepared(true).ToSQL() + if err := pgxscan.Select(ctx, global.DB, ®ions, regionQuerySql, regionParams...); err != nil { + r.log.Error("获取指定行政区划下所有直接子级行政区划失败!", zap.Error(err)) + return nil, err + } + if len(regions) > 0 { + cache.CacheSearch(regions, []string{"region"}, "region", cacheConditions...) + } + + return regions, nil +} + +// 获取一个指定编号的行政区划详细信息 +func (r *_RegionRepository) FindRegion(code string) (*model.Region, error) { + r.log.Info("获取指定行政区划信息", zap.String("code", code)) + if region, err := cache.RetrieveEntity[model.Region]("region", code); err == nil && region != nil { + r.log.Info("已经从缓存获取到了指定的行政区划详细信息。") + return region, nil + } + + ctx, cancel := global.TimeoutContext() + defer cancel() + + var region model.Region + regionQuerySql, regionParams, _ := r.ds. + From("region"). + Where(goqu.Ex{"code": code}). + Prepared(true).ToSQL() + + if err := pgxscan.Get(ctx, global.DB, ®ion, regionQuerySql, regionParams...); err != nil { + r.log.Error("获取指定行政区划信息失败!", zap.Error(err)) + return nil, err + } + + cache.CacheEntity(region, []string{"region"}, "region", code) + return ®ion, nil +} + +// 获取指定行政区划的所有直接和非直接父级 +func (r *_RegionRepository) FindParentRegions(code string) ([]*model.Region, error) { + r.log.Info("获取指定行政区划的所有直接和非直接父级", zap.String("code", code)) + cacheConditions := []string{ + "parent", code, + } + if regions, err := cache.RetrieveSearch[[]*model.Region]("region", cacheConditions...); err == nil && regions != nil { + r.log.Info("已经从缓存获取到了指定的父级行政区划。") + return *regions, nil + } + + var ( + regionsScanTask = []string{code} + regions = make([]*model.Region, 0) + ) + for len(regionsScanTask) > 0 { + region, err := r.FindRegion(regionsScanTask[0]) + regionsScanTask = append([]string{}, regionsScanTask[1:]...) + if err == nil && region != nil { + regions = append(regions, region) + if region.Parent != "0" { + regionsScanTask = append(regionsScanTask, region.Parent) + } + } + } + + if len(regions) > 0 { + cache.CacheSearch(regions, []string{"region"}, "region", cacheConditions...) + } + return regions, nil +}