This commit is contained in:
Asim Aslam
2020-10-02 11:13:01 +01:00
commit 61fe9c169b
62 changed files with 4428 additions and 0 deletions

7
blog/README.md Normal file
View File

@@ -0,0 +1,7 @@
# Blog
This is a full end to end example of writing a multi-service blog application
## Usage
Check out the [blog tutorial](https://m3o.dev/building-a-blog) on the developer docs.

2
blog/comments/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
comment-service

3
blog/comments/Dockerfile Normal file
View File

@@ -0,0 +1,3 @@
FROM alpine
ADD comments-service /comments-service
ENTRYPOINT [ "/comments-service" ]

22
blog/comments/Makefile Normal file
View File

@@ -0,0 +1,22 @@
GOPATH:=$(shell go env GOPATH)
MODIFY=Mgithub.com/micro/go-micro/api/proto/api.proto=github.com/micro/go-micro/v3/api/proto
.PHONY: proto
proto:
protoc --proto_path=. --micro_out=${MODIFY}:. --go_out=${MODIFY}:. proto/comments/comments.proto
.PHONY: build
build: proto
go build -o comments-service *.go
.PHONY: test
test:
go test -v ./... -cover
.PHONY: docker
docker:
docker build . -t comments-service:latest

3
blog/comments/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Comments Service
Still yet to implement

View File

@@ -0,0 +1,3 @@
package main
//go:generate make proto

View File

@@ -0,0 +1,16 @@
package handler
import (
"context"
"github.com/micro/micro/v3/service/logger"
pb "github.com/micro/services/blog/comments/proto"
)
type Comments struct{}
// Call is a single request handler called via client.Call or the generated client code
func (c *Comments) Save(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
logger.Info("Not yet implemented")
return nil
}

22
blog/comments/main.go Normal file
View File

@@ -0,0 +1,22 @@
package main
import (
"github.com/micro/micro/v3/service"
"github.com/micro/micro/v3/service/logger"
"github.com/micro/services/blog/comments/handler"
)
func main() {
// Create the service
srv := service.New(
service.Name("comments"),
)
// Register Handler
srv.Handle(new(handler.Comments))
// Run service
if err := srv.Run(); err != nil {
logger.Fatal(err)
}
}

View File

@@ -0,0 +1,218 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.22.0
// protoc v3.11.4
// source: github.com/micro/services/blog/comments/proto/comments.proto
package comments
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Request struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// post to comment on
PostId string `protobuf:"bytes,1,opt,name=post_id,json=postId,proto3" json:"post_id,omitempty"`
// message to leave
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *Request) Reset() {
*x = Request{}
if protoimpl.UnsafeEnabled {
mi := &file_github_com_micro_services_blog_comments_proto_comments_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Request) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Request) ProtoMessage() {}
func (x *Request) ProtoReflect() protoreflect.Message {
mi := &file_github_com_micro_services_blog_comments_proto_comments_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Request.ProtoReflect.Descriptor instead.
func (*Request) Descriptor() ([]byte, []int) {
return file_github_com_micro_services_blog_comments_proto_comments_proto_rawDescGZIP(), []int{0}
}
func (x *Request) GetPostId() string {
if x != nil {
return x.PostId
}
return ""
}
func (x *Request) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
type Response struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *Response) Reset() {
*x = Response{}
if protoimpl.UnsafeEnabled {
mi := &file_github_com_micro_services_blog_comments_proto_comments_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Response) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Response) ProtoMessage() {}
func (x *Response) ProtoReflect() protoreflect.Message {
mi := &file_github_com_micro_services_blog_comments_proto_comments_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Response.ProtoReflect.Descriptor instead.
func (*Response) Descriptor() ([]byte, []int) {
return file_github_com_micro_services_blog_comments_proto_comments_proto_rawDescGZIP(), []int{1}
}
var File_github_com_micro_services_blog_comments_proto_comments_proto protoreflect.FileDescriptor
var file_github_com_micro_services_blog_comments_proto_comments_proto_rawDesc = []byte{
0x0a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69, 0x63,
0x72, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x62, 0x6c, 0x6f, 0x67,
0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08,
0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3c, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x0a, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x32, 0x3b, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2f,
0x0a, 0x04, 0x53, 0x61, 0x76, 0x65, 0x12, 0x11, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74,
0x73, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x65, 0x6e, 0x74, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_github_com_micro_services_blog_comments_proto_comments_proto_rawDescOnce sync.Once
file_github_com_micro_services_blog_comments_proto_comments_proto_rawDescData = file_github_com_micro_services_blog_comments_proto_comments_proto_rawDesc
)
func file_github_com_micro_services_blog_comments_proto_comments_proto_rawDescGZIP() []byte {
file_github_com_micro_services_blog_comments_proto_comments_proto_rawDescOnce.Do(func() {
file_github_com_micro_services_blog_comments_proto_comments_proto_rawDescData = protoimpl.X.CompressGZIP(file_github_com_micro_services_blog_comments_proto_comments_proto_rawDescData)
})
return file_github_com_micro_services_blog_comments_proto_comments_proto_rawDescData
}
var file_github_com_micro_services_blog_comments_proto_comments_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_github_com_micro_services_blog_comments_proto_comments_proto_goTypes = []interface{}{
(*Request)(nil), // 0: comments.Request
(*Response)(nil), // 1: comments.Response
}
var file_github_com_micro_services_blog_comments_proto_comments_proto_depIdxs = []int32{
0, // 0: comments.Comments.Save:input_type -> comments.Request
1, // 1: comments.Comments.Save:output_type -> comments.Response
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_github_com_micro_services_blog_comments_proto_comments_proto_init() }
func file_github_com_micro_services_blog_comments_proto_comments_proto_init() {
if File_github_com_micro_services_blog_comments_proto_comments_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_github_com_micro_services_blog_comments_proto_comments_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Request); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_github_com_micro_services_blog_comments_proto_comments_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Response); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_github_com_micro_services_blog_comments_proto_comments_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_github_com_micro_services_blog_comments_proto_comments_proto_goTypes,
DependencyIndexes: file_github_com_micro_services_blog_comments_proto_comments_proto_depIdxs,
MessageInfos: file_github_com_micro_services_blog_comments_proto_comments_proto_msgTypes,
}.Build()
File_github_com_micro_services_blog_comments_proto_comments_proto = out.File
file_github_com_micro_services_blog_comments_proto_comments_proto_rawDesc = nil
file_github_com_micro_services_blog_comments_proto_comments_proto_goTypes = nil
file_github_com_micro_services_blog_comments_proto_comments_proto_depIdxs = nil
}

View File

