Skip to content

Commit 8797f7d

Browse files
authored
fix(bookstore): add support for isbn / authors (#69)
Setting isbn/authors was failing due to not serializing into proper strings in the database.
1 parent 9198dab commit 8797f7d

8 files changed

Lines changed: 692 additions & 629 deletions

File tree

example/bookstore/v1/bookstore.pb.go

Lines changed: 606 additions & 606 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/bookstore/v1/bookstore.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ message Book {
291291
int32 edition = 4 [(google.api.field_behavior) = REQUIRED];
292292

293293
// Field for author.
294-
repeated Author author = 5 [(google.api.field_behavior) = REQUIRED];
294+
repeated Author author = 5;
295295

296296
// Field for path.
297297
string path = 10018;

example/bookstore/v1/bookstore.swagger.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,8 +1515,7 @@
15151515
"isbn",
15161516
"price",
15171517
"published",
1518-
"edition",
1519-
"author"
1518+
"edition"
15201519
]
15211520
},
15221521
"v1BookEdition": {

example/bookstore/v1/bookstore.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ resources:
3030
parents: ["publisher"]
3131
schema:
3232
type: object
33-
required: ["author", "edition", "isbn", "price", "published"]
33+
required: ["edition", "isbn", "price", "published"]
3434
properties:
3535
isbn:
3636
type: array

example/bookstore/v1/bookstore_openapi.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1398,7 +1398,6 @@
13981398
]
13991399
},
14001400
"required": [
1401-
"author",
14021401
"edition",
14031402
"isbn",
14041403
"price",

example/bookstore/v1/bookstore_openapi.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ components:
3636
type: boolean
3737
x-aep-field-number: 3
3838
required:
39-
- author
4039
- edition
4140
- isbn
4241
- price

example/service/service.go

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ func NewBookstoreServer(db *sql.DB) *BookstoreServer {
7474
}
7575

7676
func (s BookstoreServer) CreateBook(_ context.Context, r *bpb.CreateBookRequest) (*bpb.Book, error) {
77-
book := proto.Clone(r.Book).(*bpb.Book)
77+
book, err := NewSerializableBook(proto.Clone(r.Book).(*bpb.Book))
78+
if err != nil {
79+
return nil, status.Errorf(codes.Internal, "failed to create book: %v", err)
80+
}
7881
log.Printf("creating book %q", r)
7982
if r.Id == "" {
8083
var maxID int
@@ -87,23 +90,25 @@ func (s BookstoreServer) CreateBook(_ context.Context, r *bpb.CreateBookRequest)
8790
path := fmt.Sprintf("%v/books/%v", r.Parent, r.Id)
8891
book.Path = path
8992

90-
_, err := s.db.Exec(`
93+
_, err = s.db.Exec(`
9194
INSERT INTO books (path, author, price, published, edition, isbn)
9295
VALUES (?, ?, ?, ?, ?, ?)`,
93-
book.Path, book.Author, book.Price, book.Published, book.Edition, book.Isbn)
96+
book.Path, book.AuthorSerialized, book.Price, book.Published, book.Edition, book.IsbnSerialized)
9497
if err != nil {
9598
return nil, status.Errorf(codes.Internal, "failed to create book: %v", err)
9699
}
97100

98101
log.Printf("created book %q", path)
99-
return book, nil
102+
return book.Book, nil
100103
}
101104

102105
func (s BookstoreServer) ApplyBook(_ context.Context, r *bpb.ApplyBookRequest) (*bpb.Book, error) {
106+
book, err := NewSerializableBook(proto.Clone(r.Book).(*bpb.Book))
107+
if err != nil {
108+
return nil, status.Errorf(codes.Internal, "failed to create book: %v", err)
109+
}
103110
log.Printf("applying book request: %v", r)
104-
book := proto.Clone(r.Book).(*bpb.Book)
105111
book.Path = r.Path
106-
107112
result, err := s.db.Exec(`
108113
INSERT INTO books (path, author, price, published, edition, isbn)
109114
VALUES (?, ?, ?, ?, ?, ?)
@@ -113,7 +118,7 @@ func (s BookstoreServer) ApplyBook(_ context.Context, r *bpb.ApplyBookRequest) (
113118
published = excluded.published,
114119
edition = excluded.edition,
115120
isbn = excluded.isbn`,
116-
book.Path, book.Author, book.Price, book.Published, book.Edition, book.Isbn)
121+
book.Path, book.AuthorSerialized, book.Price, book.Published, book.Edition, book.IsbnSerialized)
117122
if err != nil {
118123
return nil, status.Errorf(codes.Internal, "failed to apply book: %v", err)
119124
}
@@ -126,18 +131,20 @@ func (s BookstoreServer) ApplyBook(_ context.Context, r *bpb.ApplyBookRequest) (
126131
}
127132

128133
log.Printf("applied book %q", book.Path)
129-
return book, nil
134+
return book.Book, nil
130135
}
131136

132137
func (s BookstoreServer) UpdateBook(_ context.Context, r *bpb.UpdateBookRequest) (*bpb.Book, error) {
133-
book := proto.Clone(r.Book).(*bpb.Book)
138+
book, err := NewSerializableBook(proto.Clone(r.Book).(*bpb.Book))
139+
if err != nil {
140+
return nil, status.Errorf(codes.Internal, "failed to create book: %v", err)
141+
}
134142
book.Path = r.Path
135-
136143
result, err := s.db.Exec(`
137144
UPDATE books
138145
SET author = ?, price = ?, published = ?, edition = ?
139146
WHERE path = ?`,
140-
book.Author, book.Price, book.Published, book.Edition, book.Path)
147+
book.AuthorSerialized, book.Price, book.Published, book.Edition, book.Path)
141148
if err != nil {
142149
return nil, status.Errorf(codes.Internal, "failed to update book: %v", err)
143150
}
@@ -151,7 +158,7 @@ func (s BookstoreServer) UpdateBook(_ context.Context, r *bpb.UpdateBookRequest)
151158
}
152159

153160
log.Printf("updated book %q", book.Path)
154-
return book, nil
161+
return book.Book, nil
155162
}
156163

157164
func (s BookstoreServer) DeleteBook(_ context.Context, r *bpb.DeleteBookRequest) (*emptypb.Empty, error) {
@@ -174,23 +181,31 @@ func (s BookstoreServer) DeleteBook(_ context.Context, r *bpb.DeleteBookRequest)
174181

175182
func (s BookstoreServer) GetBook(_ context.Context, r *bpb.GetBookRequest) (*bpb.Book, error) {
176183
book := &bpb.Book{}
184+
185+
// Deserialize the 'author' field from JSON when reading from the database
186+
var authorsSerialized string
187+
var isbnSerialized string
177188
err := s.db.QueryRow(`
178-
SELECT path, author, price, published, edition
189+
SELECT path, author, price, published, edition, isbn
179190
FROM books WHERE path = ?`, r.Path).Scan(
180-
&book.Path, &book.Author, &book.Price, &book.Published, &book.Edition)
181-
191+
&book.Path, &authorsSerialized, &book.Price, &book.Published, &book.Edition, isbnSerialized)
182192
if err == sql.ErrNoRows {
183193
return nil, status.Errorf(codes.NotFound, "book %q not found", r.Path)
184194
}
185195
if err != nil {
186196
return nil, status.Errorf(codes.Internal, "failed to get book: %v", err)
187197
}
198+
err = UnmarshalIntoBook(authorsSerialized, isbnSerialized, book)
199+
if err != nil {
200+
return nil, status.Errorf(codes.Internal, "failed to deserialize book: %v", err)
201+
}
202+
188203
return book, nil
189204
}
190205

191206
func (s BookstoreServer) ListBooks(_ context.Context, r *bpb.ListBooksRequest) (*bpb.ListBooksResponse, error) {
192207
rows, err := s.db.Query(`
193-
SELECT path, author, price, published, edition
208+
SELECT path, author, price, published, edition, isbn
194209
FROM books`)
195210
if err != nil {
196211
return nil, status.Errorf(codes.Internal, "failed to list books: %v", err)
@@ -200,9 +215,17 @@ func (s BookstoreServer) ListBooks(_ context.Context, r *bpb.ListBooksRequest) (
200215
var books []*bpb.Book
201216
for rows.Next() {
202217
book := &bpb.Book{}
203-
if err := rows.Scan(&book.Path, &book.Author, &book.Price, &book.Published, &book.Edition); err != nil {
218+
219+
// Deserialize the 'author' field from JSON when listing books
220+
var authorsSerialized string
221+
var isbnSerialized string
222+
if err := rows.Scan(&book.Path, &authorsSerialized, &book.Price, &book.Published, &book.Edition, &isbnSerialized); err != nil {
204223
return nil, status.Errorf(codes.Internal, "failed to scan book: %v", err)
205224
}
225+
if err := UnmarshalIntoBook(authorsSerialized, isbnSerialized, book); err != nil {
226+
return nil, status.Errorf(codes.Internal, "failed to deserialize authors: %v", err)
227+
}
228+
206229
books = append(books, book)
207230
}
208231
if err = rows.Err(); err != nil {

example/service/types.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package service
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
bpb "github.com/aep-dev/aepc/example/bookstore/v1"
8+
)
9+
10+
type SerializableBook struct {
11+
*bpb.Book
12+
AuthorSerialized string
13+
IsbnSerialized string
14+
}
15+
16+
func NewSerializableBook(b *bpb.Book) (*SerializableBook, error) {
17+
authorSerialized, err := json.Marshal(b.Author)
18+
if err != nil {
19+
return nil, fmt.Errorf("failed to serialize author: %v", err)
20+
}
21+
isbnSerialized, err := json.Marshal(b.Isbn)
22+
if err != nil {
23+
return nil, fmt.Errorf("failed to serialize author: %v", err)
24+
}
25+
return &SerializableBook{
26+
Book: b,
27+
AuthorSerialized: string(authorSerialized),
28+
IsbnSerialized: string(isbnSerialized),
29+
}, nil
30+
}
31+
32+
func UnmarshalIntoBook(authorsSerialized, isbnSerialized string, b *bpb.Book) error {
33+
err := json.Unmarshal([]byte(authorsSerialized), &b.Author)
34+
if err != nil {
35+
return fmt.Errorf("failed to deserialize authors: %v", err)
36+
}
37+
38+
err = json.Unmarshal([]byte(isbnSerialized), &b.Isbn)
39+
if err != nil {
40+
return fmt.Errorf("failed to deserialize isbn: %v", err)
41+
}
42+
return nil
43+
}

0 commit comments

Comments
 (0)