diff --git a/README.md b/README.md index fb3d7fb1..cc073713 100644 --- a/README.md +++ b/README.md @@ -170,10 +170,10 @@ This sample uses the following libraries. |Library Name|Version| |:---|:---:| -|echo|4.7.2| -|gorm|1.23.8| +|echo|4.9.0| +|gorm|1.23.10| |go-playground/validator.v9|9.31.0| -|zap|1.21.0| +|zap|1.23.0| ## Contribution Please read [CONTRIBUTING.md](https://github.com/ybkuroki/go-webapp-sample/blob/master/CONTRIBUTING.md) for proposing new functions, reporting bugs and submitting pull requests before contributing to this repository. diff --git a/config/config.go b/config/config.go index bcf05b6d..0053ba46 100644 --- a/config/config.go +++ b/config/config.go @@ -6,7 +6,7 @@ import ( "fmt" "os" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) // Config represents the composition of yml settings. diff --git a/controller/book_test.go b/controller/book_test.go index bb272104..31f58807 100644 --- a/controller/book_test.go +++ b/controller/book_test.go @@ -36,7 +36,8 @@ func TestGetBook_Success(t *testing.T) { router.ServeHTTP(rec, req) entity := &model.Book{} - data, _ := entity.FindByID(container.GetRepository(), 1) + opt := entity.FindByID(container.GetRepository(), 1) + data, _ := opt.Take() assert.Equal(t, http.StatusOK, rec.Code) assert.JSONEq(t, test.ConvertToString(data), rec.Body.String()) @@ -57,7 +58,7 @@ func TestGetBook_Failure(t *testing.T) { router.ServeHTTP(rec, req) assert.Equal(t, http.StatusBadRequest, rec.Code) - assert.Equal(t, "\"failed to fetch data\"\n", rec.Body.String()) + assert.Equal(t, "\"none value taken\"\n", rec.Body.String()) } func TestGetBookList_Success(t *testing.T) { @@ -94,7 +95,8 @@ func TestCreateBook_Success(t *testing.T) { router.ServeHTTP(rec, req) entity := &model.Book{} - data, _ := entity.FindByID(container.GetRepository(), 1) + opt := entity.FindByID(container.GetRepository(), 1) + data, _ := opt.Take() assert.Equal(t, http.StatusOK, rec.Code) assert.JSONEq(t, test.ConvertToString(data), rec.Body.String()) @@ -150,7 +152,8 @@ func TestUpdateBook_Success(t *testing.T) { router.ServeHTTP(rec, req) entity := &model.Book{} - data, _ := entity.FindByID(container.GetRepository(), 1) + opt := entity.FindByID(container.GetRepository(), 1) + data, _ := opt.Take() assert.Equal(t, http.StatusOK, rec.Code) assert.JSONEq(t, test.ConvertToString(data), rec.Body.String()) @@ -205,7 +208,8 @@ func TestDeleteBook_Success(t *testing.T) { setUpTestData(container) entity := &model.Book{} - data, _ := entity.FindByID(container.GetRepository(), 1) + opt := entity.FindByID(container.GetRepository(), 1) + data, _ := opt.Take() uri := util.NewRequestBuilder().URL(APIBooks).PathParams("1").Build().GetRequestURL() req := test.NewJSONRequest("DELETE", uri, nil) @@ -279,8 +283,8 @@ func createResultForBindError() *dto.BookDto { func createResultForValidationError() map[string]string { return map[string]string{ - "isbn": "ISBNは、10文字以上20文字以下で入力してください", - "title": "書籍タイトルは、3文字以上50文字以下で入力してください", + "isbn": dto.ValidationErrMessageBookISBN, + "title": dto.ValidationErrMessageBookTitle, } } diff --git a/go.mod b/go.mod index 242df494..ca4fd011 100644 --- a/go.mod +++ b/go.mod @@ -9,16 +9,17 @@ require ( github.com/go-openapi/swag v0.19.15 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect github.com/gorilla/sessions v1.2.1 - github.com/jackc/pgproto3/v2 v2.3.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.1 // indirect github.com/labstack/echo-contrib v0.13.0 github.com/labstack/echo/v4 v4.9.0 github.com/leodido/go-urn v1.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect + github.com/moznion/go-optional v0.5.0 github.com/stretchr/testify v1.8.0 github.com/swaggo/echo-swagger v1.3.4 - github.com/swaggo/swag v1.8.5 + github.com/swaggo/swag v1.8.6 github.com/valyala/fasttemplate v1.2.1 go.uber.org/zap v1.23.0 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa @@ -29,11 +30,11 @@ require ( gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v9 v9.31.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 - gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.3.6 - gorm.io/driver/postgres v1.3.9 + gorm.io/driver/postgres v1.3.10 gorm.io/driver/sqlite v1.3.6 - gorm.io/gorm v1.23.8 + gorm.io/gorm v1.23.10 ) require ( @@ -49,12 +50,12 @@ require ( github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.12.1 // indirect + github.com/jackc/pgconn v1.13.0 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.11.0 // indirect - github.com/jackc/pgx/v4 v4.16.1 // indirect + github.com/jackc/pgtype v1.12.0 // indirect + github.com/jackc/pgx/v4 v4.17.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -67,5 +68,5 @@ require ( go.uber.org/multierr v1.6.0 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 0fc825ee..96c6ed57 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8= -github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= +github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= +github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -83,26 +83,26 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y= -github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= +github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs= -github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y= -github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= +github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= +github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= @@ -152,6 +152,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/moznion/go-optional v0.5.0 h1:BGfkHyvSbdfGP4F7x7ywxg6wltAagG/BGOXoEyBTBlQ= +github.com/moznion/go-optional v0.5.0/go.mod h1:lTyBRKsQPhzFQZb5M+v4cCOYLuD9JUgP0izTOjR8lsw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= @@ -195,8 +197,8 @@ github.com/swaggo/echo-swagger v1.3.4/go.mod h1:vh8QAdbHtTXwTSaWzc1Nby7zMYJd/g0F github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a h1:kAe4YSu0O0UFn1DowNo2MY5p6xzqtJ/wQ7LZynSvGaY= github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= -github.com/swaggo/swag v1.8.5 h1:7NgtfXsXE+jrcOwRyiftGKW7Ppydj7tZiVenuRf1fE4= -github.com/swaggo/swag v1.8.5/go.mod h1:jMLeXOOmYyjk8PvHTsXBdrubsNd9gUJTTCzL5iBnseg= +github.com/swaggo/swag v1.8.6 h1:2rgOaLbonWu1PLP6G+/rYjSvPg0jQE0HtrEKuE380eg= +github.com/swaggo/swag v1.8.6/go.mod h1:jMLeXOOmYyjk8PvHTsXBdrubsNd9gUJTTCzL5iBnseg= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= @@ -338,12 +340,13 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.3.6 h1:BhX1Y/RyALb+T9bZ3t07wLnPZBukt+IRkMn8UZSNbGM= gorm.io/driver/mysql v1.3.6/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c= -gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg= -gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U= +gorm.io/driver/postgres v1.3.10 h1:Fsd+pQpFMGlGxxVMUPJhNo8gG8B1lKtk8QQ4/VZZAJw= +gorm.io/driver/postgres v1.3.10/go.mod h1:whNfh5WhhHs96honoLjBAMwJGYEuA3m1hvgUbNXhPCw= gorm.io/driver/sqlite v1.3.6 h1:Fi8xNYCUplOqWiPa3/GuCeowRNBRGTf62DEmhMDHeQQ= gorm.io/driver/sqlite v1.3.6/go.mod h1:Sg1/pvnKtbQ7jLXxfZa+jSHvoX8hoZA8cn4xllOMTgE= gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE= gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.10 h1:4Ne9ZbzID9GUxRkllxN4WjJKpsHx8YbKvekVdgyWh24= +gorm.io/gorm v1.23.10/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/logger/logger.go b/logger/logger.go index d05c90fb..391344f9 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -9,7 +9,7 @@ import ( "go.uber.org/zap" "gopkg.in/natefinch/lumberjack.v2" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" gormLogger "gorm.io/gorm/logger" ) diff --git a/model/account.go b/model/account.go index 5e58af7f..1c115eec 100644 --- a/model/account.go +++ b/model/account.go @@ -1,8 +1,6 @@ package model import ( - "encoding/json" - "github.com/ybkuroki/go-webapp-sample/repository" "golang.org/x/crypto/bcrypt" ) @@ -70,7 +68,6 @@ func convertToAccount(rec *RecordAccount) *Account { } // ToString is return string of object -func (a *Account) ToString() (string, error) { - bytes, err := json.Marshal(a) - return string(bytes), err +func (a *Account) ToString() string { + return toString(a) } diff --git a/model/authority.go b/model/authority.go index 162b034e..3097c7dd 100644 --- a/model/authority.go +++ b/model/authority.go @@ -1,8 +1,6 @@ package model import ( - "encoding/json" - "github.com/ybkuroki/go-webapp-sample/repository" ) @@ -31,7 +29,6 @@ func (a *Authority) Create(rep repository.Repository) (*Authority, error) { } // ToString is return string of object -func (a *Authority) ToString() (string, error) { - bytes, err := json.Marshal(a) - return string(bytes), err +func (a *Authority) ToString() string { + return toString(a) } diff --git a/model/base.go b/model/base.go new file mode 100644 index 00000000..f4c48f6a --- /dev/null +++ b/model/base.go @@ -0,0 +1,18 @@ +package model + +import "encoding/json" + +// DomainObject defines the common interface for domain models. +type DomainObject interface { + Account | Authority | Book | Category | Format +} + +// toString returns the JSON data of the domain models. +func toString[T DomainObject](o *T) string { + var bytes []byte + var err error + if bytes, err = json.Marshal(o); err != nil { + return "" + } + return string(bytes) +} diff --git a/model/book.go b/model/book.go index bb867e51..f6a83588 100644 --- a/model/book.go +++ b/model/book.go @@ -2,10 +2,10 @@ package model import ( "database/sql" - "encoding/json" "errors" "math" + "github.com/moznion/go-optional" "github.com/ybkuroki/go-webapp-sample/repository" "github.com/ybkuroki/go-webapp-sample/util" "gorm.io/gorm" @@ -52,7 +52,7 @@ func NewBook(title string, isbn string, categoryID uint, formatID uint) *Book { } // FindByID returns a book full matched given book's ID. -func (b *Book) FindByID(rep repository.Repository, id uint) (*Book, error) { +func (b *Book) FindByID(rep repository.Repository, id uint) optional.Option[*Book] { var rec RecordBook args := []interface{}{id} @@ -110,10 +110,12 @@ func findRows(rep repository.Repository, sqlquery string, page string, size stri if err = rep.ScanRows(rows, &rec); err != nil { return nil, err } - book, err := convertToBook(&rec) - if err != nil { - return nil, err + + opt := convertToBook(&rec) + if opt.IsNone() { + return nil, errors.New("failed to fetch data") } + book, _ := opt.Take() books = append(books, *book) } return books, nil @@ -179,17 +181,17 @@ func (b *Book) Delete(rep repository.Repository) (*Book, error) { return b, nil } -func convertToBook(rec *RecordBook) (*Book, error) { +func convertToBook(rec *RecordBook) optional.Option[*Book] { if rec.ID == 0 { - return nil, errors.New("failed to fetch data") + return optional.None[*Book]() } c := &Category{ID: rec.CategoryID, Name: rec.CategoryName} f := &Format{ID: rec.FormatID, Name: rec.FormatName} - return &Book{ID: rec.ID, Title: rec.Title, Isbn: rec.Isbn, CategoryID: rec.CategoryID, Category: c, FormatID: rec.FormatID, Format: f}, nil + return optional.Some( + &Book{ID: rec.ID, Title: rec.Title, Isbn: rec.Isbn, CategoryID: rec.CategoryID, Category: c, FormatID: rec.FormatID, Format: f}) } // ToString is return string of object -func (b *Book) ToString() (string, error) { - bytes, err := json.Marshal(b) - return string(bytes), err +func (b *Book) ToString() string { + return toString(b) } diff --git a/model/category.go b/model/category.go index 59ca7777..4f4a42a6 100644 --- a/model/category.go +++ b/model/category.go @@ -1,8 +1,7 @@ package model import ( - "encoding/json" - + "github.com/moznion/go-optional" "github.com/ybkuroki/go-webapp-sample/repository" ) @@ -35,12 +34,12 @@ func (c *Category) Exist(rep repository.Repository, id uint) (bool, error) { } // FindByID returns a category full matched given category's ID. -func (c *Category) FindByID(rep repository.Repository, id uint) (*Category, error) { +func (c *Category) FindByID(rep repository.Repository, id uint) optional.Option[*Category] { var category Category if err := rep.Where("id = ?", id).First(&category).Error; err != nil { - return nil, err + return optional.None[*Category]() } - return &category, nil + return optional.Some(&category) } // FindAll returns all categories of the category table. @@ -61,7 +60,6 @@ func (c *Category) Create(rep repository.Repository) (*Category, error) { } // ToString is return string of object -func (c *Category) ToString() (string, error) { - bytes, err := json.Marshal(c) - return string(bytes), err +func (c *Category) ToString() string { + return toString(c) } diff --git a/model/dto/book.go b/model/dto/book.go index d9c5f5fe..d3627d8a 100644 --- a/model/dto/book.go +++ b/model/dto/book.go @@ -13,6 +13,11 @@ const ( min string = "min" ) +const ( + ValidationErrMessageBookTitle string = "Please enter the title with 3 to 50 characters." + ValidationErrMessageBookISBN string = "Please enter the ISBN with 10 to 20 characters." +) + // BookDto defines a data transfer object for book. type BookDto struct { Title string `validate:"required,min=3,max=50" json:"title"` @@ -57,12 +62,12 @@ func createErrorMessages(errors validator.ValidationErrors) map[string]string { case "Title": switch errors[i].Tag() { case required, min, max: - result["title"] = "書籍タイトルは、3文字以上50文字以下で入力してください" + result["title"] = ValidationErrMessageBookTitle } case "Isbn": switch errors[i].Tag() { case required, min, max: - result["isbn"] = "ISBNは、10文字以上20文字以下で入力してください" + result["isbn"] = ValidationErrMessageBookISBN } } } diff --git a/model/dto/book_test.go b/model/dto/book_test.go index 8cb0c19f..6ea35d5e 100644 --- a/model/dto/book_test.go +++ b/model/dto/book_test.go @@ -9,7 +9,7 @@ import ( func TestValidate_Title2Error(t *testing.T) { dto := createBookForTitle2() result := dto.Validate() - assert.Equal(t, "書籍タイトルは、3文字以上50文字以下で入力してください", result["title"]) + assert.Equal(t, ValidationErrMessageBookTitle, result["title"]) } func TestValidate_Title3Success(t *testing.T) { @@ -39,13 +39,13 @@ func TestValidate_Title50Success(t *testing.T) { func TestValidate_Title51Error(t *testing.T) { dto := createBookForTitle51() result := dto.Validate() - assert.Equal(t, "書籍タイトルは、3文字以上50文字以下で入力してください", result["title"]) + assert.Equal(t, ValidationErrMessageBookTitle, result["title"]) } func TestValidate_Isbn9Error(t *testing.T) { dto := createBookForIsbn9() result := dto.Validate() - assert.Equal(t, "ISBNは、10文字以上20文字以下で入力してください", result["isbn"]) + assert.Equal(t, ValidationErrMessageBookISBN, result["isbn"]) } func TestValidate_Isbn10Success(t *testing.T) { @@ -75,7 +75,7 @@ func TestValidate_Isbn20Success(t *testing.T) { func TestValidate_Isbn21Error(t *testing.T) { dto := createBookForIsbn21() result := dto.Validate() - assert.Equal(t, "ISBNは、10文字以上20文字以下で入力してください", result["isbn"]) + assert.Equal(t, ValidationErrMessageBookISBN, result["isbn"]) } func TestToString(t *testing.T) { diff --git a/model/format.go b/model/format.go index 4b561e90..74371a2b 100644 --- a/model/format.go +++ b/model/format.go @@ -1,8 +1,7 @@ package model import ( - "encoding/json" - + "github.com/moznion/go-optional" "github.com/ybkuroki/go-webapp-sample/repository" ) @@ -23,12 +22,12 @@ func NewFormat(name string) *Format { } // FindByID returns a format full matched given format's ID. -func (f *Format) FindByID(rep repository.Repository, id uint) (*Format, error) { +func (f *Format) FindByID(rep repository.Repository, id uint) optional.Option[*Format] { var format Format if err := rep.Where("id = ?", id).First(&format).Error; err != nil { - return nil, err + return optional.None[*Format]() } - return &format, nil + return optional.Some(&format) } // FindAll returns all formats of the format table. @@ -49,7 +48,6 @@ func (f *Format) Create(rep repository.Repository) (*Format, error) { } // ToString is return string of object -func (f *Format) ToString() (string, error) { - bytes, err := json.Marshal(f) - return string(bytes), err +func (f *Format) ToString() string { + return toString(f) } diff --git a/service/book.go b/service/book.go index 1528dcde..e1a8d5cf 100644 --- a/service/book.go +++ b/service/book.go @@ -38,9 +38,9 @@ func (b *bookService) FindByID(id string) (*model.Book, error) { rep := b.container.GetRepository() book := model.Book{} - result, err := book.FindByID(rep, util.ConvertToUint(id)) - if err != nil { - b.container.GetLogger().GetZapLogger().Errorf(err.Error()) + var result *model.Book + var err error + if result, err = book.FindByID(rep, util.ConvertToUint(id)).Take(); err != nil { return nil, err } return result, nil @@ -108,12 +108,12 @@ func txCreateBook(txrep repository.Repository, dto *dto.BookDto) (*model.Book, e book := dto.Create() category := model.Category{} - if book.Category, err = category.FindByID(txrep, dto.CategoryID); err != nil { + if book.Category, err = category.FindByID(txrep, dto.CategoryID).Take(); err != nil { return nil, err } format := model.Format{} - if book.Format, err = format.FindByID(txrep, dto.FormatID); err != nil { + if book.Format, err = format.FindByID(txrep, dto.FormatID).Take(); err != nil { return nil, err } @@ -149,7 +149,7 @@ func txUpdateBook(txrep repository.Repository, dto *dto.BookDto, id string) (*mo var err error b := model.Book{} - if book, err = b.FindByID(txrep, util.ConvertToUint(id)); err != nil { + if book, err = b.FindByID(txrep, util.ConvertToUint(id)).Take(); err != nil { return nil, err } @@ -159,12 +159,12 @@ func txUpdateBook(txrep repository.Repository, dto *dto.BookDto, id string) (*mo book.FormatID = dto.FormatID category := model.Category{} - if book.Category, err = category.FindByID(txrep, dto.CategoryID); err != nil { + if book.Category, err = category.FindByID(txrep, dto.CategoryID).Take(); err != nil { return nil, err } format := model.Format{} - if book.Format, err = format.FindByID(txrep, dto.FormatID); err != nil { + if book.Format, err = format.FindByID(txrep, dto.FormatID).Take(); err != nil { return nil, err } @@ -196,7 +196,7 @@ func txDeleteBook(txrep repository.Repository, id string) (*model.Book, error) { var err error b := model.Book{} - if book, err = b.FindByID(txrep, util.ConvertToUint(id)); err != nil { + if book, err = b.FindByID(txrep, util.ConvertToUint(id)).Take(); err != nil { return nil, err } diff --git a/service/book_test.go b/service/book_test.go index f0f0cd43..ba519eb8 100644 --- a/service/book_test.go +++ b/service/book_test.go @@ -98,7 +98,7 @@ func TestCreateBook_Success(t *testing.T) { result, err := service.CreateBook(createBookForCreate()) entity := &model.Book{} - data, _ := entity.FindByID(container.GetRepository(), 1) + data, _ := entity.FindByID(container.GetRepository(), 1).Take() assert.Equal(t, data, result) assert.Empty(t, err) @@ -143,7 +143,7 @@ func TestUpdateBook_Success(t *testing.T) { result, err := service.UpdateBook(createBookForCreate(), "1") entity := &model.Book{} - data, _ := entity.FindByID(container.GetRepository(), 1) + data, _ := entity.FindByID(container.GetRepository(), 1).Take() assert.Equal(t, data, result) assert.Empty(t, err) @@ -203,7 +203,7 @@ func TestDeleteBook_Success(t *testing.T) { setUpTestData(container) entity := &model.Book{} - data, _ := entity.FindByID(container.GetRepository(), 1) + data, _ := entity.FindByID(container.GetRepository(), 1).Take() service := NewBookService(container) result, err := service.DeleteBook("1")