@@ -0,0 +1,93 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: github.com/micro/services/blog/comments/proto/comments.proto
package comments
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
api "github.com/micro/go-micro/v3/api"
client "github.com/micro/go-micro/v3/client"
server "github.com/micro/go-micro/v3/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Comments service
func NewCommentsEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Comments service
type CommentsService interface {
Save(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
}
type commentsService struct {
c client.Client
name string
}
func NewCommentsService(name string, c client.Client) CommentsService {
return &commentsService{
c: c,
name: name,
}
}
func (c *commentsService) Save(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
req := c.c.NewRequest(c.name, "Comments.Save", in)
out := new(Response)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Comments service
type CommentsHandler interface {
Save(context.Context, *Request, *Response) error
}
func RegisterCommentsHandler(s server.Server, hdlr CommentsHandler, opts ...server.HandlerOption) error {
type comments interface {
Save(ctx context.Context, in *Request, out *Response) error
}
type Comments struct {
comments
}
h := &commentsHandler{hdlr}
return s.Handle(s.NewHandler(&Comments{h}, opts...))
}
type commentsHandler struct {
CommentsHandler
}
func (h *commentsHandler) Save(ctx context.Context, in *Request, out *Response) error {
return h.CommentsHandler.Save(ctx, in, out)
}

View File

@@ -0,0 +1,17 @@
syntax = "proto3";
package comments;
service Comments {
rpc Save(Request) returns (Response) {}
}
message Request {
// post to comment on
string post_id = 1;
// message to leave
string message = 2;
}
message Response {}

2
blog/posts/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
./posts

3
blog/posts/Dockerfile Normal file
View File

@@ -0,0 +1,3 @@
FROM alpine
ADD post-service /post-service
ENTRYPOINT [ "/post-service" ]

22
blog/posts/Makefile Normal file
View File

@@ -0,0 +1,22 @@
GOPATH:=$(shell go env GOPATH)
MODIFY=Mgithub.com/micro/go-micro/api/proto/api.proto=github.com/micro/go-micro/v3/api/proto
.PHONY: proto
proto:
protoc --proto_path=. --micro_out=${MODIFY}:. --go_out=${MODIFY}:. proto/post/post.proto
.PHONY: build
build: proto
go build -o post-service *.go
.PHONY: test
test:
go test -v ./... -cover
.PHONY: docker
docker:
docker build . -t post-service:latest

32
blog/posts/README.md Normal file
View File

@@ -0,0 +1,32 @@
# Post Service
The posts service stores posts
## Usage
### Create a post
```
micro call posts Posts.Save '{"post":{"id":"1","title":"How to Micro","content":"Simply put, Micro is awesome."}}'
micro call posts Posts.Save '{"post":{"id":"2","title":"Fresh posts are fresh","content":"This post is fresher than the How to Micro one"}}'
```
### Create a post with tags
```
micro call posts Posts.Save '{"post":{"id":"3","title":"How to do epic things with Micro","content":"Everything is awesome.","tagNames":["a","b"]}}'
```
### Query posts
```
micro call posts Posts.Query '{}'
micro call posts Posts.Query '{"slug":"how-to-micro"}'
micro call posts Posts.Query '{"offset": 10, "limit": 10}'
```
### Delete posts
```
micro call posts Posts.Delete '{"offset": 10, "limit": 10}'
```

3
blog/posts/generate.go Normal file
View File

@@ -0,0 +1,3 @@
package main
//go:generate make proto

258
blog/posts/handler/posts.go Normal file
View File

@@ -0,0 +1,258 @@
package handler
import (
"context"
"encoding/json"
"fmt"
"math"
"time"
"github.com/micro/go-micro/v3/errors"
gostore "github.com/micro/go-micro/v3/store"
"github.com/micro/micro/v3/service/logger"
"github.com/micro/micro/v3/service/store"
"github.com/gosimple/slug"
pb "github.com/micro/services/blog/posts/proto/posts"
posts "github.com/micro/services/blog/posts/proto/posts"
tags "github.com/micro/services/blog/tags/proto"
)
const (
tagType = "post-tag"
slugPrefix = "slug"
idPrefix = "id"
timeStampPrefix = "timestamp"
)
type Post struct {
ID string `json:"id"`
Title string `json:"title"`
Slug string `json:"slug"`
Content string `json:"content"`
CreateTimestamp int64 `json:"create_timestamp"`
UpdateTimestamp int64 `json:"update_timestamp"`
TagNames []string `json:"tagNames"`
}
type Posts struct {
Tags tags.TagsService
}
func (p *Posts) Save(ctx context.Context, req *posts.SaveRequest, rsp *posts.SaveResponse) error {
if len(req.Post.Id) == 0 || len(req.Post.Title) == 0 || len(req.Post.Content) == 0 {
return errors.BadRequest("posts.save.input-check", "Id, title or content is missing")
}
// read by post
records, err := store.Read(fmt.Sprintf("%v:%v", idPrefix, req.Post.Id))
if err != nil && err != gostore.ErrNotFound {
return errors.InternalServerError("posts.save.store-id-read", "Failed to read post by id: %v", err.Error())
}
postSlug := slug.Make(req.Post.Title)
// If no existing record is found, create a new one
if len(records) == 0 {
post := &Post{
ID: req.Post.Id,
Title: req.Post.Title,
Content: req.Post.Content,
TagNames: req.Post.TagNames,
Slug: postSlug,
CreateTimestamp: time.Now().Unix(),
}
err := p.savePost(ctx, nil, post)
if err != nil {
return errors.InternalServerError("posts.save.post-save", "Failed to save new post: %v", err.Error())
}
return nil
}
record := records[0]
oldPost := &Post{}
err = json.Unmarshal(record.Value, oldPost)
if err != nil {
return errors.InternalServerError("posts.save.unmarshal", "Failed to unmarshal old post: %v", err.Error())
}
post := &Post{
ID: req.Post.Id,
Title: req.Post.Title,
Content: req.Post.Content,
Slug: postSlug,
TagNames: req.Post.TagNames,
CreateTimestamp: oldPost.CreateTimestamp,
UpdateTimestamp: time.Now().Unix(),
}
// Check if slug exists
recordsBySlug, err := store.Read(fmt.Sprintf("%v:%v", slugPrefix, postSlug))
if err != nil && err != gostore.ErrNotFound {
return errors.InternalServerError("posts.save.store-read", "Failed to read post by slug: %v", err.Error())
}
otherSlugPost := &Post{}
err = json.Unmarshal(record.Value, otherSlugPost)
if err != nil {
return errors.InternalServerError("posts.save.slug-unmarshal", "Error unmarshaling other post with same slug: %v", err.Error())
}
if len(recordsBySlug) > 0 && oldPost.ID != otherSlugPost.ID {
return errors.BadRequest("posts.save.slug-check", "An other post with this slug already exists")
}
return p.savePost(ctx, oldPost, post)
}
func (p *Posts) savePost(ctx context.Context, oldPost, post *Post) error {
bytes, err := json.Marshal(post)
if err != nil {
return err
}
err = store.Write(&gostore.Record{
Key: fmt.Sprintf("%v:%v", idPrefix, post.ID),
Value: bytes,
})
if err != nil {
return err
}
// Delete old slug index if the slug has changed
if oldPost != nil && oldPost.Slug != post.Slug {
err = store.Delete(fmt.Sprintf("%v:%v", slugPrefix, post.Slug))
if err != nil {
return err
}
}
err = store.Write(&gostore.Record{
Key: fmt.Sprintf("%v:%v", slugPrefix, post.Slug),
Value: bytes,
})
if err != nil {
return err
}
err = store.Write(&gostore.Record{
Key: fmt.Sprintf("%v:%v", timeStampPrefix, math.MaxInt64-post.CreateTimestamp),
Value: bytes,
})
if err != nil {
return err
}
if oldPost == nil {
for _, tagName := range post.TagNames {
_, err := p.Tags.IncreaseCount(ctx, &tags.IncreaseCountRequest{
ParentID: post.ID,
Type: tagType,
Title: tagName,
})
if err != nil {
return err
}
}
return nil
}
return p.diffTags(ctx, post.ID, oldPost.TagNames, post.TagNames)
}
func (p *Posts) diffTags(ctx context.Context, parentID string, oldTagNames, newTagNames []string) error {
oldTags := map[string]struct{}{}
for _, v := range oldTagNames {
oldTags[v] = struct{}{}
}
newTags := map[string]struct{}{}
for _, v := range newTagNames {
newTags[v] = struct{}{}
}
for i := range oldTags {
_, stillThere := newTags[i]
if !stillThere {
_, err := p.Tags.DecreaseCount(ctx, &tags.DecreaseCountRequest{
ParentID: parentID,
Type: tagType,
Title: i,
})
if err != nil {
logger.Errorf("Error decreasing count for tag '%v' with type '%v' for parent '%v'", i, tagType, parentID)
}
}
}
for i := range newTags {
_, newlyAdded := oldTags[i]
if newlyAdded {
_, err := p.Tags.IncreaseCount(ctx, &tags.IncreaseCountRequest{
ParentID: parentID,
Type: tagType,
Title: i,
})
if err != nil {
logger.Errorf("Error increasing count for tag '%v' with type '%v' for parent '%v'", i, tagType, parentID)
}
}
}
return nil
}
func (p *Posts) Query(ctx context.Context, req *pb.QueryRequest, rsp *pb.QueryResponse) error {
var records []*gostore.Record
var err error
if len(req.Slug) > 0 {
key := fmt.Sprintf("%v:%v", slugPrefix, req.Slug)
logger.Infof("Reading post by slug: %v", req.Slug)
records, err = store.Read("", store.Prefix(key))
} else {
key := fmt.Sprintf("%v:", timeStampPrefix)
var limit uint
limit = 20
if req.Limit > 0 {
limit = uint(req.Limit)
}
logger.Infof("Listing posts, offset: %v, limit: %v", req.Offset, limit)
records, err = store.Read("", store.Prefix(key),
store.Offset(uint(req.Offset)),
store.Limit(limit))
}
if err != nil {
return errors.BadRequest("posts.query.store-read", "Failed to read from store: %v", err.Error())
}
rsp.Posts = make([]*pb.Post, len(records))
for i, record := range records {
postRecord := &Post{}
err := json.Unmarshal(record.Value, postRecord)
if err != nil {
return errors.InternalServerError("posts.save.unmarshal", "Failed to unmarshal old post: %v", err.Error())
}
rsp.Posts[i] = &pb.Post{
Id: postRecord.ID,
Title: postRecord.Title,
Slug: postRecord.Slug,
Content: postRecord.Content,
TagNames: postRecord.TagNames,
}
}
return nil
}
func (p *Posts) Delete(ctx context.Context, req *pb.DeleteRequest, rsp *pb.DeleteResponse) error {
logger.Info("Received Post.Delete request")
records, err := store.Read(fmt.Sprintf("%v:%v", idPrefix, req.Id))
if err != nil && err != gostore.ErrNotFound {
return err
}
if len(records) == 0 {
return fmt.Errorf("Post with ID %v not found", req.Id)
}
post := &Post{}
err = json.Unmarshal(records[0].Value, post)
if err != nil {
return err
}
// Delete by ID
err = store.Delete(fmt.Sprintf("%v:%v", idPrefix, post.ID))
if err != nil {
return err
}
// Delete by slug
err = store.Delete(fmt.Sprintf("%v:%v", slugPrefix, post.Slug))
if err != nil {
return err
}
// Delete by timeStamp
return store.Delete(fmt.Sprintf("%v:%v", timeStampPrefix, post.CreateTimestamp))
}

25
blog/posts/main.go Normal file
View File

@@ -0,0 +1,25 @@
package main
import (
"github.com/micro/micro/v3/service"
"github.com/micro/micro/v3/service/logger"
"github.com/micro/services/blog/posts/handler"
tags "github.com/micro/services/blog/tags/proto"
)
func main() {
// Create the service
srv := service.New(
service.Name("posts"),
)
// Register Handler
srv.Handle(&handler.Posts{
Tags: tags.NewTagsService("tags", srv.Client()),
})
// Run service
if err := srv.Run(); err != nil {
logger.Fatal(err)
}
}

View File

@@ -0,0 +1,380 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: blog/posts/proto/posts/post.proto
package posts
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Post struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
Slug string `protobuf:"bytes,3,opt,name=slug,proto3" json:"slug,omitempty"`
Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"`
Timestamp int64 `protobuf:"varint,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
TagNames []string `protobuf:"bytes,6,rep,name=tagNames,proto3" json:"tagNames,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Post) Reset() { *m = Post{} }
func (m *Post) String() string { return proto.CompactTextString(m) }
func (*Post) ProtoMessage() {}
func (*Post) Descriptor() ([]byte, []int) {
return fileDescriptor_2d32cca1c2f74735, []int{0}
}
func (m *Post) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Post.Unmarshal(m, b)
}
func (m *Post) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Post.Marshal(b, m, deterministic)
}
func (m *Post) XXX_Merge(src proto.Message) {
xxx_messageInfo_Post.Merge(m, src)
}
func (m *Post) XXX_Size() int {
return xxx_messageInfo_Post.Size(m)
}
func (m *Post) XXX_DiscardUnknown() {
xxx_messageInfo_Post.DiscardUnknown(m)
}
var xxx_messageInfo_Post proto.InternalMessageInfo
func (m *Post) GetId() string {
if m != nil {
return m.Id
}
return ""
}
func (m *Post) GetTitle() string {
if m != nil {
return m.Title
}
return ""
}
func (m *Post) GetSlug() string {
if m != nil {
return m.Slug
}
return ""
}
func (m *Post) GetContent() string {
if m != nil {
return m.Content
}
return ""
}
func (m *Post) GetTimestamp() int64 {
if m != nil {
return m.Timestamp
}
return 0
}
func (m *Post) GetTagNames() []string {
if m != nil {
return m.TagNames
}
return nil
}
type QueryRequest struct {
Slug string `protobuf:"bytes,1,opt,name=slug,proto3" json:"slug,omitempty"`
Offset int64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
Limit int64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *QueryRequest) Reset() { *m = QueryRequest{} }
func (m *QueryRequest) String() string { return proto.CompactTextString(m) }
func (*QueryRequest) ProtoMessage() {}
func (*QueryRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_2d32cca1c2f74735, []int{1}
}
func (m *QueryRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_QueryRequest.Unmarshal(m, b)
}
func (m *QueryRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_QueryRequest.Marshal(b, m, deterministic)
}
func (m *QueryRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_QueryRequest.Merge(m, src)
}
func (m *QueryRequest) XXX_Size() int {
return xxx_messageInfo_QueryRequest.Size(m)
}
func (m *QueryRequest) XXX_DiscardUnknown() {
xxx_messageInfo_QueryRequest.DiscardUnknown(m)
}
var xxx_messageInfo_QueryRequest proto.InternalMessageInfo
func (m *QueryRequest) GetSlug() string {
if m != nil {
return m.Slug
}
return ""
}
func (m *QueryRequest) GetOffset() int64 {
if m != nil {
return m.Offset
}
return 0
}
func (m *QueryRequest) GetLimit() int64 {
if m != nil {
return m.Limit
}
return 0
}
type QueryResponse struct {
Posts []*Post `protobuf:"bytes,1,rep,name=posts,proto3" json:"posts,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *QueryResponse) Reset() { *m = QueryResponse{} }
func (m *QueryResponse) String() string { return proto.CompactTextString(m) }
func (*QueryResponse) ProtoMessage() {}
func (*QueryResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_2d32cca1c2f74735, []int{2}
}
func (m *QueryResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_QueryResponse.Unmarshal(m, b)
}
func (m *QueryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_QueryResponse.Marshal(b, m, deterministic)
}
func (m *QueryResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_QueryResponse.Merge(m, src)
}
func (m *QueryResponse) XXX_Size() int {
return xxx_messageInfo_QueryResponse.Size(m)
}
func (m *QueryResponse) XXX_DiscardUnknown() {
xxx_messageInfo_QueryResponse.DiscardUnknown(m)
}
var xxx_messageInfo_QueryResponse proto.InternalMessageInfo
func (m *QueryResponse) GetPosts() []*Post {
if m != nil {
return m.Posts
}
return nil
}
type SaveRequest struct {
Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SaveRequest) Reset() { *m = SaveRequest{} }
func (m *SaveRequest) String() string { return proto.CompactTextString(m) }
func (*SaveRequest) ProtoMessage() {}
func (*SaveRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_2d32cca1c2f74735, []int{3}
}
func (m *SaveRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SaveRequest.Unmarshal(m, b)
}
func (m *SaveRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SaveRequest.Marshal(b, m, deterministic)
}
func (m *SaveRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_SaveRequest.Merge(m, src)
}
func (m *SaveRequest) XXX_Size() int {
return xxx_messageInfo_SaveRequest.Size(m)
}
func (m *SaveRequest) XXX_DiscardUnknown() {
xxx_messageInfo_SaveRequest.DiscardUnknown(m)
}
var xxx_messageInfo_SaveRequest proto.InternalMessageInfo
func (m *SaveRequest) GetPost() *Post {
if m != nil {
return m.Post
}
return nil
}
type SaveResponse struct {
Post *Post `protobuf:"bytes,1,opt,name=post,proto3" json:"post,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SaveResponse) Reset() { *m = SaveResponse{} }
func (m *SaveResponse) String() string { return proto.CompactTextString(m) }
func (*SaveResponse) ProtoMessage() {}
func (*SaveResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_2d32cca1c2f74735, []int{4}
}
func (m *SaveResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SaveResponse.Unmarshal(m, b)
}
func (m *SaveResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SaveResponse.Marshal(b, m, deterministic)
}
func (m *SaveResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_SaveResponse.Merge(m, src)
}
func (m *SaveResponse) XXX_Size() int {
return xxx_messageInfo_SaveResponse.Size(m)
}
func (m *SaveResponse) XXX_DiscardUnknown() {
xxx_messageInfo_SaveResponse.DiscardUnknown(m)
}
var xxx_messageInfo_SaveResponse proto.InternalMessageInfo
func (m *SaveResponse) GetPost() *Post {
if m != nil {
return m.Post
}
return nil
}
type DeleteRequest struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DeleteRequest) Reset() { *m = DeleteRequest{} }
func (m *DeleteRequest) String() string { return proto.CompactTextString(m) }
func (*DeleteRequest) ProtoMessage() {}
func (*DeleteRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_2d32cca1c2f74735, []int{5}
}
func (m *DeleteRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DeleteRequest.Unmarshal(m, b)
}
func (m *DeleteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DeleteRequest.Marshal(b, m, deterministic)
}
func (m *DeleteRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_DeleteRequest.Merge(m, src)
}
func (m *DeleteRequest) XXX_Size() int {
return xxx_messageInfo_DeleteRequest.Size(m)
}
func (m *DeleteRequest) XXX_DiscardUnknown() {
xxx_messageInfo_DeleteRequest.DiscardUnknown(m)
}
var xxx_messageInfo_DeleteRequest proto.InternalMessageInfo
func (m *DeleteRequest) GetId() string {
if m != nil {
return m.Id
}
return ""
}
type DeleteResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DeleteResponse) Reset() { *m = DeleteResponse{} }
func (m *DeleteResponse) String() string { return proto.CompactTextString(m) }
func (*DeleteResponse) ProtoMessage() {}
func (*DeleteResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_2d32cca1c2f74735, []int{6}
}
func (m *DeleteResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DeleteResponse.Unmarshal(m, b)
}
func (m *DeleteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DeleteResponse.Marshal(b, m, deterministic)
}
func (m *DeleteResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_DeleteResponse.Merge(m, src)
}
func (m *DeleteResponse) XXX_Size() int {
return xxx_messageInfo_DeleteResponse.Size(m)
}
func (m *DeleteResponse) XXX_DiscardUnknown() {
xxx_messageInfo_DeleteResponse.DiscardUnknown(m)
}
var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo
func init() {
proto.RegisterType((*Post)(nil), "posts.Post")
proto.RegisterType((*QueryRequest)(nil), "posts.QueryRequest")
proto.RegisterType((*QueryResponse)(nil), "posts.QueryResponse")
proto.RegisterType((*SaveRequest)(nil), "posts.SaveRequest")
proto.RegisterType((*SaveResponse)(nil), "posts.SaveResponse")
proto.RegisterType((*DeleteRequest)(nil), "posts.DeleteRequest")
proto.RegisterType((*DeleteResponse)(nil), "posts.DeleteResponse")
}
func init() { proto.RegisterFile("blog/posts/proto/posts/post.proto", fileDescriptor_2d32cca1c2f74735) }
var fileDescriptor_2d32cca1c2f74735 = []byte{
// 343 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0x4d, 0x4e, 0xc3, 0x30,
0x10, 0x85, 0x71, 0xf3, 0x03, 0x9d, 0xfe, 0x08, 0x4d, 0x0b, 0xb2, 0x22, 0xa4, 0xa6, 0x59, 0x65,
0x95, 0x8a, 0x82, 0xc4, 0x05, 0x58, 0xa3, 0x62, 0x4e, 0x90, 0x52, 0xb7, 0x8a, 0x94, 0xd4, 0xa1,
0x9e, 0x22, 0x71, 0x0f, 0x2e, 0xc1, 0x2d, 0x51, 0xec, 0x24, 0xb4, 0xd9, 0xb0, 0xf3, 0xfb, 0xec,
0x79, 0xf3, 0x66, 0x12, 0x98, 0xaf, 0x73, 0xb5, 0x5b, 0x94, 0x4a, 0x93, 0x5e, 0x94, 0x07, 0x45,
0xaa, 0x39, 0x2b, 0x4d, 0x89, 0x01, 0xe8, 0x19, 0x12, 0x7d, 0x33, 0x70, 0x57, 0x4a, 0x13, 0x8e,
0xa1, 0x97, 0x6d, 0x38, 0x0b, 0x59, 0xdc, 0x17, 0xbd, 0x6c, 0x83, 0x53, 0xf0, 0x28, 0xa3, 0x5c,
0xf2, 0x9e, 0x41, 0x56, 0x20, 0x82, 0xab, 0xf3, 0xe3, 0x8e, 0x3b, 0x06, 0x9a, 0x33, 0x72, 0xb8,
0x7c, 0x57, 0x7b, 0x92, 0x7b, 0xe2, 0xae, 0xc1, 0x8d, 0xc4, 0x3b, 0xe8, 0x53, 0x56, 0x48, 0x4d,
0x69, 0x51, 0x72, 0x2f, 0x64, 0xb1, 0x23, 0xfe, 0x00, 0x06, 0x70, 0x45, 0xe9, 0xee, 0x25, 0x2d,
0xa4, 0xe6, 0x7e, 0xe8, 0xc4, 0x7d, 0xd1, 0xea, 0x68, 0x05, 0xc3, 0xd7, 0xa3, 0x3c, 0x7c, 0x09,
0xf9, 0x71, 0x94, 0x9a, 0xda, 0xbe, 0xec, 0xa4, 0xef, 0x2d, 0xf8, 0x6a, 0xbb, 0xd5, 0x92, 0x4c,
0x44, 0x47, 0xd4, 0xaa, 0x4a, 0x9e, 0x67, 0x45, 0x46, 0x26, 0xa4, 0x23, 0xac, 0x88, 0x96, 0x30,
0xaa, 0x1d, 0x75, 0xa9, 0xf6, 0x5a, 0xe2, 0x1c, 0xec, 0x0a, 0x38, 0x0b, 0x9d, 0x78, 0xb0, 0x1c,
0x24, 0x46, 0x25, 0xd5, 0x32, 0x44, 0xbd, 0x9c, 0x04, 0x06, 0x6f, 0xe9, 0xa7, 0x6c, 0x42, 0xcc,
0xc0, 0xad, 0xb8, 0x09, 0xd1, 0x29, 0x30, 0x17, 0xd1, 0x02, 0x86, 0xf6, 0x7d, 0xdd, 0xe2, 0xdf,
0x82, 0x19, 0x8c, 0x9e, 0x65, 0x2e, 0xa9, 0x6d, 0xd1, 0xf9, 0x0a, 0xd1, 0x35, 0x8c, 0x9b, 0x07,
0xd6, 0x73, 0xf9, 0xc3, 0xc0, 0xab, 0x1c, 0x34, 0x3e, 0x82, 0x67, 0x26, 0xc2, 0x49, 0x6d, 0x7c,
0xba, 0xb1, 0x60, 0x7a, 0x0e, 0x6d, 0x75, 0x74, 0x81, 0xf7, 0xe0, 0x56, 0x19, 0x11, 0xeb, 0xfb,
0x93, 0x01, 0x83, 0xc9, 0x19, 0x6b, 0x4b, 0x9e, 0xc0, 0xb7, 0x21, 0xb0, 0x31, 0x3d, 0x0b, 0x1d,
0xdc, 0x74, 0x68, 0x53, 0xb8, 0xf6, 0xcd, 0xaf, 0xf6, 0xf0, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xd5,
0xd2, 0x06, 0xac, 0x8f, 0x02, 0x00, 0x00,
}

