diff --git a/.gitignore b/.gitignore
index 72f5ed7..5c092e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,5 +14,6 @@ _vendor-*/
gin-bin
goAPISkel
goAPISkel.yml
+config.yml
gorm.db
coverage.out
diff --git a/README.md b/README.md
index 45bac13..9e55ca6 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# golang API Skeleton
-[](https://drone.devices.local/mawas/golang-api-skeleton)
+[](https://drone.devices.local/mawas/golang-api-skeleton)
refined skeleton future apis should be based on
diff --git a/go.mod b/go.mod
index 9e1409e..d8c2548 100644
--- a/go.mod
+++ b/go.mod
@@ -3,11 +3,13 @@ module git.devices.local/mawas/golang-api-skeleton
go 1.15
require (
+ github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7 // indirect
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
+ github.com/dgraph-io/badger/v2 v2.2007.2 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
- github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
+ github.com/google/uuid v1.2.0
github.com/magiconair/properties v1.8.4 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/pelletier/go-toml v1.8.1 // indirect
diff --git a/go.sum b/go.sum
index ecddf9b..eb9888f 100644
--- a/go.sum
+++ b/go.sum
@@ -11,16 +11,18 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
+github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
@@ -28,16 +30,21 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -45,10 +52,17 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
+github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k=
+github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
+github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA=
+github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
+github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@@ -77,7 +91,10 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
+github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -86,6 +103,8 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
@@ -182,9 +201,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@@ -198,7 +215,7 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY=
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
@@ -223,7 +240,6 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
@@ -232,7 +248,6 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
@@ -257,6 +272,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
@@ -267,7 +283,6 @@ github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhr
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
-github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
@@ -277,24 +292,23 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg=
github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
-github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
-github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
-github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
@@ -309,7 +323,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -324,6 +340,7 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
@@ -366,6 +383,7 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -381,6 +399,7 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -391,19 +410,18 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -460,9 +478,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
-gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@@ -470,9 +488,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/lib/cmd/cmd.go b/lib/cmd/cmd.go
index b8730ac..ec2d416 100644
--- a/lib/cmd/cmd.go
+++ b/lib/cmd/cmd.go
@@ -1,61 +1,77 @@
package cmd
import (
- "fmt"
"os"
"git.devices.local/mawas/golang-api-skeleton/lib/config"
"github.com/spf13/cobra"
)
-var (
- Version string
- APPName string
- APPDescription string
-)
+// TODO add shell completion
-var rootCmd = &cobra.Command{
- Use: APPName,
- Short: APPDescription,
- Long: APPDescription,
- // SilenceUsage: true,
- // SilenceErrors: true,
- Run: func(cmd *cobra.Command, args []string) {
- },
+func newRootCmd(appName string, appDescription string) *cobra.Command {
+ return &cobra.Command{
+ Use: appName,
+ Short: appDescription,
+ Long: appDescription,
+ // SilenceUsage: true,
+ // SilenceErrors: true,
+ DisableAutoGenTag: true,
+ Run: func(cmd *cobra.Command, args []string) {
+ },
+ }
}
-var versionCmd = &cobra.Command{
- Use: "version",
- Short: "Print the version number",
- Long: "Print the version number",
- Run: func(cmd *cobra.Command, args []string) {
- fmt.Println(APPName, "version:", Version)
- os.Exit(0)
- },
+func newVersionCmd(version string, appName string) *cobra.Command {
+ return &cobra.Command{
+ Use: "version",
+ Aliases: []string{"Version"},
+ Short: "Print the version number",
+ Long: "Print the version number",
+ DisableAutoGenTag: true,
+ Run: func(cmd *cobra.Command, args []string) {
+ cmd.Println(appName, "version", version)
+ os.Exit(0)
+ },
+ }
}
-var sampleCfgCmd = &cobra.Command{
- Use: "sample-config",
- Short: "Print sample config",
- Long: "Print an example configuration file content",
- Run: func(cmd *cobra.Command, args []string) {
- fmt.Println(config.Sample)
- os.Exit(0)
- },
+
+func newSampleCfgCmd() *cobra.Command {
+ return &cobra.Command{
+ Use: "sample-config",
+ Short: "Print sample config",
+ Long: "Print an example configuration file content",
+ Run: func(cmd *cobra.Command, args []string) {
+ cmd.Println(config.Sample)
+ os.Exit(0)
+ },
+ }
+}
+
+func newSampleCLICmd() *cobra.Command {
+ return &cobra.Command{
+ Use: "cli",
+ Short: "Interactive CLI",
+ Long: "Interactive CLI maybe",
+ Run: func(cmd *cobra.Command, args []string) {
+ cmd.Println("here might be an cli")
+ os.Exit(0)
+ },
+ }
}
-func Initialize(version string, appName string, appDescription string) error {
+func Initialize(version string, appName string, appDescription string) (string, map[string]interface{}, error) {
var cfgFile string
- Version = version
- APPName = appName
- APPDescription = appDescription
+ rootCmd := newRootCmd(appName, appDescription)
rootCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
if err := cmd.Usage(); err != nil {
os.Exit(1)
}
os.Exit(0)
})
- rootCmd.AddCommand(versionCmd)
- rootCmd.AddCommand(sampleCfgCmd)
+ rootCmd.AddCommand(newVersionCmd(version, appName))
+ rootCmd.AddCommand(newSampleCfgCmd())
+ // rootCmd.AddCommand(newSampleCLICmd())
rootCmd.Flags().StringVarP(&cfgFile, "config", "c", "", "config file")
flagCfg := map[string]interface{}{
@@ -73,10 +89,44 @@ func Initialize(version string, appName string, appDescription string) error {
"database.maxlifetime": rootCmd.Flags().IntP("database-maxlifetime", "t", 0, "database max connection lifetime"),
}
if err := rootCmd.Execute(); err != nil {
- return err
- }
- if err := config.Initialize(appName, cfgFile, flagCfg); err != nil {
- return err
+ return cfgFile, flagCfg, err
}
- return nil
+ return cfgFile, flagCfg, nil
}
+
+// func Initialize(version string, appName string, appDescription string) error {
+// var cfgFile string
+// rootCmd := newRootCmd(appName, appDescription)
+// rootCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
+// if err := cmd.Usage(); err != nil {
+// os.Exit(1)
+// }
+// os.Exit(0)
+// })
+// rootCmd.AddCommand(newVersionCmd(version, appName))
+// rootCmd.AddCommand(newSampleCfgCmd())
+// // rootCmd.AddCommand(newSampleCLICmd())
+//
+// rootCmd.Flags().StringVarP(&cfgFile, "config", "c", "", "config file")
+// flagCfg := map[string]interface{}{
+// "application.environment": rootCmd.Flags().StringP("environment", "e", "", "application environment"),
+// "application.listenaddress": rootCmd.Flags().StringP("listenaddress", "l", "", "application listenaddress or host"),
+// "application.port": rootCmd.Flags().IntP("port", "p", 0, "application listenport"),
+// "database.host": rootCmd.Flags().StringP("database-host", "H", "", "database host"),
+// "database.port": rootCmd.Flags().IntP("database-port", "P", 0, "database port"),
+// "database.dialect": rootCmd.Flags().StringP("database-dialect", "D", "", "database dialect"),
+// "database.database": rootCmd.Flags().StringP("database-name", "d", "", "database name"),
+// "database.user": rootCmd.Flags().StringP("database-user", "u", "", "database user"),
+// "database.password": rootCmd.Flags().StringP("database-password", "s", "", "database password"),
+// "database.maxopenconn": rootCmd.Flags().IntP("database-maxopen", "o", 0, "database max open connections"),
+// "database.maxidleconn": rootCmd.Flags().IntP("database-maxidle", "i", 0, "database max idle connections"),
+// "database.maxlifetime": rootCmd.Flags().IntP("database-maxlifetime", "t", 0, "database max connection lifetime"),
+// }
+// if err := rootCmd.Execute(); err != nil {
+// return err
+// }
+// if err := config.Initialize(appName, cfgFile, flagCfg); err != nil {
+// return err
+// }
+// return nil
+// }
diff --git a/lib/cmd/cmd_test.go b/lib/cmd/cmd_test.go
index d00cd3f..49bddb0 100644
--- a/lib/cmd/cmd_test.go
+++ b/lib/cmd/cmd_test.go
@@ -4,11 +4,34 @@ import (
"testing"
)
+// func TestVersion(t *testing.T) {
+// // FIXME maybe PanicOnExit0 can help regarding unexpected call to os.Exit(0) during test
+// appname := "unittest"
+// version := "0.0.1"
+// cmd := newVersionCmd(version, appname)
+// b := bytes.NewBufferString("")
+// cmd.SetOut(b)
+// if err := cmd.Execute(); err != nil {
+// t.Fatal(err)
+// }
+// out, err := ioutil.ReadAll(b)
+// if err != nil {
+// t.Fatal(err)
+// }
+// expected := appname + " version " + version
+// got := strings.TrimSpace(string(out))
+// if got != expected {
+// t.Fatalf("expected \"%s\" got \"%s\"", expected, got)
+// }
+// }
+
func TestInitalize(t *testing.T) {
- args := []string{"--database-user", "unittest"}
- rootCmd.SetArgs(args)
- if err := Initialize("0.0.1", "unittest", ""); err != nil {
- t.Errorf("%v\n", err)
+ _, flagCfg, err := Initialize("0.0.1", "unittest", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(flagCfg) == 0 {
+ t.Fatal("flag configuration missing")
}
}
@@ -19,6 +42,6 @@ func TestInitalize(t *testing.T) {
// t.Errorf("%v\n", err)
// }
// if err := Initialize("0.0.1", "unittest", ""); err != nil {
-// t.Errorf("%v\n", err)
+// t.Errorf("%v\n", err)
// }
// }
diff --git a/lib/common/common.go b/lib/common/common.go
new file mode 100644
index 0000000..faf40dc
--- /dev/null
+++ b/lib/common/common.go
@@ -0,0 +1,126 @@
+package common
+
+import (
+ "database/sql/driver"
+ "time"
+
+ "github.com/google/uuid"
+ "gorm.io/gorm"
+)
+
+type UsernameContextKey string
+
+// GUID -> new datatype
+type GUID uuid.UUID
+
+// StringToGUID -> parse string to GUID
+func StringToGUID(s string) (GUID, error) {
+ id, err := uuid.Parse(s)
+ return GUID(id), err
+}
+
+// String -> String Representation of Binary16
+func (guid GUID) String() string {
+ return uuid.UUID(guid).String()
+}
+
+// GormDataType -> sets type to binary(16)
+func (guid GUID) GormDataType() string {
+ return "binary(16)"
+}
+
+func (guid GUID) MarshalJSON() ([]byte, error) {
+ s := uuid.UUID(guid)
+ str := "\"" + s.String() + "\""
+ return []byte(str), nil
+}
+
+func (guid *GUID) UnmarshalJSON(by []byte) error {
+ s, err := uuid.ParseBytes(by)
+ *guid = GUID(s)
+ return err
+}
+
+// Scan --> tells GORM how to receive from the database
+func (guid *GUID) Scan(value interface{}) error {
+ bytes, _ := value.([]byte)
+ parseByte, err := uuid.FromBytes(bytes)
+ *guid = GUID(parseByte)
+ return err
+}
+
+// Value -> tells GORM how to save into the database
+func (guid GUID) Value() (driver.Value, error) {
+ return uuid.UUID(guid).MarshalBinary()
+}
+
+type BasicFields struct {
+ CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
+ CreatedByDB GUID `gorm:"column:created_by" json:"-"`
+ CreatedByJSON string `gorm:"-" json:"created_by"`
+ UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
+ UpdatedByDB GUID `gorm:"column:updated_by" json:"-"`
+ UpdatedByJSON string `gorm:"-" json:"updated_by"`
+ DeletedAtDB gorm.DeletedAt `gorm:"column:deleted_at" json:"-"`
+ DeletedAtJSON *time.Time `gorm:"-" json:"deleted_at,omitempty"`
+ DeletedBy string `gorm:"column:deleted_by" json:"deleted_by,omitempty"`
+}
+
+func (basicFields *BasicFields) BeforeCreate(tx *gorm.DB) error {
+ if userID, ok := tx.Get("userID"); ok {
+ if guid, ok := userID.(GUID); ok {
+ basicFields.CreatedByDB = guid
+ basicFields.UpdatedByDB = guid
+ }
+ }
+ return nil
+}
+
+func (basicFields *BasicFields) AfterCreate(tx *gorm.DB) error {
+ if username, ok := tx.Get("username"); ok {
+ if name, ok := username.(string); ok {
+ basicFields.CreatedByJSON = name
+ basicFields.UpdatedByJSON = name
+ }
+ }
+ return nil
+}
+
+type GUIDPKicPK struct {
+ ID uint64 `gorm:"primaryKey;column:id" json:"id"`
+ BasicFields
+}
+
+type ModelGUIDPK struct {
+ ID GUID `gorm:"primaryKey;column:id" json:"id"`
+ BasicFields
+}
+
+func (guidPK *ModelGUIDPK) BeforeCreate(tx *gorm.DB) error {
+ id, err := uuid.NewRandom()
+ guidPK.ID = GUID(id)
+ if userID, ok := tx.Get("userID"); ok {
+ if guid, ok := userID.(GUID); ok {
+ guidPK.CreatedByDB = guid
+ guidPK.UpdatedByDB = guid
+ }
+ }
+ return err
+}
+
+type ModelHiddenGUIDPK struct {
+ ID GUID `gorm:"primaryKey;column:id" json:"-"`
+ BasicFields
+}
+
+func (guidPK *ModelHiddenGUIDPK) BeforeCreate(tx *gorm.DB) error {
+ id, err := uuid.NewRandom()
+ guidPK.ID = GUID(id)
+ if userID, ok := tx.Get("userID"); ok {
+ if guid, ok := userID.(GUID); ok {
+ guidPK.CreatedByDB = guid
+ guidPK.UpdatedByDB = guid
+ }
+ }
+ return err
+}
diff --git a/lib/config/config.go b/lib/config/config.go
index fbcfd29..f10d7de 100644
--- a/lib/config/config.go
+++ b/lib/config/config.go
@@ -121,7 +121,7 @@ func validateEnvironment(environment string) error {
func validateDatabaseDialect(dialect string) error {
if err := validation.Validate(
dialect,
- validation.In(MYSQL, POSTGRES, MSSQL),
+ validation.In(MYSQL, POSTGRES, MSSQL, "sqlite"),
); err != nil {
return fmt.Errorf(
"database.dialect (must be one of %s, %s or %s)",
diff --git a/lib/database/database.go b/lib/database/database.go
index 1b09db1..540d1f6 100644
--- a/lib/database/database.go
+++ b/lib/database/database.go
@@ -1,14 +1,18 @@
package database
import (
+ "log"
+ "os"
"strconv"
"strings"
+ "time"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/sqlite"
"gorm.io/driver/sqlserver"
"gorm.io/gorm"
+ "gorm.io/gorm/logger"
)
type Credentials struct {
@@ -59,13 +63,22 @@ func (c *Credentials) getDSN() gorm.Dialector {
" sslmode=disable connect_timeout=5"
return postgres.Open(dsn)
case "sqlite":
- return sqlite.Open("gorm.db")
+ // return sqlite.Open("gorm.db")
+ return sqlite.Open("file::memory:?cache=shared")
}
return nil
}
func Connect(c Credentials) (*gorm.DB, error) {
- db, err := gorm.Open(c.getDSN(), &gorm.Config{})
+ newLogger := logger.New(
+ log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
+ logger.Config{
+ SlowThreshold: time.Second, // Slow SQL threshold
+ LogLevel: logger.Info, // Log level
+ Colorful: true, // Disable color
+ },
+ )
+ db, err := gorm.Open(c.getDSN(), &gorm.Config{Logger: newLogger})
if err != nil {
return nil, err
}
diff --git a/lib/utils/utils.go b/lib/utils/utils.go
new file mode 100644
index 0000000..7cb8e6e
--- /dev/null
+++ b/lib/utils/utils.go
@@ -0,0 +1,60 @@
+package utils
+
+import (
+ "encoding/json"
+ "fmt"
+ "math/rand"
+ "strings"
+ "time"
+)
+
+const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+const (
+ letterIdxBits = 6 // 6 bits to represent a letter index
+ letterIdxMask = 1<= 0; {
+ if remain == 0 {
+ cache, remain = src.Int63(), letterIdxMax
+ }
+ if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
+ sb.WriteByte(letterBytes[idx])
+ i--
+ }
+ cache >>= letterIdxBits
+ remain--
+ }
+ return sb.String()
+}
+
+func RandInt(s int, e int) int {
+ var integer int
+ for {
+ integer = rand.Intn(e)
+ if integer > s {
+ break
+ }
+ }
+ return integer
+}
+
+func PrettyPrintJSON(s interface{}) {
+ switch s.(type) {
+ case string:
+ var j map[string]interface{}
+ json.Unmarshal([]byte(s.(string)), &j)
+ // jsonString, _ := json.MarshalIndent(j, "", " ")
+ jsonString, _ := json.Marshal(j)
+ fmt.Println(string(jsonString))
+ default:
+ jsonString, _ := json.MarshalIndent(s, "", " ")
+ fmt.Println(string(jsonString))
+ }
+}
diff --git a/main.go b/main.go
index 36b7f02..a8bb6b7 100644
--- a/main.go
+++ b/main.go
@@ -1,14 +1,37 @@
package main
import (
- "fmt"
"os"
+ "strings"
+ "time"
+ "git.devices.local/mawas/golang-api-skeleton/lib/cache"
"git.devices.local/mawas/golang-api-skeleton/lib/cmd"
+ "git.devices.local/mawas/golang-api-skeleton/lib/common"
+ "git.devices.local/mawas/golang-api-skeleton/lib/config"
+ "git.devices.local/mawas/golang-api-skeleton/lib/database"
+ "git.devices.local/mawas/golang-api-skeleton/lib/utils"
+ "git.devices.local/mawas/golang-api-skeleton/models"
+ "git.devices.local/mawas/golang-api-skeleton/repositories"
+ "git.devices.local/mawas/golang-api-skeleton/services"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
+// https://towardsdatascience.com/building-restful-apis-in-golang-e3fe6e3f8f95
+// https://www.voile.com/voile-straps.html
+
+// FIXME how to set unique index for username to make soft deletes possible but disallow duplicates... also how to cache a username which got delete and recerated... user ID would get overwritten, maybe pre/suffix deleted username?
+// TODO replace uuids with ulids
+// TODO use badgerdb for permissions? path:[token1, token2...]
+// TODO add database loadbalancing feature... so allow more hosts use first as default and other ones as fallback
+// TODO add userid and username to repo
+// TODO usrid and username for cli user is hardcoded.. no need to live in database
+// TODO get-stats cli command... which means unix socket support to communicate with server
+// TODO data versioning which will be used as reference from the log, also with predictive analytics for restore which means versioning of reference objects needs to be considered
+// TODO request body store as reference for log
+// TODO because their is a badgerdb cache which tokens are existing or which userids are existing make an existence check at uuid generation just do be sure
+
var (
Version string // allows to set version on build
APPName string // allows to overwrite app name on build
@@ -27,16 +50,153 @@ func main() {
"version": Version,
"app": APPName,
})
- // config priority: flags > env > config file
// cobra sets env if flag is given so that viper can pick it up
- if err := cmd.Initialize(Version, APPName, APPDescription); err != nil {
+ cfgFile, flagCfg, err := cmd.Initialize(Version, APPName, APPDescription)
+ if err != nil {
+ os.Exit(1)
+ }
+ // config priority: flags > env > config file
+ if err := config.Initialize(APPName, cfgFile, flagCfg); err != nil {
contextLogger.WithFields(log.Fields{
"module": "config",
}).Fatal(err)
}
+ // bootstrap cache
+ c, err := cache.Bootstrap()
+ if err != nil {
+ contextLogger.WithFields(log.Fields{
+ "module": "cache",
+ }).Fatal(err)
+ }
+ defer c.Close()
+ db, err := database.Connect(database.Credentials{
+ Host: viper.GetString("database.host"),
+ Port: viper.GetInt("database.port"),
+ Dialect: viper.GetString("database.dialect"),
+ Database: viper.GetString("database.database"),
+ User: viper.GetString("database.user"),
+ Password: viper.GetString("database.password"),
+ MaxOpenConn: viper.GetInt("database.port"),
+ MaxIdleConn: viper.GetInt("database.port"),
+ MaxLifeTime: viper.GetInt("database.port"),
+ Debug: true,
+ })
+ if err != nil {
+ contextLogger.WithFields(log.Fields{
+ "module": "database",
+ }).Fatal(err)
+ }
+
+ db.AutoMigrate(&models.User{})
+ db.AutoMigrate(&models.Token{})
+ userRepo := repositories.NewUserRepository(db, common.GUID{}, "", nil)
+ userService := services.NewUserService(userRepo)
+
+ // Prefill cache
+ // TODO also add deleted users to cache for old references
+ if userData, err := userService.ReadAll(); err != nil {
+ contextLogger.WithFields(log.Fields{
+ "module": "userService",
+ }).Fatal(err)
+ } else {
+ for i := range userData {
+ if err := c.Set("user:"+userData[i].ID.String(), userData[i].Username); err != nil { // userID -> username mapping
+ contextLogger.WithFields(log.Fields{
+ "module": "cache",
+ }).Fatal(err)
+ }
+ if err := c.Set("user:"+userData[i].Username, userData[i].ID.String()); err != nil { // username -> userID mapping
+ contextLogger.WithFields(log.Fields{
+ "module": "cache",
+ }).Fatal(err)
+ }
+ }
+ }
+
+ var userID common.GUID
+ firstname := strings.ToLower(utils.RandString(utils.RandInt(5, 10)))
+ lastname := strings.ToLower(utils.RandString(utils.RandInt(6, 14)))
+ username := string([]byte(firstname)[0]) + lastname
+ user1 := &models.User{
+ Username: username,
+ Firstname: strings.ToUpper(string([]byte(firstname)[0])) + string([]byte(firstname)[1:]),
+ Lastname: strings.ToUpper(string([]byte(lastname)[0])) + string([]byte(lastname)[1:]),
+ Email: username + "@acme.inc",
+ }
+ if result, err := userService.Create(user1); err != nil {
+ panic(err)
+ } else {
+ utils.PrettyPrintJSON(result)
+ if err := c.Set("user:"+result.ID.String(), result.Username); err != nil { // userID -> username mapping
+ contextLogger.WithFields(log.Fields{
+ "module": "cache",
+ }).Fatal(err)
+ }
+ if err := c.Set("user:"+result.Username, result.ID.String()); err != nil { // username -> userID mapping
+ contextLogger.WithFields(log.Fields{
+ "module": "cache",
+ }).Fatal(err)
+ }
+ userID = result.ID
+ }
+
+ userRepo = repositories.NewUserRepository(db, userID, username, c)
+ userService = services.NewUserService(userRepo)
+ // userID db context?
+ // k := common.UsernameContextKey("username")
+ // ctx := context.WithValue(context.Background(), "username", username)
+ // db = db.WithContext(ctx)
+ // db = db.Set("username", username)
+ // fmt.Println(db.Get("username"))
+
+ // create example token
+ tokenRepo := repositories.NewTokenRepository(db, userID, username, c)
+ tokenService := services.NewTokenService(tokenRepo)
+ token1 := &models.Token{
+ ExpiresAt: time.Now().Add(24 * time.Hour),
+ UserID: userID,
+ Active: true,
+ }
+ if result1, err := tokenService.Create(token1); err != nil {
+ panic(err)
+ } else {
+ utils.PrettyPrintJSON(result1)
+ }
+
+ result1, err := tokenService.ReadAll()
+ if err != nil {
+ panic(err)
+ }
+ utils.PrettyPrintJSON(result1)
+
+ result, err := userService.ReadAll()
+ if err != nil {
+ panic(err)
+ }
+ utils.PrettyPrintJSON(result)
+
+ firstname2 := strings.ToLower(utils.RandString(utils.RandInt(5, 10)))
+ lastname2 := strings.ToLower(utils.RandString(utils.RandInt(6, 14)))
+ username2 := string([]byte(firstname2)[0]) + lastname2
+ user2 := &models.User{
+ Username: username2,
+ Firstname: strings.ToUpper(string([]byte(firstname2)[0])) + string([]byte(firstname2)[1:]),
+ Lastname: strings.ToUpper(string([]byte(lastname2)[0])) + string([]byte(lastname2)[1:]),
+ Email: username2 + "@acme.inc",
+ }
+ if result, err := userService.Create(user2); err != nil {
+ panic(err)
+ } else {
+ utils.PrettyPrintJSON(result)
+ result3, err := userService.ReadByID(result.Username)
+ if err != nil {
+ panic(err)
+ }
+ utils.PrettyPrintJSON(result3)
+ }
+
// db, _ := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{})
- // db.AutoMigrate(&user.User{})
// userRepo := user.NewRepository(db)
// userService := user.NewService(userRepo)
// user1 := &user.User{
@@ -51,8 +211,12 @@ func main() {
// }
// fmt.Println(result)
- fmt.Println("main.go --> Environment:", viper.GetString("application.environment"))
- fmt.Println("main.go --> Listen:", viper.GetString("application.listenaddress"))
- fmt.Println("main.go --> Database Port: ", viper.GetInt("database.port"))
- fmt.Println("main.go --> Application Port:", viper.GetInt("application.port"))
+ // fmt.Println("main.go --> Environment:", viper.GetString("application.environment"))
+ // fmt.Println("main.go --> Listen:", viper.GetString("application.listenaddress"))
+ // fmt.Println("main.go --> Database Port: ", viper.GetInt("database.port"))
+ // fmt.Println("main.go --> Application Port:", viper.GetInt("application.port"))
+ // contextLogger.WithFields(log.Fields{
+ // "module": "config",
+ // }).Fatal("ADSADSASd")
+
}
diff --git a/models/token.go b/models/token.go
new file mode 100644
index 0000000..449aa83
--- /dev/null
+++ b/models/token.go
@@ -0,0 +1,63 @@
+package models
+
+import (
+ "database/sql"
+ "time"
+
+ "git.devices.local/mawas/golang-api-skeleton/lib/cache"
+ "git.devices.local/mawas/golang-api-skeleton/lib/common"
+ "github.com/google/uuid"
+ "gorm.io/gorm"
+)
+
+// Token data model
+type Token struct {
+ common.BasicFields
+ Token common.GUID `gorm:"primaryKey" json:"token"`
+ LastUsedDB sql.NullTime `gorm:"column:last_used" json:"-"`
+ LastUsedJSON *time.Time `gorm:"-" json:"last_used,omitempty"`
+ ExpiresAt time.Time `json:"expires_at"`
+ UserID common.GUID `json:"asd"`
+ Username string `json:"username"`
+ Active bool `json:"active"`
+}
+
+func (token *Token) BeforeCreate(tx *gorm.DB) error {
+ id, err := uuid.NewRandom()
+ token.Token = common.GUID(id)
+ if userID, ok := tx.Get("userID"); ok {
+ if guid, ok := userID.(common.GUID); ok {
+ token.CreatedByDB = guid
+ token.UpdatedByDB = guid
+ }
+ }
+ return err
+}
+
+func (token *Token) AfterFind(tx *gorm.DB) error {
+ if token.LastUsedDB.Valid {
+ token.LastUsedJSON = &token.LastUsedDB.Time
+ }
+ if token.DeletedAtDB.Valid {
+ token.DeletedAtJSON = &token.DeletedAtDB.Time
+ }
+ if cc, ok := tx.Get("cache"); ok {
+ if c, ok := cc.(cache.Cache); ok {
+ if username, err := c.Get("user:" + token.CreatedByDB.String()); err != nil {
+ return err
+ } else if username != nil {
+ token.CreatedByJSON = *username
+ }
+ if username, err := c.Get("user:" + token.UpdatedByDB.String()); err != nil {
+ return err
+ } else if username != nil {
+ token.UpdatedByJSON = *username
+ }
+ if username, err := c.Get("user:" + token.UserID.String()); err != nil {
+ } else if username != nil {
+ token.Username = *username
+ }
+ }
+ }
+ return nil
+}
diff --git a/models/user.go b/models/user.go
new file mode 100644
index 0000000..71c5287
--- /dev/null
+++ b/models/user.go
@@ -0,0 +1,70 @@
+package models
+
+import (
+ "git.devices.local/mawas/golang-api-skeleton/lib/cache"
+ "git.devices.local/mawas/golang-api-skeleton/lib/common"
+ "gorm.io/gorm"
+)
+
+// User data model
+type User struct {
+ common.ModelHiddenGUIDPK
+ Username string `gorm:"unique_index:username" json:"username,omitempty"`
+ Firstname string `json:"firstname,omitempty"`
+ Lastname string `json:"lastname,omitempty"`
+ Email string `json:"email,omitempty"`
+ TokensRef []Token `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-"`
+ Tokens []string `gorm:"-" json:"tokens"`
+ PasswordHash string `json:"-"`
+ Active bool ` json:"active"`
+}
+
+func (user *User) AfterCreate(tx *gorm.DB) error {
+ if username, ok := tx.Get("username"); ok {
+ if name, ok := username.(string); ok {
+ user.CreatedByJSON = name
+ user.UpdatedByJSON = name
+ }
+ }
+ user.Tokens = []string{}
+ return nil
+}
+
+func (user *User) AfterFind(tx *gorm.DB) error {
+ if user.DeletedAtDB.Valid {
+ user.DeletedAtJSON = &user.DeletedAtDB.Time
+ }
+ for i := range user.TokensRef {
+ user.Tokens = append(user.Tokens, user.TokensRef[i].Token.String())
+ }
+ if len(user.Tokens) == 0 {
+ user.Tokens = []string{""}
+ }
+ if cc, ok := tx.Get("cache"); ok {
+ if c, ok := cc.(cache.Cache); ok {
+ if username, err := c.Get("user:" + user.CreatedByDB.String()); err != nil {
+ return err
+ } else if username != nil {
+ user.CreatedByJSON = *username
+ }
+ if username, err := c.Get("user:" + user.UpdatedByDB.String()); err != nil {
+ return err
+ } else if username != nil {
+ user.UpdatedByJSON = *username
+ }
+ }
+ }
+ return nil
+}
+
+// func (user *User) BeforeCreate(tx *gorm.DB) error {
+// // ctx := tx.Statement.Context
+// // username := ctx.Value("username")
+// // switch v := username.(type) {
+// // case nil:
+// // case string:
+// // user.CreatedBy = v
+// // }
+// //
+// return nil
+// }
diff --git a/pkg/user/database.go b/pkg/user/database.go
deleted file mode 100644
index 5958614..0000000
--- a/pkg/user/database.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package user
-
-import "gorm.io/gorm"
-
-type repo struct {
- db *gorm.DB
-}
-
-// NewRepository create new repository
-func NewRepository(db *gorm.DB) Repository {
- return &repo{
- db: db,
- }
-}
-
-func (r *repo) ReadByID(id uint) (*User, error) {
- result := User{}
- err := r.db.First(&result, id).Error
- return &result, err
-}
-
-func (r *repo) ReadAll() ([]*User, error) {
- var result []*User
- err := r.db.Find(&result).Error
- return result, err
-}
-
-func (r *repo) Create(user *User) (*User, error) {
- err := r.db.Create(user).Error
- return user, err
-}
diff --git a/pkg/user/model.go b/pkg/user/model.go
deleted file mode 100644
index 81d7f0a..0000000
--- a/pkg/user/model.go
+++ /dev/null
@@ -1,16 +0,0 @@
-package user
-
-import (
- "gorm.io/gorm"
-)
-
-// User data model
-type User struct {
- gorm.Model
- Username string `gorm:"unique_index:username" json:"username,omitempty"`
- Firstname string `json:"firstname,omitempty"`
- Lastname string `json:"lastname,omitempty"`
- Email string `json:"email,omitempty"`
- PasswordHash string `json:"-"`
- Active bool ` json:"active"`
-}
diff --git a/pkg/user/repository.go b/pkg/user/repository.go
deleted file mode 100644
index d435a46..0000000
--- a/pkg/user/repository.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package user
-
-// Reader
-type Reader interface {
- ReadByID(id uint) (*User, error)
- ReadAll() ([]*User, error)
-}
-
-// Writer
-type Writer interface {
- // Update(user *User) error
- Create(user *User) (*User, error)
- // Delete(user *User) (uint64, error)
-}
-
-// Repository repository interface
-type Repository interface {
- Reader
- Writer
-}
diff --git a/pkg/user/service.go b/pkg/user/service.go
deleted file mode 100644
index 17f2a78..0000000
--- a/pkg/user/service.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package user
-
-// Service service interface
-type Service interface {
- Reader
- Writer
- // Register(user *User) (entity.ID, error)
- // ForgotPassword(user *User) error
- // ChangePassword(user *User, password string) error
- // Validate(user *User) error
- // Auth(user *User, password string) error
- // IsValid(user *User) bool
- // GetRepo() Repository
-}
-
-func NewService(repo Repository) Service {
- return repo
-}
diff --git a/repositories/token.go b/repositories/token.go
new file mode 100644
index 0000000..9c71880
--- /dev/null
+++ b/repositories/token.go
@@ -0,0 +1,53 @@
+// Data access objects layer of model token
+package repositories
+
+import (
+ "git.devices.local/mawas/golang-api-skeleton/lib/cache"
+ "git.devices.local/mawas/golang-api-skeleton/lib/common"
+ model "git.devices.local/mawas/golang-api-skeleton/models"
+ "gorm.io/gorm"
+)
+
+type tokenDAO struct {
+ repo
+}
+
+// NewTokenRepository create new repository for model token
+func NewTokenRepository(db *gorm.DB, userID common.GUID, username string, cache cache.Cache) *tokenDAO {
+ db = db.Set("username", username).Set("userID", userID).Set("cache", cache)
+ return &tokenDAO{
+ repo: repo{
+ db: db,
+ userID: userID,
+ username: username,
+ },
+ }
+}
+
+func (dao *tokenDAO) ReadByKey(key interface{}) (*model.Token, error) {
+ token := model.Token{}
+ err := dao.db.Joins("User").First(&token, key).Error
+ return &token, err
+}
+
+func (dao *tokenDAO) ReadAll() ([]*model.Token, error) {
+ var tokens []*model.Token
+ err := dao.db.Find(&tokens).Error
+ return tokens, err
+}
+
+func (dao *tokenDAO) Create(token *model.Token) (*model.Token, error) {
+ err := dao.db.Create(token).Error
+ if cc, ok := dao.db.Get("cache"); ok {
+ if c, ok := cc.(cache.Cache); ok {
+ if username, err := c.Get("user:" + token.UserID.String()); err != nil {
+ return nil, err
+ } else {
+ if username != nil {
+ token.Username = *username
+ }
+ }
+ }
+ }
+ return token, err
+}
diff --git a/repositories/user.go b/repositories/user.go
new file mode 100644
index 0000000..4045872
--- /dev/null
+++ b/repositories/user.go
@@ -0,0 +1,42 @@
+// Data access objects layer of model user
+package repositories
+
+import (
+ "git.devices.local/mawas/golang-api-skeleton/lib/cache"
+ "git.devices.local/mawas/golang-api-skeleton/lib/common"
+ model "git.devices.local/mawas/golang-api-skeleton/models"
+ "gorm.io/gorm"
+)
+
+type UserDAO struct {
+ repo
+}
+
+// NewUserDAO create new repository for model user
+func NewUserRepository(db *gorm.DB, userID common.GUID, username string, cache cache.Cache) *UserDAO {
+ db = db.Set("username", username).Set("userID", userID).Set("cache", cache)
+ return &UserDAO{
+ repo: repo{
+ db: db,
+ userID: userID,
+ username: username,
+ },
+ }
+}
+
+func (dao *UserDAO) ReadByUsername(username string) (*model.User, error) {
+ result := model.User{}
+ err := dao.db.Where(&model.User{Username: username}).First(&result).Error
+ return &result, err
+}
+
+func (dao *UserDAO) ReadAll() ([]*model.User, error) {
+ var result []*model.User
+ err := dao.db.Preload("TokensRef").Find(&result).Error
+ return result, err
+}
+
+func (dao *UserDAO) Create(user *model.User) (*model.User, error) {
+ err := dao.db.Create(user).Error
+ return user, err
+}
diff --git a/services/token.go b/services/token.go
new file mode 100644
index 0000000..8a7a551
--- /dev/null
+++ b/services/token.go
@@ -0,0 +1,35 @@
+package services
+
+import (
+ model "git.devices.local/mawas/golang-api-skeleton/models"
+)
+
+type tokenRepository interface {
+ ReadByKey(key interface{}) (*model.Token, error)
+ ReadAll() ([]*model.Token, error)
+ Create(token *model.Token) (*model.Token, error)
+}
+
+type TokenService struct {
+ repo tokenRepository
+}
+
+// NewTokenService creates a new TokenService with the given user DAO.
+func NewTokenService(repo tokenRepository) *TokenService {
+ return &TokenService{repo}
+}
+
+// ReadByKey just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs
+func (s *TokenService) ReadByKey(key interface{}) (*model.Token, error) {
+ return s.repo.ReadByKey(key)
+}
+
+// ReadAll just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs
+func (s *TokenService) ReadAll() ([]*model.Token, error) {
+ return s.repo.ReadAll()
+}
+
+// Create just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs
+func (s *TokenService) Create(token *model.Token) (*model.Token, error) {
+ return s.repo.Create(token)
+}
diff --git a/services/user.go b/services/user.go
new file mode 100644
index 0000000..0f7007d
--- /dev/null
+++ b/services/user.go
@@ -0,0 +1,35 @@
+package services
+
+import (
+ model "git.devices.local/mawas/golang-api-skeleton/models"
+)
+
+type userRepository interface {
+ ReadByUsername(username string) (*model.User, error)
+ ReadAll() ([]*model.User, error)
+ Create(user *model.User) (*model.User, error)
+}
+
+type UserService struct {
+ repo userRepository
+}
+
+// NewUserService creates a new UserService with the given user DAO.
+func NewUserService(repo userRepository) *UserService {
+ return &UserService{repo}
+}
+
+// ReadByUsername just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs
+func (s *UserService) ReadByID(id interface{}) (*model.User, error) {
+ return s.repo.ReadByUsername(id.(string))
+}
+
+// ReadAll just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs
+func (s *UserService) ReadAll() ([]*model.User, error) {
+ return s.repo.ReadAll()
+}
+
+// Create just retrieves user using User DAO, here can be additional logic for processing data retrieved by DAOs
+func (s *UserService) Create(user *model.User) (*model.User, error) {
+ return s.repo.Create(user)
+}