View File

@@ -0,0 +1,129 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: blog/posts/proto/posts/post.proto
package posts
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
api "github.com/micro/go-micro/v3/api"
client "github.com/micro/go-micro/v3/client"
server "github.com/micro/go-micro/v3/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Posts service
func NewPostsEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Posts service
type PostsService interface {
// Query currently only supports read by slug or timestamp, no listing.
Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error)
Save(ctx context.Context, in *SaveRequest, opts ...client.CallOption) (*SaveResponse, error)
Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error)
}
type postsService struct {
c client.Client
name string
}
func NewPostsService(name string, c client.Client) PostsService {
return &postsService{
c: c,
name: name,
}
}
func (c *postsService) Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) {
req := c.c.NewRequest(c.name, "Posts.Query", in)
out := new(QueryResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *postsService) Save(ctx context.Context, in *SaveRequest, opts ...client.CallOption) (*SaveResponse, error) {
req := c.c.NewRequest(c.name, "Posts.Save", in)
out := new(SaveResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *postsService) Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) {
req := c.c.NewRequest(c.name, "Posts.Delete", in)
out := new(DeleteResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Posts service
type PostsHandler interface {
// Query currently only supports read by slug or timestamp, no listing.
Query(context.Context, *QueryRequest, *QueryResponse) error
Save(context.Context, *SaveRequest, *SaveResponse) error
Delete(context.Context, *DeleteRequest, *DeleteResponse) error
}
func RegisterPostsHandler(s server.Server, hdlr PostsHandler, opts ...server.HandlerOption) error {
type posts interface {
Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error
Save(ctx context.Context, in *SaveRequest, out *SaveResponse) error
Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error
}
type Posts struct {
posts
}
h := &postsHandler{hdlr}
return s.Handle(s.NewHandler(&Posts{h}, opts...))
}
type postsHandler struct {
PostsHandler
}
func (h *postsHandler) Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error {
return h.PostsHandler.Query(ctx, in, out)
}
func (h *postsHandler) Save(ctx context.Context, in *SaveRequest, out *SaveResponse) error {
return h.PostsHandler.Save(ctx, in, out)
}
func (h *postsHandler) Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error {
return h.PostsHandler.Delete(ctx, in, out)
}

View File

@@ -0,0 +1,45 @@
syntax = "proto3";
package posts;
service Posts {
// Query currently only supports read by slug or timestamp, no listing.
rpc Query(QueryRequest) returns (QueryResponse) {}
rpc Save(SaveRequest) returns (SaveResponse) {}
rpc Delete(DeleteRequest) returns (DeleteResponse) {}
}
message Post {
string id = 1;
string title = 2;
string slug = 3;
string content = 4;
int64 timestamp = 5;
repeated string tagNames = 6;
}
message QueryRequest {
string slug = 1;
int64 offset = 2;
int64 limit = 3;
}
message QueryResponse {
repeated Post posts = 1;
}
message SaveRequest {
Post post = 1;
}
message SaveResponse {
Post post = 1;
}
message DeleteRequest {
string id = 1;
}
message DeleteResponse {
}

2
blog/search/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
search-service

3
blog/search/Dockerfile Normal file
View File

@@ -0,0 +1,3 @@
FROM alpine
ADD search-service /search-service
ENTRYPOINT [ "/search-service" ]

22
blog/search/Makefile Normal file
View File

@@ -0,0 +1,22 @@
GOPATH:=$(shell go env GOPATH)
MODIFY=Mgithub.com/micro/go-micro/api/proto/api.proto=github.com/micro/go-micro/v3/api/proto
.PHONY: proto
proto:
protoc --proto_path=. --micro_out=${MODIFY}:. --go_out=${MODIFY}:. proto/search/search.proto
.PHONY: build
build: proto
go build -o search-service *.go
.PHONY: test
test:
go test -v ./... -cover
.PHONY: docker
docker:
docker build . -t search-service:latest

55
blog/search/README.md Normal file
View File

@@ -0,0 +1,55 @@
# Search Service
This is the Search service
Generated with
```
micro new --namespace=go.micro --type=service search
```
## Getting Started
- [Configuration](#configuration)
- [Dependencies](#dependencies)
- [Usage](#usage)
## Configuration
- FQDN: go.micro.service.search
- Type: service
- Alias: search
## Dependencies
Micro services depend on service discovery. The default is multicast DNS, a zeroconf system.
In the event you need a resilient multi-host setup we recommend etcd.
```
# install etcd
brew install etcd
# run etcd
etcd
```
## Usage
A Makefile is included for convenience
Build the binary
```
make build
```
Run the service
```
./search-service
```
Build a docker image
```
make docker
```

3
blog/search/generate.go Normal file
View File

@@ -0,0 +1,3 @@
package main
//go:generate make proto

View File

@@ -0,0 +1,20 @@
package handler
import (
"context"
"github.com/micro/micro/v3/service/logger"
pb "github.com/micro/services/blog/search/proto"
)
type Search struct{}
func (s *Search) Index(ctx context.Context, req *pb.IndexRequest, rsp *pb.IndexResponse) error {
logger.Info("Received Search.Index request")
return nil
}
func (s *Search) Search(ctx context.Context, req *pb.SearchRequest, rsp *pb.SearchResponse) error {
logger.Info("Received Search.Search request")
return nil
}

22
blog/search/main.go Normal file
View File

@@ -0,0 +1,22 @@
package main
import (
"github.com/micro/micro/v3/service"
"github.com/micro/micro/v3/service/logger"
"github.com/micro/services/blog/search/handler"
)
func main() {
// Create service
srv := service.New(
service.Name("search"),
)
// Register Handler
srv.Handle(new(handler.Search))
// Run service
if err := srv.Run(); err != nil {
logger.Fatal(err)
}
}

View File

@@ -0,0 +1,245 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: blog/search/proto/search.proto
package search
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Document struct {
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Text string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Document) Reset() { *m = Document{} }
func (m *Document) String() string { return proto.CompactTextString(m) }
func (*Document) ProtoMessage() {}
func (*Document) Descriptor() ([]byte, []int) {
return fileDescriptor_5c88c8197db8a717, []int{0}
}
func (m *Document) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Document.Unmarshal(m, b)
}
func (m *Document) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Document.Marshal(b, m, deterministic)
}
func (m *Document) XXX_Merge(src proto.Message) {
xxx_messageInfo_Document.Merge(m, src)
}
func (m *Document) XXX_Size() int {
return xxx_messageInfo_Document.Size(m)
}
func (m *Document) XXX_DiscardUnknown() {
xxx_messageInfo_Document.DiscardUnknown(m)
}
var xxx_messageInfo_Document proto.InternalMessageInfo
func (m *Document) GetId() string {
if m != nil {
return m.Id
}
return ""
}
func (m *Document) GetText() string {
if m != nil {
return m.Text
}
return ""
}
type IndexRequest struct {
Document *Document `protobuf:"bytes,1,opt,name=document,proto3" json:"document,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IndexRequest) Reset() { *m = IndexRequest{} }
func (m *IndexRequest) String() string { return proto.CompactTextString(m) }
func (*IndexRequest) ProtoMessage() {}
func (*IndexRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_5c88c8197db8a717, []int{1}
}
func (m *IndexRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IndexRequest.Unmarshal(m, b)
}
func (m *IndexRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IndexRequest.Marshal(b, m, deterministic)
}
func (m *IndexRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_IndexRequest.Merge(m, src)
}
func (m *IndexRequest) XXX_Size() int {
return xxx_messageInfo_IndexRequest.Size(m)
}
func (m *IndexRequest) XXX_DiscardUnknown() {
xxx_messageInfo_IndexRequest.DiscardUnknown(m)
}
var xxx_messageInfo_IndexRequest proto.InternalMessageInfo
func (m *IndexRequest) GetDocument() *Document {
if m != nil {
return m.Document
}
return nil
}
type IndexResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IndexResponse) Reset() { *m = IndexResponse{} }
func (m *IndexResponse) String() string { return proto.CompactTextString(m) }
func (*IndexResponse) ProtoMessage() {}
func (*IndexResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_5c88c8197db8a717, []int{2}
}
func (m *IndexResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IndexResponse.Unmarshal(m, b)
}
func (m *IndexResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IndexResponse.Marshal(b, m, deterministic)
}
func (m *IndexResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_IndexResponse.Merge(m, src)
}
func (m *IndexResponse) XXX_Size() int {
return xxx_messageInfo_IndexResponse.Size(m)
}
func (m *IndexResponse) XXX_DiscardUnknown() {
xxx_messageInfo_IndexResponse.DiscardUnknown(m)
}
var xxx_messageInfo_IndexResponse proto.InternalMessageInfo
type SearchRequest struct {
Keyword string `protobuf:"bytes,1,opt,name=keyword,proto3" json:"keyword,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SearchRequest) Reset() { *m = SearchRequest{} }
func (m *SearchRequest) String() string { return proto.CompactTextString(m) }
func (*SearchRequest) ProtoMessage() {}
func (*SearchRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_5c88c8197db8a717, []int{3}
}
func (m *SearchRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SearchRequest.Unmarshal(m, b)
}
func (m *SearchRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SearchRequest.Marshal(b, m, deterministic)
}
func (m *SearchRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_SearchRequest.Merge(m, src)
}
func (m *SearchRequest) XXX_Size() int {
return xxx_messageInfo_SearchRequest.Size(m)
}
func (m *SearchRequest) XXX_DiscardUnknown() {
xxx_messageInfo_SearchRequest.DiscardUnknown(m)
}
var xxx_messageInfo_SearchRequest proto.InternalMessageInfo
func (m *SearchRequest) GetKeyword() string {
if m != nil {
return m.Keyword
}
return ""
}
type SearchResponse struct {
Documents []*Document `protobuf:"bytes,1,rep,name=documents,proto3" json:"documents,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SearchResponse) Reset() { *m = SearchResponse{} }
func (m *SearchResponse) String() string { return proto.CompactTextString(m) }
func (*SearchResponse) ProtoMessage() {}
func (*SearchResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_5c88c8197db8a717, []int{4}
}
func (m *SearchResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SearchResponse.Unmarshal(m, b)
}
func (m *SearchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SearchResponse.Marshal(b, m, deterministic)
}
func (m *SearchResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_SearchResponse.Merge(m, src)
}
func (m *SearchResponse) XXX_Size() int {
return xxx_messageInfo_SearchResponse.Size(m)
}
func (m *SearchResponse) XXX_DiscardUnknown() {
xxx_messageInfo_SearchResponse.DiscardUnknown(m)
}
var xxx_messageInfo_SearchResponse proto.InternalMessageInfo
func (m *SearchResponse) GetDocuments() []*Document {
if m != nil {
return m.Documents
}
return nil
}
func init() {
proto.RegisterType((*Document)(nil), "search.Document")
proto.RegisterType((*IndexRequest)(nil), "search.IndexRequest")
proto.RegisterType((*IndexResponse)(nil), "search.IndexResponse")
proto.RegisterType((*SearchRequest)(nil), "search.SearchRequest")
proto.RegisterType((*SearchResponse)(nil), "search.SearchResponse")
}
func init() { proto.RegisterFile("blog/search/proto/search.proto", fileDescriptor_5c88c8197db8a717) }
var fileDescriptor_5c88c8197db8a717 = []byte{
// 233 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xca, 0xc9, 0x4f,
0xd7, 0x2f, 0x4e, 0x4d, 0x2c, 0x4a, 0xce, 0xd0, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x87, 0x72, 0xf4,
0xc0, 0x1c, 0x21, 0x36, 0x08, 0x4f, 0x49, 0x8f, 0x8b, 0xc3, 0x25, 0x3f, 0xb9, 0x34, 0x37, 0x35,
0xaf, 0x44, 0x88, 0x8f, 0x8b, 0x29, 0x33, 0x45, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x88, 0x29,
0x33, 0x45, 0x48, 0x88, 0x8b, 0xa5, 0x24, 0xb5, 0xa2, 0x44, 0x82, 0x09, 0x2c, 0x02, 0x66, 0x2b,
0xd9, 0x70, 0xf1, 0x78, 0xe6, 0xa5, 0xa4, 0x56, 0x04, 0xa5, 0x16, 0x96, 0xa6, 0x16, 0x97, 0x08,
0xe9, 0x70, 0x71, 0xa4, 0x40, 0xf5, 0x83, 0x75, 0x72, 0x1b, 0x09, 0xe8, 0x41, 0x2d, 0x82, 0x99,
0x1b, 0x04, 0x57, 0xa1, 0xc4, 0xcf, 0xc5, 0x0b, 0xd5, 0x5d, 0x5c, 0x90, 0x9f, 0x57, 0x9c, 0xaa,
0xa4, 0xc9, 0xc5, 0x1b, 0x0c, 0x56, 0x0d, 0x33, 0x4f, 0x82, 0x8b, 0x3d, 0x3b, 0xb5, 0xb2, 0x3c,
0xbf, 0x08, 0xe6, 0x10, 0x18, 0x57, 0xc9, 0x81, 0x8b, 0x0f, 0xa6, 0x14, 0xa2, 0x59, 0x48, 0x8f,
0x8b, 0x13, 0x66, 0x72, 0xb1, 0x04, 0xa3, 0x02, 0x33, 0x56, 0xcb, 0x11, 0x4a, 0x8c, 0xaa, 0xb9,
0xd8, 0x20, 0x26, 0x08, 0x99, 0x71, 0xb1, 0x82, 0xdd, 0x21, 0x24, 0x02, 0x53, 0x8f, 0xec, 0x29,
0x29, 0x51, 0x34, 0x51, 0xa8, 0x63, 0x19, 0x84, 0x2c, 0xe1, 0x26, 0xc0, 0x95, 0xa0, 0x38, 0x5f,
0x4a, 0x0c, 0x5d, 0x18, 0xa6, 0x35, 0x89, 0x0d, 0x1c, 0xee, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff,
0xff, 0x30, 0x86, 0x79, 0x74, 0x99, 0x01, 0x00, 0x00,
}

View File

@@ -0,0 +1,110 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: blog/search/proto/search.proto
package search
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
api "github.com/micro/go-micro/v3/api"
client "github.com/micro/go-micro/v3/client"
server "github.com/micro/go-micro/v3/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Search service
func NewSearchEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Search service
type SearchService interface {
Index(ctx context.Context, in *IndexRequest, opts ...client.CallOption) (*IndexResponse, error)
Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error)
}
type searchService struct {
c client.Client
name string
}
func NewSearchService(name string, c client.Client) SearchService {
return &searchService{
c: c,
name: name,
}
}
func (c *searchService) Index(ctx context.Context, in *IndexRequest, opts ...client.CallOption) (*IndexResponse, error) {
req := c.c.NewRequest(c.name, "Search.Index", in)
out := new(IndexResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *searchService) Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error) {
req := c.c.NewRequest(c.name, "Search.Search", in)
out := new(SearchResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Search service
type SearchHandler interface {
Index(context.Context, *IndexRequest, *IndexResponse) error
Search(context.Context, *SearchRequest, *SearchResponse) error
}
func RegisterSearchHandler(s server.Server, hdlr SearchHandler, opts ...server.HandlerOption) error {
type search interface {
Index(ctx context.Context, in *IndexRequest, out *IndexResponse) error
Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error
}
type Search struct {
search
}
h := &searchHandler{hdlr}
return s.Handle(s.NewHandler(&Search{h}, opts...))
}
type searchHandler struct {
SearchHandler
}
func (h *searchHandler) Index(ctx context.Context, in *IndexRequest, out *IndexResponse) error {
return h.SearchHandler.Index(ctx, in, out)
}
func (h *searchHandler) Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error {
return h.SearchHandler.Search(ctx, in, out)
}

View File

@@ -0,0 +1,27 @@
syntax = "proto3";
package search;
service Search {
rpc Index(IndexRequest) returns (IndexResponse) {}
rpc Search(SearchRequest) returns (SearchResponse) {}
}
message Document {
string id = 1;
string text = 2;
}
message IndexRequest {
Document document = 1;
}
message IndexResponse {}
message SearchRequest {
string keyword = 1;
}
message SearchResponse {
repeated Document documents = 1;
}

2
blog/tags/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
./tags

3
blog/tags/Dockerfile Normal file
View File

@@ -0,0 +1,3 @@
FROM alpine
ADD tag-service /tag-service
ENTRYPOINT [ "/tag-service" ]

22
blog/tags/Makefile Normal file
View File

@@ -0,0 +1,22 @@
GOPATH:=$(shell go env GOPATH)
MODIFY=Mgithub.com/micro/go-micro/api/proto/api.proto=github.com/micro/go-micro/v3/api/proto
.PHONY: proto
proto:
protoc --proto_path=. --micro_out=${MODIFY}:. --go_out=${MODIFY}:. proto/tag/tag.proto
.PHONY: build
build: proto
go build -o tag-service *.go
.PHONY: test
test:
go test -v ./... -cover
.PHONY: docker
docker:
docker build . -t tag-service:latest

61
blog/tags/README.md Normal file
View File

@@ -0,0 +1,61 @@
# Tag Service
This is the Tag service
## Query tags
```
micro tags list --type=post-tag
```
Generated with
```
micro new --namespace=go.micro --type=service tag
```
## Getting Started
- [Configuration](#configuration)
- [Dependencies](#dependencies)
- [Usage](#usage)
## Configuration
- FQDN: go.micro.service.tag
- Type: service
- Alias: tag
## Dependencies
Micro services depend on service discovery. The default is multicast DNS, a zeroconf system.
In the event you need a resilient multi-host setup we recommend etcd.
```
# install etcd
brew install etcd
# run etcd
etcd
```
## Usage
A Makefile is included for convenience
Build the binary
```
make build
```
Run the service
```
./tag-service
```
Build a docker image
```
make docker
```

3
blog/tags/generate.go Normal file
View File

@@ -0,0 +1,3 @@
package main
//go:generate make proto

185
blog/tags/handler/tags.go Normal file
View File

@@ -0,0 +1,185 @@
package handler
import (
"context"
"encoding/json"
"fmt"
"github.com/gosimple/slug"
"github.com/micro/go-micro/v3/errors"
gostore "github.com/micro/go-micro/v3/store"
"github.com/micro/micro/v3/service/logger"
"github.com/micro/micro/v3/service/store"
pb "github.com/micro/services/blog/tags/proto"
)
const (
parentPrefix = "parent"
typePrefix = "type"
)
type Tag struct {
ParentID string `json:"parentID"`
Title string `json:"title"`
Slug string `json:"slug"`
Type string `json:"type"`
Count int64 `json:"count"`
}
type Tags struct{}
func (t *Tags) IncreaseCount(ctx context.Context, req *pb.IncreaseCountRequest, rsp *pb.IncreaseCountResponse) error {
if len(req.ParentID) == 0 || len(req.Type) == 0 {
return errors.BadRequest("tags.increasecount.input-check", "parent id and type is required")
}
tagSlug := slug.Make(req.GetTitle())
parentID := fmt.Sprintf("%v:%v:%v", parentPrefix, req.GetParentID(), tagSlug)
// read by parent ID + slug, the record is identical in boths places anyway
records, err := store.Read(parentID)
if err != nil && err != gostore.ErrNotFound {
return err
}
// If no existing record is found, create a new one
if len(records) == 0 {
tag := &Tag{
ParentID: req.GetParentID(),
Title: req.GetTitle(),
Type: req.Type,
Slug: tagSlug,
Count: 1,
}
return t.saveTag(tag)
}
record := records[0]
tag := &Tag{}
err = json.Unmarshal(record.Value, tag)
if err != nil {
return err
}
tag.Count++
return t.saveTag(tag)
}
func (t *Tags) saveTag(tag *Tag) error {
tagSlug := slug.Make(tag.Title)
parentID := fmt.Sprintf("%v:%v:%v", parentPrefix, tag.ParentID, tagSlug)
typeID := fmt.Sprintf("%v:%v:%v", typePrefix, tag.Type, tagSlug)
bytes, err := json.Marshal(tag)
if err != nil {
return err
}
// write parentId:slug to enable prefix listing based on parent
err = store.Write(&gostore.Record{
Key: parentID,
Value: bytes,
})
if err != nil {
return err
}
// write type:slug to enable prefix listing based on parent
return store.Write(&gostore.Record{
Key: typeID,
Value: bytes,
})
}
func (t *Tags) DecreaseCount(ctx context.Context, req *pb.DecreaseCountRequest, rsp *pb.DecreaseCountResponse) error {
if len(req.ParentID) == 0 || len(req.Type) == 0 {
return errors.BadRequest("tags.decreaseecount.input-check", "parent id and type is required")
}
tagSlug := slug.Make(req.GetTitle())
parentID := fmt.Sprintf("%v:%v:%v", parentPrefix, req.GetParentID(), tagSlug)
// read by parent ID + slug, the record is identical in boths places anyway
records, err := store.Read(parentID)
if err != nil && err != gostore.ErrNotFound {
return err
}
// If no existing record is found, there is nothing to decrease
if len(records) == 0 {
// return error?
return nil
}
record := records[0]
tag := &Tag{}
err = json.Unmarshal(record.Value, tag)
if err != nil {
return err
}
if tag.Count == 0 {
// return error?
return nil
}
tag.Count--
return t.saveTag(tag)
}
func (t *Tags) List(ctx context.Context, req *pb.ListRequest, rsp *pb.ListResponse) error {
logger.Info("Received Tags.List request")
key := ""
if len(req.ParentID) > 0 {
key = fmt.Sprintf("%v:%v", parentPrefix, req.ParentID)
} else if len(req.Type) > 0 {
key = fmt.Sprintf("%v:%v", typePrefix, req.Type)
} else {
return errors.BadRequest("tags.list.input-check", "parent id or type is required")
}
records, err := store.Read("", store.Prefix(key))
if err != nil {
return err
}
rsp.Tags = make([]*pb.Tag, len(records))
for i, record := range records {
tagRecord := &Tag{}
err := json.Unmarshal(record.Value, tagRecord)
if err != nil {
return err
}
rsp.Tags[i] = &pb.Tag{
ParentID: tagRecord.ParentID,
Title: tagRecord.Title,
Type: tagRecord.Type,
Slug: tagRecord.Slug,
Count: tagRecord.Count,
}
}
return nil
}
func (t *Tags) Update(ctx context.Context, req *pb.UpdateRequest, rsp *pb.UpdateResponse) error {
if len(req.ParentID) == 0 || len(req.Type) == 0 {
return errors.BadRequest("tags.update.input-check", "parent id and type is required")
}
tagSlug := slug.Make(req.GetTitle())
parentID := fmt.Sprintf("%v:%v:%v", parentPrefix, req.GetParentID(), tagSlug)
// read by parent ID + slug, the record is identical in boths places anyway
records, err := store.Read(parentID)
if err != nil {
return err
}
if len(records) == 0 {
return fmt.Errorf("Tag with slug '%v' not found, nothing to update", tagSlug)
}
record := records[0]
tag := &Tag{}
err = json.Unmarshal(record.Value, tag)
if err != nil {
return err
}
tag.Title = req.Title
return t.saveTag(tag)
}

23
blog/tags/main.go Normal file
View File

@@ -0,0 +1,23 @@
package main
import (
"github.com/micro/micro/v3/service"
"github.com/micro/micro/v3/service/logger"
"github.com/micro/services/blog/tags/handler"
)
func main() {
// Create service
srv := service.New(
service.Name("tags"),
)
// Register Handler
srv.Handle(new(handler.Tags))
// Run service
if err := srv.Run(); err != nil {
logger.Fatal(err)
}
}

497
blog/tags/proto/tags.pb.go Normal file
View File

@@ -0,0 +1,497 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: blog/tags/proto/tags.proto
package tags
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Tag struct {
// The id of the parent object
ParentID string `protobuf:"bytes,1,opt,name=parentID,proto3" json:"parentID,omitempty"`
// Type is useful for namespacing and listing across parents,
// ie. list tags for posts, customers etc.
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Slug string `protobuf:"bytes,3,opt,name=slug,proto3" json:"slug,omitempty"`
Title string `protobuf:"bytes,4,opt,name=title,proto3" json:"title,omitempty"`
Count int64 `protobuf:"varint,5,opt,name=count,proto3" json:"count,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Tag) Reset() { *m = Tag{} }
func (m *Tag) String() string { return proto.CompactTextString(m) }
func (*Tag) ProtoMessage() {}
func (*Tag) Descriptor() ([]byte, []int) {
return fileDescriptor_3298e21a718ae8a1, []int{0}
}
func (m *Tag) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Tag.Unmarshal(m, b)
}
func (m *Tag) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Tag.Marshal(b, m, deterministic)
}
func (m *Tag) XXX_Merge(src proto.Message) {
xxx_messageInfo_Tag.Merge(m, src)
}
func (m *Tag) XXX_Size() int {
return xxx_messageInfo_Tag.Size(m)
}
func (m *Tag) XXX_DiscardUnknown() {
xxx_messageInfo_Tag.DiscardUnknown(m)
}
var xxx_messageInfo_Tag proto.InternalMessageInfo
func (m *Tag) GetParentID() string {
if m != nil {
return m.ParentID
}
return ""
}
func (m *Tag) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (m *Tag) GetSlug() string {
if m != nil {
return m.Slug
}
return ""
}
func (m *Tag) GetTitle() string {
if m != nil {
return m.Title
}
return ""
}
func (m *Tag) GetCount() int64 {
if m != nil {
return m.Count
}
return 0
}
type IncreaseCountRequest struct {
ParentID string `protobuf:"bytes,1,opt,name=parentID,proto3" json:"parentID,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IncreaseCountRequest) Reset() { *m = IncreaseCountRequest{} }
func (m *IncreaseCountRequest) String() string { return proto.CompactTextString(m) }
func (*IncreaseCountRequest) ProtoMessage() {}
func (*IncreaseCountRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_3298e21a718ae8a1, []int{1}
}
func (m *IncreaseCountRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IncreaseCountRequest.Unmarshal(m, b)
}
func (m *IncreaseCountRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IncreaseCountRequest.Marshal(b, m, deterministic)
}
func (m *IncreaseCountRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_IncreaseCountRequest.Merge(m, src)
}
func (m *IncreaseCountRequest) XXX_Size() int {
return xxx_messageInfo_IncreaseCountRequest.Size(m)
}
func (m *IncreaseCountRequest) XXX_DiscardUnknown() {
xxx_messageInfo_IncreaseCountRequest.DiscardUnknown(m)
}
var xxx_messageInfo_IncreaseCountRequest proto.InternalMessageInfo
func (m *IncreaseCountRequest) GetParentID() string {
if m != nil {
return m.ParentID
}
return ""
}
func (m *IncreaseCountRequest) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (m *IncreaseCountRequest) GetTitle() string {
if m != nil {
return m.Title
}
return ""
}
type IncreaseCountResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IncreaseCountResponse) Reset() { *m = IncreaseCountResponse{} }
func (m *IncreaseCountResponse) String() string { return proto.CompactTextString(m) }
func (*IncreaseCountResponse) ProtoMessage() {}
func (*IncreaseCountResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_3298e21a718ae8a1, []int{2}
}
func (m *IncreaseCountResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IncreaseCountResponse.Unmarshal(m, b)
}
func (m *IncreaseCountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IncreaseCountResponse.Marshal(b, m, deterministic)
}
func (m *IncreaseCountResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_IncreaseCountResponse.Merge(m, src)
}
func (m *IncreaseCountResponse) XXX_Size() int {
return xxx_messageInfo_IncreaseCountResponse.Size(m)
}
func (m *IncreaseCountResponse) XXX_DiscardUnknown() {
xxx_messageInfo_IncreaseCountResponse.DiscardUnknown(m)
}
var xxx_messageInfo_IncreaseCountResponse proto.InternalMessageInfo
type DecreaseCountRequest struct {
ParentID string `protobuf:"bytes,1,opt,name=parentID,proto3" json:"parentID,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DecreaseCountRequest) Reset() { *m = DecreaseCountRequest{} }
func (m *DecreaseCountRequest) String() string { return proto.CompactTextString(m) }
func (*DecreaseCountRequest) ProtoMessage() {}
func (*DecreaseCountRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_3298e21a718ae8a1, []int{3}
}
func (m *DecreaseCountRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DecreaseCountRequest.Unmarshal(m, b)
}
func (m *DecreaseCountRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DecreaseCountRequest.Marshal(b, m, deterministic)
}
func (m *DecreaseCountRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_DecreaseCountRequest.Merge(m, src)
}
func (m *DecreaseCountRequest) XXX_Size() int {
return xxx_messageInfo_DecreaseCountRequest.Size(m)
}
func (m *DecreaseCountRequest) XXX_DiscardUnknown() {
xxx_messageInfo_DecreaseCountRequest.DiscardUnknown(m)
}
var xxx_messageInfo_DecreaseCountRequest proto.InternalMessageInfo
func (m *DecreaseCountRequest) GetParentID() string {
if m != nil {
return m.ParentID
}
return ""
}
func (m *DecreaseCountRequest) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (m *DecreaseCountRequest) GetTitle() string {
if m != nil {
return m.Title
}
return ""
}
type DecreaseCountResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DecreaseCountResponse) Reset() { *m = DecreaseCountResponse{} }
func (m *DecreaseCountResponse) String() string { return proto.CompactTextString(m) }
func (*DecreaseCountResponse) ProtoMessage() {}
func (*DecreaseCountResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_3298e21a718ae8a1, []int{4}
}
func (m *DecreaseCountResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DecreaseCountResponse.Unmarshal(m, b)
}
func (m *DecreaseCountResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DecreaseCountResponse.Marshal(b, m, deterministic)
}
func (m *DecreaseCountResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_DecreaseCountResponse.Merge(m, src)
}
func (m *DecreaseCountResponse) XXX_Size() int {
return xxx_messageInfo_DecreaseCountResponse.Size(m)
}
func (m *DecreaseCountResponse) XXX_DiscardUnknown() {
xxx_messageInfo_DecreaseCountResponse.DiscardUnknown(m)
}
var xxx_messageInfo_DecreaseCountResponse proto.InternalMessageInfo
type UpdateRequest struct {
ParentID string `protobuf:"bytes,1,opt,name=parentID,proto3" json:"parentID,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *UpdateRequest) Reset() { *m = UpdateRequest{} }
func (m *UpdateRequest) String() string { return proto.CompactTextString(m) }
func (*UpdateRequest) ProtoMessage() {}
func (*UpdateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_3298e21a718ae8a1, []int{5}
}
func (m *UpdateRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_UpdateRequest.Unmarshal(m, b)
}
func (m *UpdateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_UpdateRequest.Marshal(b, m, deterministic)
}
func (m *UpdateRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_UpdateRequest.Merge(m, src)
}
func (m *UpdateRequest) XXX_Size() int {
return xxx_messageInfo_UpdateRequest.Size(m)
}
func (m *UpdateRequest) XXX_DiscardUnknown() {
xxx_messageInfo_UpdateRequest.DiscardUnknown(m)
}
var xxx_messageInfo_UpdateRequest proto.InternalMessageInfo
func (m *UpdateRequest) GetParentID() string {
if m != nil {
return m.ParentID
}
return ""
}
func (m *UpdateRequest) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (m *UpdateRequest) GetTitle() string {
if m != nil {
return m.Title
}
return ""
}
type UpdateResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *UpdateResponse) Reset() { *m = UpdateResponse{} }
func (m *UpdateResponse) String() string { return proto.CompactTextString(m) }
func (*UpdateResponse) ProtoMessage() {}
func (*UpdateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_3298e21a718ae8a1, []int{6}
}
func (m *UpdateResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_UpdateResponse.Unmarshal(m, b)
}
func (m *UpdateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_UpdateResponse.Marshal(b, m, deterministic)
}
func (m *UpdateResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_UpdateResponse.Merge(m, src)
}
func (m *UpdateResponse) XXX_Size() int {
return xxx_messageInfo_UpdateResponse.Size(m)
}
func (m *UpdateResponse) XXX_DiscardUnknown() {
xxx_messageInfo_UpdateResponse.DiscardUnknown(m)
}
var xxx_messageInfo_UpdateResponse proto.InternalMessageInfo
// ListRequest: list either by parent id or type.
// Optionally filter by min or max count.
type ListRequest struct {
ParentID string `protobuf:"bytes,1,opt,name=parentID,proto3" json:"parentID,omitempty"`
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
MinCount int64 `protobuf:"varint,3,opt,name=minCount,proto3" json:"minCount,omitempty"`
MaxCount int64 `protobuf:"varint,4,opt,name=maxCount,proto3" json:"maxCount,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListRequest) Reset() { *m = ListRequest{} }
func (m *ListRequest) String() string { return proto.CompactTextString(m) }
func (*ListRequest) ProtoMessage() {}
func (*ListRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_3298e21a718ae8a1, []int{7}
}
func (m *ListRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListRequest.Unmarshal(m, b)
}
func (m *ListRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListRequest.Marshal(b, m, deterministic)
}
func (m *ListRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListRequest.Merge(m, src)
}
func (m *ListRequest) XXX_Size() int {
return xxx_messageInfo_ListRequest.Size(m)
}
func (m *ListRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ListRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ListRequest proto.InternalMessageInfo
func (m *ListRequest) GetParentID() string {
if m != nil {
return m.ParentID
}
return ""
}
func (m *ListRequest) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (m *ListRequest) GetMinCount() int64 {
if m != nil {
return m.MinCount
}
return 0
}
func (m *ListRequest) GetMaxCount() int64 {
if m != nil {
return m.MaxCount
}
return 0
}
type ListResponse struct {
Tags []*Tag `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListResponse) Reset() { *m = ListResponse{} }
func (m *ListResponse) String() string { return proto.CompactTextString(m) }
func (*ListResponse) ProtoMessage() {}
func (*ListResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_3298e21a718ae8a1, []int{8}
}
func (m *ListResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListResponse.Unmarshal(m, b)
}
func (m *ListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListResponse.Marshal(b, m, deterministic)
}
func (m *ListResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListResponse.Merge(m, src)
}
func (m *ListResponse) XXX_Size() int {
return xxx_messageInfo_ListResponse.Size(m)
}
func (m *ListResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ListResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ListResponse proto.InternalMessageInfo
func (m *ListResponse) GetTags() []*Tag {
if m != nil {
return m.Tags
}
return nil
}
func init() {
proto.RegisterType((*Tag)(nil), "tags.Tag")
proto.RegisterType((*IncreaseCountRequest)(nil), "tags.IncreaseCountRequest")
proto.RegisterType((*IncreaseCountResponse)(nil), "tags.IncreaseCountResponse")
proto.RegisterType((*DecreaseCountRequest)(nil), "tags.DecreaseCountRequest")
proto.RegisterType((*DecreaseCountResponse)(nil), "tags.DecreaseCountResponse")
proto.RegisterType((*UpdateRequest)(nil), "tags.UpdateRequest")
proto.RegisterType((*UpdateResponse)(nil), "tags.UpdateResponse")
proto.RegisterType((*ListRequest)(nil), "tags.ListRequest")
proto.RegisterType((*ListResponse)(nil), "tags.ListResponse")
}
func init() { proto.RegisterFile("blog/tags/proto/tags.proto", fileDescriptor_3298e21a718ae8a1) }
var fileDescriptor_3298e21a718ae8a1 = []byte{
// 341 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x41, 0x4f, 0x32, 0x31,
0x10, 0x65, 0xd9, 0x42, 0x60, 0xf8, 0xf8, 0xa2, 0x23, 0xc6, 0xa6, 0xc6, 0x84, 0xec, 0x89, 0x8b,
0x90, 0x60, 0xfc, 0x05, 0x72, 0xc1, 0x78, 0xda, 0xc0, 0xcd, 0x4b, 0xc1, 0xa6, 0x21, 0xc1, 0xdd,
0x95, 0x76, 0x13, 0xfd, 0x03, 0xfe, 0x6e, 0xd3, 0xe9, 0xee, 0x86, 0x25, 0x7b, 0xd1, 0xe8, 0x6d,
0xe6, 0x4d, 0xfb, 0xde, 0x4c, 0xdf, 0x14, 0xc4, 0x66, 0x9f, 0xea, 0x99, 0x95, 0xda, 0xcc, 0xb2,
0x43, 0x6a, 0x53, 0x0a, 0xa7, 0x14, 0x22, 0x73, 0x71, 0x94, 0x43, 0xb8, 0x92, 0x1a, 0x05, 0xf4,
0x32, 0x79, 0x50, 0x89, 0x5d, 0x2e, 0x78, 0x30, 0x0e, 0x26, 0xfd, 0xb8, 0xca, 0x11, 0x81, 0xd9,
0x8f, 0x4c, 0xf1, 0x36, 0xe1, 0x14, 0x3b, 0xcc, 0xec, 0x73, 0xcd, 0x43, 0x8f, 0xb9, 0x18, 0x47,
0xd0, 0xb1, 0x3b, 0xbb, 0x57, 0x9c, 0x11, 0xe8, 0x13, 0x87, 0x6e, 0xd3, 0x3c, 0xb1, 0xbc, 0x33,
0x0e, 0x26, 0x61, 0xec, 0x93, 0xe8, 0x19, 0x46, 0xcb, 0x64, 0x7b, 0x50, 0xd2, 0xa8, 0x07, 0x07,
0xc4, 0xea, 0x2d, 0x57, 0xc6, 0x7e, 0xbb, 0x8f, 0x4a, 0x33, 0x3c, 0xd2, 0x8c, 0xae, 0xe0, 0xf2,
0x84, 0xdd, 0x64, 0x69, 0x62, 0x94, 0x93, 0x5d, 0xa8, 0xbf, 0x94, 0x3d, 0x61, 0x2f, 0x64, 0xd7,
0x30, 0x5c, 0x67, 0x2f, 0xd2, 0xaa, 0xdf, 0xd5, 0x3b, 0x83, 0xff, 0x25, 0x6d, 0x21, 0x94, 0xc3,
0xe0, 0x69, 0x67, 0x7e, 0x3c, 0x96, 0x80, 0xde, 0xeb, 0x2e, 0xa1, 0xde, 0x49, 0x29, 0x8c, 0xab,
0x9c, 0x6a, 0xf2, 0xdd, 0xd7, 0x58, 0x51, 0x2b, 0xf2, 0xe8, 0x16, 0xfe, 0x79, 0x59, 0xdf, 0x06,
0xde, 0x00, 0x2d, 0x17, 0x0f, 0xc6, 0xe1, 0x64, 0x30, 0xef, 0x4f, 0x69, 0xeb, 0x56, 0x52, 0xc7,
0x04, 0xcf, 0x3f, 0xdb, 0xc0, 0x56, 0x52, 0x1b, 0x7c, 0x84, 0x61, 0xcd, 0x27, 0x14, 0xfe, 0x68,
0xd3, 0x6a, 0x88, 0xeb, 0xc6, 0x5a, 0x31, 0x78, 0xcb, 0x71, 0xd5, 0x1e, 0xbf, 0xe4, 0x6a, 0xf2,
0xbb, 0xe4, 0x6a, 0x76, 0xab, 0x85, 0x33, 0x60, 0x6e, 0x1e, 0x3c, 0xf7, 0xc7, 0x8e, 0x9e, 0x54,
0xe0, 0x31, 0x54, 0x5d, 0xb8, 0x87, 0xae, 0x77, 0x02, 0x2f, 0x7c, 0xbd, 0x66, 0xb7, 0x18, 0xd5,
0xc1, 0xf2, 0xda, 0xa6, 0x4b, 0x3f, 0xf1, 0xee, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xd1, 0x76,
0x1f, 0xa7, 0x03, 0x00, 0x00,
}

View File

@@ -0,0 +1,150 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: blog/tags/proto/tags.proto
package tags
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
api "github.com/micro/go-micro/v3/api"
client "github.com/micro/go-micro/v3/client"
server "github.com/micro/go-micro/v3/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Tags service
func NewTagsEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Tags service
type TagsService interface {
// Increase count creates the tag or bumps the counter
IncreaseCount(ctx context.Context, in *IncreaseCountRequest, opts ...client.CallOption) (*IncreaseCountResponse, error)
// Decreases the counter
DecreaseCount(ctx context.Context, in *DecreaseCountRequest, opts ...client.CallOption) (*DecreaseCountResponse, error)
List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error)
// Change properties of a tag, currently only the title
Update(ctx context.Context, in *UpdateRequest, opts ...client.CallOption) (*UpdateResponse, error)
}
type tagsService struct {
c client.Client
name string
}
func NewTagsService(name string, c client.Client) TagsService {
return &tagsService{
c: c,
name: name,
}
}
func (c *tagsService) IncreaseCount(ctx context.Context, in *IncreaseCountRequest, opts ...client.CallOption) (*IncreaseCountResponse, error) {
req := c.c.NewRequest(c.name, "Tags.IncreaseCount", in)
out := new(IncreaseCountResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tagsService) DecreaseCount(ctx context.Context, in *DecreaseCountRequest, opts ...client.CallOption) (*DecreaseCountResponse, error) {
req := c.c.NewRequest(c.name, "Tags.DecreaseCount", in)
out := new(DecreaseCountResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tagsService) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) {
req := c.c.NewRequest(c.name, "Tags.List", in)
out := new(ListResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *tagsService) Update(ctx context.Context, in *UpdateRequest, opts ...client.CallOption) (*UpdateResponse, error) {
req := c.c.NewRequest(c.name, "Tags.Update", in)
out := new(UpdateResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Tags service
type TagsHandler interface {
// Increase count creates the tag or bumps the counter
IncreaseCount(context.Context, *IncreaseCountRequest, *IncreaseCountResponse) error
// Decreases the counter
DecreaseCount(context.Context, *DecreaseCountRequest, *DecreaseCountResponse) error
List(context.Context, *ListRequest, *ListResponse) error
// Change properties of a tag, currently only the title
Update(context.Context, *UpdateRequest, *UpdateResponse) error
}
func RegisterTagsHandler(s server.Server, hdlr TagsHandler, opts ...server.HandlerOption) error {
type tags interface {
IncreaseCount(ctx context.Context, in *IncreaseCountRequest, out *IncreaseCountResponse) error
DecreaseCount(ctx context.Context, in *DecreaseCountRequest, out *DecreaseCountResponse) error
List(ctx context.Context, in *ListRequest, out *ListResponse) error
Update(ctx context.Context, in *UpdateRequest, out *UpdateResponse) error
}
type Tags struct {
tags
}
h := &tagsHandler{hdlr}
return s.Handle(s.NewHandler(&Tags{h}, opts...))
}
type tagsHandler struct {
TagsHandler
}
func (h *tagsHandler) IncreaseCount(ctx context.Context, in *IncreaseCountRequest, out *IncreaseCountResponse) error {
return h.TagsHandler.IncreaseCount(ctx, in, out)
}
func (h *tagsHandler) DecreaseCount(ctx context.Context, in *DecreaseCountRequest, out *DecreaseCountResponse) error {
return h.TagsHandler.DecreaseCount(ctx, in, out)
}
func (h *tagsHandler) List(ctx context.Context, in *ListRequest, out *ListResponse) error {
return h.TagsHandler.List(ctx, in, out)
}
func (h *tagsHandler) Update(ctx context.Context, in *UpdateRequest, out *UpdateResponse) error {
return h.TagsHandler.Update(ctx, in, out)
}

View File

@@ -0,0 +1,62 @@
syntax = "proto3";
package tags;
service Tags {
// Increase count creates the tag or bumps the counter
rpc IncreaseCount(IncreaseCountRequest) returns (IncreaseCountResponse) {}
// Decreases the counter
rpc DecreaseCount(DecreaseCountRequest) returns (DecreaseCountResponse) {}
rpc List(ListRequest) returns (ListResponse) {}
// Change properties of a tag, currently only the title
rpc Update(UpdateRequest) returns (UpdateResponse){}
}
message Tag {
// The id of the parent object
string parentID = 1;
// Type is useful for namespacing and listing across parents,
// ie. list tags for posts, customers etc.
string type = 2;
string slug = 3;
string title = 4;
int64 count = 5;
}
message IncreaseCountRequest {
string parentID = 1;
string type = 2;
string title = 3;
}
message IncreaseCountResponse{}
message DecreaseCountRequest{
string parentID = 1;
string type = 2;
string title = 3;
}
message DecreaseCountResponse{}
message UpdateRequest {
string parentID = 1;
string type = 2;
string title = 3;
}
message UpdateResponse{}
// ListRequest: list either by parent id or type.
// Optionally filter by min or max count.
message ListRequest{
string parentID = 1;
string type = 2;
int64 minCount = 3;
int64 maxCount = 4;
}
message ListResponse{
repeated Tag tags = 1;
}