yjp 1 년 전
부모
커밋
6b76dc9aaf

+ 8 - 2
go.mod

@@ -8,9 +8,13 @@ require (
 	git.sxidc.com/service-supports/fslog v0.5.9
 	git.sxidc.com/service-supports/websocket v1.3.1
 	github.com/gin-gonic/gin v1.10.0
+	github.com/golang/protobuf v1.5.4
 	github.com/iancoleman/strcase v0.3.0
+	github.com/mwitkow/go-proto-validators v0.3.2
 	github.com/vrecan/death v3.0.1+incompatible
 	go.uber.org/zap v1.27.0
+	google.golang.org/grpc v1.64.0
+	google.golang.org/protobuf v1.34.1
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1
 	gopkg.in/yaml.v3 v3.0.1
 	gorm.io/driver/postgres v1.5.7
@@ -31,8 +35,10 @@ require (
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
 	github.com/go-playground/validator/v10 v10.20.0 // indirect
+	github.com/go-resty/resty/v2 v2.11.0 // indirect
 	github.com/goccy/go-json v0.10.2 // indirect
-	github.com/google/uuid v1.1.1 // indirect
+	github.com/gogo/protobuf v1.3.0 // indirect
+	github.com/google/uuid v1.6.0 // indirect
 	github.com/gorilla/websocket v1.5.0 // indirect
 	github.com/huandu/xstrings v1.3.3 // indirect
 	github.com/imdario/mergo v0.3.11 // indirect
@@ -65,5 +71,5 @@ require (
 	golang.org/x/net v0.25.0 // indirect
 	golang.org/x/sys v0.20.0 // indirect
 	golang.org/x/text v0.15.0 // indirect
-	google.golang.org/protobuf v1.34.1 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
 )

+ 35 - 1
go.sum

@@ -39,13 +39,21 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
 github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
 github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
+github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=
+github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
 github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
@@ -70,6 +78,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
 github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
@@ -91,6 +101,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mwitkow/go-proto-validators v0.3.2 h1:qRlmpTzm2pstMKKzTdvwPCF5QfBNURSlAgN/R+qbKos=
+github.com/mwitkow/go-proto-validators v0.3.2/go.mod h1:ej0Qp0qMgHN/KtDyUt+Q1/tA7a5VarXUOUxD+oeD30w=
 github.com/olahol/melody v1.2.1 h1:xdwRkzHxf+B0w4TKbGpUSSkV516ZucQZJIWLztOWICQ=
 github.com/olahol/melody v1.2.1/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4=
 github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
@@ -144,17 +156,23 @@ golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
 golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
 golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
 golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -163,21 +181,37 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
 golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
+google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
+google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
 google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
 google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

+ 126 - 0
infrastructure/database/data_service/client/client.go

@@ -0,0 +1,126 @@
+package client
+
+import (
+	"git.sxidc.com/go-tools/utils/http_client"
+	"time"
+)
+
+const (
+	defaultTimeoutSec = 30
+)
+
+var instance *Client
+
+func InitInstance(timeout time.Duration) {
+	if instance == nil {
+		if timeout == 0 {
+			timeout = defaultTimeoutSec * time.Second
+		}
+
+		instance = New(timeout)
+	}
+}
+
+func GetInstance() *Client {
+	if instance == nil {
+		panic("还没有调用InitInstance")
+	}
+
+	return instance
+}
+
+type Client struct {
+	client  *http_client.Client
+	timeout time.Duration
+}
+
+func New(timeout time.Duration) *Client {
+	client := http_client.New()
+
+	return &Client{
+		client:  client,
+		timeout: timeout,
+	}
+}
+
+func (c *Client) post(token string, url string, request interface{}, result interface{}) error {
+	req := c.client.NewRequest(http_client.WithNewRequestTimeout(c.timeout))
+
+	resp, err := req.Post(url, request,
+		http_client.WithRequestHeaders(map[string]string{
+			"Content-Type":  "application/json",
+			"Authorization": token,
+		}))
+	if err != nil {
+		return err
+	}
+
+	err = resp.Json(result)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *Client) delete(token string, url string, queryMap map[string]string, result interface{}) error {
+	req := c.client.NewRequest(http_client.WithNewRequestTimeout(c.timeout))
+
+	resp, err := req.Delete(url,
+		http_client.WithRequestHeaders(map[string]string{
+			"Content-Type":  "application/json",
+			"Authorization": token,
+		}),
+		http_client.WithRequestQueryParams(queryMap))
+	if err != nil {
+		return err
+	}
+
+	err = resp.Json(result)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *Client) put(token string, url string, request interface{}, result interface{}) error {
+	req := c.client.NewRequest(http_client.WithNewRequestTimeout(c.timeout))
+
+	resp, err := req.Put(url, request,
+		http_client.WithRequestHeaders(map[string]string{
+			"Content-Type":  "application/json",
+			"Authorization": token,
+		}))
+	if err != nil {
+		return err
+	}
+
+	err = resp.Json(result)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *Client) get(token string, url string, queryMap map[string]string, result interface{}) error {
+	req := c.client.NewRequest(http_client.WithNewRequestTimeout(c.timeout))
+
+	resp, err := req.Get(url,
+		http_client.WithRequestHeaders(map[string]string{
+			"Content-Type":  "application/json",
+			"Authorization": token,
+		}),
+		http_client.WithRequestQueryParams(queryMap))
+	if err != nil {
+		return err
+	}
+
+	err = resp.Json(result)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}

+ 43 - 0
infrastructure/database/data_service/client/data_source.go

@@ -0,0 +1,43 @@
+package client
+
+import (
+	"fmt"
+	"net/url"
+	"strconv"
+)
+
+const (
+	getDataSourcesUrl = "/ds/api/v1/dataSource/query"
+)
+
+func (c *Client) GetDataSources(token string, baseUrl string, namespace string, name string, typeStr string, pageNo int, pageSize int) ([]DataSourceInfo, error) {
+	fullUrl, err := url.JoinPath(baseUrl, getDataSourcesUrl)
+	if err != nil {
+		return nil, err
+	}
+
+	resp := new(struct {
+		Success    bool             `json:"success"`
+		Msg        string           `json:"msg"`
+		Infos      []DataSourceInfo `json:"infos"`
+		TotalCount int64            `json:"totalCount"`
+		PageNo     int64            `json:"pageNo"`
+	})
+
+	err = c.get(token, fullUrl, map[string]string{
+		"namespace": namespace,
+		"name":      name,
+		"type":      typeStr,
+		"pageNo":    strconv.Itoa(pageNo),
+		"pageSize":  strconv.Itoa(pageSize),
+	}, resp)
+	if err != nil {
+		return nil, err
+	}
+
+	if !resp.Success {
+		return nil, fmt.Errorf(resp.Msg)
+	}
+
+	return resp.Infos, nil
+}

+ 17 - 0
infrastructure/database/data_service/client/infos.go

@@ -0,0 +1,17 @@
+package client
+
+type NamespaceInfo struct {
+	ID          string `json:"id"`
+	Name        string `json:"name"`
+	Creator     string `json:"creator"`
+	CreatedTime string `json:"createdTime"`
+}
+
+type DataSourceInfo struct {
+	Namespace   string `json:"namespace"`
+	Name        string `json:"name"`
+	Type        string `json:"type"`
+	Spec        string `json:"spec"`
+	Creator     string `json:"creator"`
+	CreatedTime string `json:"createdTime"`
+}

+ 41 - 0
infrastructure/database/data_service/client/namespace.go

@@ -0,0 +1,41 @@
+package client
+
+import (
+	"fmt"
+	"net/url"
+	"strconv"
+)
+
+const (
+	getNamespacesUrl = "/ds/api/v1/namespace/query"
+)
+
+func (c *Client) GetNamespaces(token string, baseUrl string, name string, pageNo int, pageSize int) ([]NamespaceInfo, error) {
+	fullUrl, err := url.JoinPath(baseUrl, getNamespacesUrl)
+	if err != nil {
+		return nil, err
+	}
+
+	resp := new(struct {
+		Success    bool            `json:"success"`
+		Msg        string          `json:"msg"`
+		Infos      []NamespaceInfo `json:"infos"`
+		TotalCount int64           `json:"totalCount"`
+		PageNo     int64           `json:"pageNo"`
+	})
+
+	err = c.get(token, fullUrl, map[string]string{
+		"name":     name,
+		"pageNo":   strconv.Itoa(pageNo),
+		"pageSize": strconv.Itoa(pageSize),
+	}, resp)
+	if err != nil {
+		return nil, err
+	}
+
+	if !resp.Success {
+		return nil, fmt.Errorf(resp.Msg)
+	}
+
+	return resp.Infos, nil
+}

+ 71 - 0
infrastructure/database/data_service/client/sql.go

@@ -0,0 +1,71 @@
+package client
+
+import (
+	"fmt"
+	"net/url"
+)
+
+const (
+	executeRawSqlUrl = "/ds/api/v1/sql/rawSql/execute"
+	executeSqlUrl    = "/ds/api/v1/sql/execute"
+)
+
+func (c *Client) ExecuteRawSql(token string, baseUrl string,
+	namespace string, dataSource string, sql string, executeParams map[string]any) ([]map[string]any, error) {
+	fullUrl, err := url.JoinPath(baseUrl, executeRawSqlUrl)
+	if err != nil {
+		return nil, err
+	}
+
+	resp := new(struct {
+		Success bool             `json:"success"`
+		Msg     string           `json:"msg"`
+		Results []map[string]any `json:"results"`
+	})
+
+	err = c.post(token, fullUrl, map[string]any{
+		"namespace":     namespace,
+		"dataSource":    dataSource,
+		"sql":           sql,
+		"executeParams": executeParams,
+	}, resp)
+	if err != nil {
+		return nil, err
+	}
+
+	if !resp.Success {
+		return nil, fmt.Errorf(resp.Msg)
+	}
+
+	return resp.Results, nil
+}
+
+func (c *Client) ExecuteSql(token string, baseUrl string,
+	namespace string, dataSource string, name string, executeParams map[string]any) ([]map[string]any, error) {
+	fullUrl, err := url.JoinPath(baseUrl, executeSqlUrl)
+	if err != nil {
+		return nil, err
+	}
+
+	resp := new(struct {
+		Success bool             `json:"success"`
+		Msg     string           `json:"msg"`
+		Results []map[string]any `json:"results"`
+	})
+
+	err = c.post(token, fullUrl, map[string]any{
+		"namespace":     namespace,
+		"dataSource":    dataSource,
+		"name":          name,
+		"executeParams": executeParams,
+	}, resp)
+	if err != nil {
+		return nil, err
+	}
+
+	if !resp.Success {
+		return nil, fmt.Errorf(resp.Msg)
+	}
+
+	return resp.Results, nil
+}

+ 173 - 1
infrastructure/database/data_service/data_service.go

@@ -1,3 +1,175 @@
 package data_service
 
-type DataService struct{}
+import (
+	"git.sxidc.com/go-framework/baize/infrastructure/database/data_service/client"
+	"git.sxidc.com/go-framework/baize/infrastructure/database/data_service/grpc_client"
+	"git.sxidc.com/go-framework/baize/infrastructure/database/data_service/grpc_client/v1/request"
+	"git.sxidc.com/go-framework/baize/infrastructure/database/sql"
+	"git.sxidc.com/go-tools/utils/strutils"
+	"git.sxidc.com/service-supports/fserr"
+	"io"
+	"time"
+)
+
+type Config struct {
+	token       string
+	baseUrl     string
+	grpcAddress string
+	namespace   string
+	dataSource  string
+	timeout     time.Duration
+}
+
+type DataService struct {
+	config     Config
+	client     *client.Client
+	grpcClient *grpc_client.Client
+}
+
+func NewDataService(config Config) (*DataService, error) {
+	c := client.New(config.timeout)
+
+	namespaceInfos, err := c.GetNamespaces(config.token, config.baseUrl, config.namespace, 1, 1)
+	if err != nil {
+		return nil, err
+	}
+
+	if namespaceInfos == nil || len(namespaceInfos) == 0 {
+		return nil, fserr.New("命名空间不存在")
+	}
+
+	dataSourceInfos, err := c.GetDataSources(
+		config.token, config.baseUrl, config.namespace, config.dataSource, "", 1, 1)
+	if err != nil {
+		return nil, err
+	}
+
+	if dataSourceInfos == nil || len(dataSourceInfos) == 0 {
+		return nil, fserr.New("数据源不存在")
+	}
+
+	grpcClient, err := grpc_client.NewClient(config.grpcAddress)
+	if err != nil {
+		return nil, err
+	}
+
+	return &DataService{
+		config:     config,
+		client:     c,
+		grpcClient: grpcClient,
+	}, nil
+}
+
+func DestroyDataService(ds *DataService) error {
+	if ds == nil {
+		return nil
+	}
+
+	err := grpc_client.Destroy(ds.grpcClient)
+	if err != nil {
+		return err
+	}
+
+	ds = nil
+
+	return nil
+}
+
+func (ds *DataService) ExecuteRawSql(sqlStr string, executeParams map[string]any) ([]sql.Result, error) {
+	if strutils.IsStringEmpty(sqlStr) {
+		return make([]sql.Result, 0), nil
+	}
+
+	config := ds.config
+
+	tableRows, err := ds.client.ExecuteRawSql(config.token, config.baseUrl,
+		config.namespace, config.dataSource, sqlStr, executeParams)
+	if err != nil {
+		return nil, err
+	}
+
+	results := make([]sql.Result, len(tableRows))
+	for i, row := range tableRows {
+		results[i] = row
+	}
+
+	return results, nil
+}
+
+func (ds *DataService) ExecuteSql(name string, executeParams map[string]any) ([]sql.Result, error) {
+	if strutils.IsStringEmpty(name) {
+		return nil, fserr.New("没有传递SQL资源名称")
+	}
+
+	config := ds.config
+
+	tableRows, err := ds.client.ExecuteSql(config.token, config.baseUrl,
+		config.namespace, config.dataSource, name, executeParams)
+	if err != nil {
+		return nil, err
+	}
+
+	results := make([]sql.Result, len(tableRows))
+	for i, row := range tableRows {
+		results[i] = row
+	}
+
+	return results, nil
+}
+
+func (ds *DataService) Transaction(txFunc TxFunc) error {
+	stream, err := ds.grpcClient.Transaction()
+	if err != nil {
+		return err
+	}
+
+	defer func() {
+		innerErr := stream.CloseSend()
+		if innerErr != nil {
+			panic(innerErr)
+		}
+	}()
+
+	err = stream.Send(&request.TransactionOperation{
+		Request: &request.TransactionOperation_TransactionBeginRequest{
+			TransactionBeginRequest: &request.TransactionBeginRequest{
+				Token:      ds.config.token,
+				Namespace:  ds.config.namespace,
+				DataSource: ds.config.dataSource,
+			},
+		}})
+	if err != nil {
+		return err
+	}
+
+	resp, err := stream.Recv()
+	if err != nil {
+		return err
+	}
+
+	if !resp.Success {
+		return fserr.New(resp.Msg)
+	}
+
+	err = txFunc(&Transaction{
+		stream: stream,
+	})
+	if err != nil {
+		return err
+	}
+
+	err = stream.Send(&request.TransactionOperation{
+		Request: &request.TransactionOperation_TransactionEndRequest{
+			TransactionEndRequest: &request.TransactionEndRequest{},
+		}})
+	if err != nil {
+		return err
+	}
+
+	_, err = stream.Recv()
+	if err != nil && err != io.EOF {
+		return err
+	}
+
+	return nil
+}

+ 46 - 0
infrastructure/database/data_service/grpc_client/grpc_client.go

@@ -0,0 +1,46 @@
+package grpc_client
+
+import (
+	"context"
+	"git.sxidc.com/go-framework/baize/infrastructure/database/data_service/grpc_client/v1"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials/insecure"
+)
+
+type Client struct {
+	conn         *grpc.ClientConn
+	sqlServiceV1 v1.SqlServiceClient
+}
+
+func NewClient(address string) (*Client, error) {
+	conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()))
+	if err != nil {
+		return nil, err
+	}
+
+	return &Client{
+		conn:         conn,
+		sqlServiceV1: v1.NewSqlServiceClient(conn),
+	}, nil
+}
+
+func Destroy(c *Client) error {
+	if c == nil {
+		return nil
+	}
+
+	err := c.conn.Close()
+	if err != nil {
+		return err
+	}
+
+	c.sqlServiceV1 = nil
+	c.conn = nil
+	c = nil
+
+	return nil
+}
+
+func (c *Client) Transaction() (v1.SqlService_TransactionClient, error) {
+	return c.sqlServiceV1.Transaction(context.Background())
+}

+ 525 - 0
infrastructure/database/data_service/grpc_client/v1/request/sql.pb.go

@@ -0,0 +1,525 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v3.12.4
+// source: v1/request/sql.proto
+
+package request
+
+import (
+	_ "github.com/mwitkow/go-proto-validators"
+	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)
+)
+
+type TransactionBeginRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Token      string `protobuf:"bytes,1,opt,name=Token,proto3" json:"Token,omitempty"`
+	Namespace  string `protobuf:"bytes,2,opt,name=Namespace,proto3" json:"Namespace,omitempty"`
+	DataSource string `protobuf:"bytes,3,opt,name=DataSource,proto3" json:"DataSource,omitempty"`
+}
+
+func (x *TransactionBeginRequest) Reset() {
+	*x = TransactionBeginRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_v1_request_sql_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TransactionBeginRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TransactionBeginRequest) ProtoMessage() {}
+
+func (x *TransactionBeginRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_v1_request_sql_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 TransactionBeginRequest.ProtoReflect.Descriptor instead.
+func (*TransactionBeginRequest) Descriptor() ([]byte, []int) {
+	return file_v1_request_sql_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *TransactionBeginRequest) GetToken() string {
+	if x != nil {
+		return x.Token
+	}
+	return ""
+}
+
+func (x *TransactionBeginRequest) GetNamespace() string {
+	if x != nil {
+		return x.Namespace
+	}
+	return ""
+}
+
+func (x *TransactionBeginRequest) GetDataSource() string {
+	if x != nil {
+		return x.DataSource
+	}
+	return ""
+}
+
+type TransactionEndRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *TransactionEndRequest) Reset() {
+	*x = TransactionEndRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_v1_request_sql_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TransactionEndRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TransactionEndRequest) ProtoMessage() {}
+
+func (x *TransactionEndRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_v1_request_sql_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 TransactionEndRequest.ProtoReflect.Descriptor instead.
+func (*TransactionEndRequest) Descriptor() ([]byte, []int) {
+	return file_v1_request_sql_proto_rawDescGZIP(), []int{1}
+}
+
+type ExecuteRawSqlRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	SQL           string `protobuf:"bytes,1,opt,name=SQL,proto3" json:"SQL,omitempty"`
+	ExecuteParams string `protobuf:"bytes,2,opt,name=ExecuteParams,proto3" json:"ExecuteParams,omitempty"`
+}
+
+func (x *ExecuteRawSqlRequest) Reset() {
+	*x = ExecuteRawSqlRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_v1_request_sql_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ExecuteRawSqlRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExecuteRawSqlRequest) ProtoMessage() {}
+
+func (x *ExecuteRawSqlRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_v1_request_sql_proto_msgTypes[2]
+	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 ExecuteRawSqlRequest.ProtoReflect.Descriptor instead.
+func (*ExecuteRawSqlRequest) Descriptor() ([]byte, []int) {
+	return file_v1_request_sql_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ExecuteRawSqlRequest) GetSQL() string {
+	if x != nil {
+		return x.SQL
+	}
+	return ""
+}
+
+func (x *ExecuteRawSqlRequest) GetExecuteParams() string {
+	if x != nil {
+		return x.ExecuteParams
+	}
+	return ""
+}
+
+type ExecuteSqlRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Name          string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
+	ExecuteParams string `protobuf:"bytes,2,opt,name=ExecuteParams,proto3" json:"ExecuteParams,omitempty"`
+}
+
+func (x *ExecuteSqlRequest) Reset() {
+	*x = ExecuteSqlRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_v1_request_sql_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ExecuteSqlRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ExecuteSqlRequest) ProtoMessage() {}
+
+func (x *ExecuteSqlRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_v1_request_sql_proto_msgTypes[3]
+	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 ExecuteSqlRequest.ProtoReflect.Descriptor instead.
+func (*ExecuteSqlRequest) Descriptor() ([]byte, []int) {
+	return file_v1_request_sql_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ExecuteSqlRequest) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *ExecuteSqlRequest) GetExecuteParams() string {
+	if x != nil {
+		return x.ExecuteParams
+	}
+	return ""
+}
+
+type TransactionOperation struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Types that are assignable to Request:
+	//
+	//	*TransactionOperation_TransactionBeginRequest
+	//	*TransactionOperation_TransactionEndRequest
+	//	*TransactionOperation_ExecuteRawSqlRequest
+	//	*TransactionOperation_ExecuteSqlRequest
+	Request isTransactionOperation_Request `protobuf_oneof:"Request"`
+}
+
+func (x *TransactionOperation) Reset() {
+	*x = TransactionOperation{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_v1_request_sql_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TransactionOperation) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TransactionOperation) ProtoMessage() {}
+
+func (x *TransactionOperation) ProtoReflect() protoreflect.Message {
+	mi := &file_v1_request_sql_proto_msgTypes[4]
+	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 TransactionOperation.ProtoReflect.Descriptor instead.
+func (*TransactionOperation) Descriptor() ([]byte, []int) {
+	return file_v1_request_sql_proto_rawDescGZIP(), []int{4}
+}
+
+func (m *TransactionOperation) GetRequest() isTransactionOperation_Request {
+	if m != nil {
+		return m.Request
+	}
+	return nil
+}
+
+func (x *TransactionOperation) GetTransactionBeginRequest() *TransactionBeginRequest {
+	if x, ok := x.GetRequest().(*TransactionOperation_TransactionBeginRequest); ok {
+		return x.TransactionBeginRequest
+	}
+	return nil
+}
+
+func (x *TransactionOperation) GetTransactionEndRequest() *TransactionEndRequest {
+	if x, ok := x.GetRequest().(*TransactionOperation_TransactionEndRequest); ok {
+		return x.TransactionEndRequest
+	}
+	return nil
+}
+
+func (x *TransactionOperation) GetExecuteRawSqlRequest() *ExecuteRawSqlRequest {
+	if x, ok := x.GetRequest().(*TransactionOperation_ExecuteRawSqlRequest); ok {
+		return x.ExecuteRawSqlRequest
+	}
+	return nil
+}
+
+func (x *TransactionOperation) GetExecuteSqlRequest() *ExecuteSqlRequest {
+	if x, ok := x.GetRequest().(*TransactionOperation_ExecuteSqlRequest); ok {
+		return x.ExecuteSqlRequest
+	}
+	return nil
+}
+
+type isTransactionOperation_Request interface {
+	isTransactionOperation_Request()
+}
+
+type TransactionOperation_TransactionBeginRequest struct {
+	TransactionBeginRequest *TransactionBeginRequest `protobuf:"bytes,1,opt,name=TransactionBeginRequest,proto3,oneof"`
+}
+
+type TransactionOperation_TransactionEndRequest struct {
+	TransactionEndRequest *TransactionEndRequest `protobuf:"bytes,2,opt,name=TransactionEndRequest,proto3,oneof"`
+}
+
+type TransactionOperation_ExecuteRawSqlRequest struct {
+	ExecuteRawSqlRequest *ExecuteRawSqlRequest `protobuf:"bytes,3,opt,name=ExecuteRawSqlRequest,proto3,oneof"`
+}
+
+type TransactionOperation_ExecuteSqlRequest struct {
+	ExecuteSqlRequest *ExecuteSqlRequest `protobuf:"bytes,4,opt,name=ExecuteSqlRequest,proto3,oneof"`
+}
+
+func (*TransactionOperation_TransactionBeginRequest) isTransactionOperation_Request() {}
+
+func (*TransactionOperation_TransactionEndRequest) isTransactionOperation_Request() {}
+
+func (*TransactionOperation_ExecuteRawSqlRequest) isTransactionOperation_Request() {}
+
+func (*TransactionOperation_ExecuteSqlRequest) isTransactionOperation_Request() {}
+
+var File_v1_request_sql_proto protoreflect.FileDescriptor
+
+var file_v1_request_sql_proto_rawDesc = []byte{
+	0x0a, 0x14, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2f, 0x73, 0x71, 0x6c,
+	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x77, 0x69, 0x74,
+	0x6b, 0x6f, 0x77, 0x2f, 0x67, 0x6f, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x76, 0x61, 0x6c,
+	0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f,
+	0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x85, 0x01, 0x0a, 0x17, 0x54, 0x72, 0x61, 0x6e,
+	0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x65, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x05, 0x54, 0x6f, 0x6b, 0x65,
+	0x6e, 0x12, 0x24, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x09, 0x4e, 0x61,
+	0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x26, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x53,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f,
+	0x02, 0x58, 0x01, 0x52, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22,
+	0x17, 0x0a, 0x15, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e,
+	0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x56, 0x0a, 0x14, 0x45, 0x78, 0x65, 0x63,
+	0x75, 0x74, 0x65, 0x52, 0x61, 0x77, 0x53, 0x71, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x18, 0x0a, 0x03, 0x53, 0x51, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x06, 0xe2,
+	0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x03, 0x53, 0x51, 0x4c, 0x12, 0x24, 0x0a, 0x0d, 0x45, 0x78,
+	0x65, 0x63, 0x75, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0d, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73,
+	0x22, 0x55, 0x0a, 0x11, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x71, 0x6c, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x42, 0x06, 0xe2, 0xdf, 0x1f, 0x02, 0x58, 0x01, 0x52, 0x04, 0x4e, 0x61, 0x6d,
+	0x65, 0x12, 0x24, 0x0a, 0x0d, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x50, 0x61, 0x72, 0x61,
+	0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74,
+	0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0xf8, 0x02, 0x0a, 0x14, 0x54, 0x72, 0x61, 0x6e,
+	0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+	0x12, 0x5c, 0x0a, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42,
+	0x65, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x20, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e,
+	0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x65, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
+	0x6f, 0x6e, 0x42, 0x65, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x56,
+	0x0a, 0x15, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e,
+	0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
+	0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52,
+	0x15, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x53, 0x0a, 0x14, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74,
+	0x65, 0x52, 0x61, 0x77, 0x53, 0x71, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x45,
+	0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x61, 0x77, 0x53, 0x71, 0x6c, 0x52, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x14, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x52, 0x61,
+	0x77, 0x53, 0x71, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x11, 0x45,
+	0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x71, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x71, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x48, 0x00, 0x52, 0x11, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x53, 0x71, 0x6c,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x42, 0x1f, 0x5a, 0x1d, 0x64, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70,
+	0x63, 0x5f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x71, 0x75,
+	0x65, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_v1_request_sql_proto_rawDescOnce sync.Once
+	file_v1_request_sql_proto_rawDescData = file_v1_request_sql_proto_rawDesc
+)
+
+func file_v1_request_sql_proto_rawDescGZIP() []byte {
+	file_v1_request_sql_proto_rawDescOnce.Do(func() {
+		file_v1_request_sql_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_request_sql_proto_rawDescData)
+	})
+	return file_v1_request_sql_proto_rawDescData
+}
+
+var file_v1_request_sql_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_v1_request_sql_proto_goTypes = []interface{}{
+	(*TransactionBeginRequest)(nil), // 0: request.TransactionBeginRequest
+	(*TransactionEndRequest)(nil),   // 1: request.TransactionEndRequest
+	(*ExecuteRawSqlRequest)(nil),    // 2: request.ExecuteRawSqlRequest
+	(*ExecuteSqlRequest)(nil),       // 3: request.ExecuteSqlRequest
+	(*TransactionOperation)(nil),    // 4: request.TransactionOperation
+}
+var file_v1_request_sql_proto_depIdxs = []int32{
+	0, // 0: request.TransactionOperation.TransactionBeginRequest:type_name -> request.TransactionBeginRequest
+	1, // 1: request.TransactionOperation.TransactionEndRequest:type_name -> request.TransactionEndRequest
+	2, // 2: request.TransactionOperation.ExecuteRawSqlRequest:type_name -> request.ExecuteRawSqlRequest
+	3, // 3: request.TransactionOperation.ExecuteSqlRequest:type_name -> request.ExecuteSqlRequest
+	4, // [4:4] is the sub-list for method output_type
+	4, // [4:4] is the sub-list for method input_type
+	4, // [4:4] is the sub-list for extension type_name
+	4, // [4:4] is the sub-list for extension extendee
+	0, // [0:4] is the sub-list for field type_name
+}
+
+func init() { file_v1_request_sql_proto_init() }
+func file_v1_request_sql_proto_init() {
+	if File_v1_request_sql_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_v1_request_sql_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TransactionBeginRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_v1_request_sql_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TransactionEndRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_v1_request_sql_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ExecuteRawSqlRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_v1_request_sql_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ExecuteSqlRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_v1_request_sql_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TransactionOperation); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	file_v1_request_sql_proto_msgTypes[4].OneofWrappers = []interface{}{
+		(*TransactionOperation_TransactionBeginRequest)(nil),
+		(*TransactionOperation_TransactionEndRequest)(nil),
+		(*TransactionOperation_ExecuteRawSqlRequest)(nil),
+		(*TransactionOperation_ExecuteSqlRequest)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_v1_request_sql_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   5,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_v1_request_sql_proto_goTypes,
+		DependencyIndexes: file_v1_request_sql_proto_depIdxs,
+		MessageInfos:      file_v1_request_sql_proto_msgTypes,
+	}.Build()
+	File_v1_request_sql_proto = out.File
+	file_v1_request_sql_proto_rawDesc = nil
+	file_v1_request_sql_proto_goTypes = nil
+	file_v1_request_sql_proto_depIdxs = nil
+}

+ 76 - 0
infrastructure/database/data_service/grpc_client/v1/request/sql.validator.pb.go

@@ -0,0 +1,76 @@
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
+// source: v1/request/sql.proto
+
+package request
+
+import (
+	fmt "fmt"
+	math "math"
+	proto "github.com/golang/protobuf/proto"
+	_ "github.com/mwitkow/go-proto-validators"
+	github_com_mwitkow_go_proto_validators "github.com/mwitkow/go-proto-validators"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+func (this *TransactionBeginRequest) Validate() error {
+	if this.Token == "" {
+		return github_com_mwitkow_go_proto_validators.FieldError("Token", fmt.Errorf(`value '%v' must not be an empty string`, this.Token))
+	}
+	if this.Namespace == "" {
+		return github_com_mwitkow_go_proto_validators.FieldError("Namespace", fmt.Errorf(`value '%v' must not be an empty string`, this.Namespace))
+	}
+	if this.DataSource == "" {
+		return github_com_mwitkow_go_proto_validators.FieldError("DataSource", fmt.Errorf(`value '%v' must not be an empty string`, this.DataSource))
+	}
+	return nil
+}
+func (this *TransactionEndRequest) Validate() error {
+	return nil
+}
+func (this *ExecuteRawSqlRequest) Validate() error {
+	if this.SQL == "" {
+		return github_com_mwitkow_go_proto_validators.FieldError("SQL", fmt.Errorf(`value '%v' must not be an empty string`, this.SQL))
+	}
+	return nil
+}
+func (this *ExecuteSqlRequest) Validate() error {
+	if this.Name == "" {
+		return github_com_mwitkow_go_proto_validators.FieldError("Name", fmt.Errorf(`value '%v' must not be an empty string`, this.Name))
+	}
+	return nil
+}
+func (this *TransactionOperation) Validate() error {
+	if oneOfNester, ok := this.GetRequest().(*TransactionOperation_TransactionBeginRequest); ok {
+		if oneOfNester.TransactionBeginRequest != nil {
+			if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.TransactionBeginRequest); err != nil {
+				return github_com_mwitkow_go_proto_validators.FieldError("TransactionBeginRequest", err)
+			}
+		}
+	}
+	if oneOfNester, ok := this.GetRequest().(*TransactionOperation_TransactionEndRequest); ok {
+		if oneOfNester.TransactionEndRequest != nil {
+			if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.TransactionEndRequest); err != nil {
+				return github_com_mwitkow_go_proto_validators.FieldError("TransactionEndRequest", err)
+			}
+		}
+	}
+	if oneOfNester, ok := this.GetRequest().(*TransactionOperation_ExecuteRawSqlRequest); ok {
+		if oneOfNester.ExecuteRawSqlRequest != nil {
+			if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.ExecuteRawSqlRequest); err != nil {
+				return github_com_mwitkow_go_proto_validators.FieldError("ExecuteRawSqlRequest", err)
+			}
+		}
+	}
+	if oneOfNester, ok := this.GetRequest().(*TransactionOperation_ExecuteSqlRequest); ok {
+		if oneOfNester.ExecuteSqlRequest != nil {
+			if err := github_com_mwitkow_go_proto_validators.CallValidatorIfExists(oneOfNester.ExecuteSqlRequest); err != nil {
+				return github_com_mwitkow_go_proto_validators.FieldError("ExecuteSqlRequest", err)
+			}
+		}
+	}
+	return nil
+}

+ 163 - 0
infrastructure/database/data_service/grpc_client/v1/response/sql.pb.go

@@ -0,0 +1,163 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v3.12.4
+// source: v1/response/sql.proto
+
+package response
+
+import (
+	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)
+)
+
+type TransactionResponse struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Success bool   `protobuf:"varint,1,opt,name=Success,proto3" json:"Success,omitempty"`
+	Msg     string `protobuf:"bytes,2,opt,name=Msg,proto3" json:"Msg,omitempty"`
+	Results string `protobuf:"bytes,3,opt,name=Results,proto3" json:"Results,omitempty"`
+}
+
+func (x *TransactionResponse) Reset() {
+	*x = TransactionResponse{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_v1_response_sql_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TransactionResponse) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TransactionResponse) ProtoMessage() {}
+
+func (x *TransactionResponse) ProtoReflect() protoreflect.Message {
+	mi := &file_v1_response_sql_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 TransactionResponse.ProtoReflect.Descriptor instead.
+func (*TransactionResponse) Descriptor() ([]byte, []int) {
+	return file_v1_response_sql_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *TransactionResponse) GetSuccess() bool {
+	if x != nil {
+		return x.Success
+	}
+	return false
+}
+
+func (x *TransactionResponse) GetMsg() string {
+	if x != nil {
+		return x.Msg
+	}
+	return ""
+}
+
+func (x *TransactionResponse) GetResults() string {
+	if x != nil {
+		return x.Results
+	}
+	return ""
+}
+
+var File_v1_response_sql_proto protoreflect.FileDescriptor
+
+var file_v1_response_sql_proto_rawDesc = []byte{
+	0x0a, 0x15, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2f, 0x73, 0x71,
+	0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x22, 0x5b, 0x0a, 0x13, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+	0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63,
+	0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65,
+	0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x03, 0x4d, 0x73, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x42, 0x20,
+	0x5a, 0x1e, 0x64, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x61, 0x70,
+	0x69, 0x2f, 0x70, 0x62, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
+	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_v1_response_sql_proto_rawDescOnce sync.Once
+	file_v1_response_sql_proto_rawDescData = file_v1_response_sql_proto_rawDesc
+)
+
+func file_v1_response_sql_proto_rawDescGZIP() []byte {
+	file_v1_response_sql_proto_rawDescOnce.Do(func() {
+		file_v1_response_sql_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_response_sql_proto_rawDescData)
+	})
+	return file_v1_response_sql_proto_rawDescData
+}
+
+var file_v1_response_sql_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_v1_response_sql_proto_goTypes = []interface{}{
+	(*TransactionResponse)(nil), // 0: response.TransactionResponse
+}
+var file_v1_response_sql_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] 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_v1_response_sql_proto_init() }
+func file_v1_response_sql_proto_init() {
+	if File_v1_response_sql_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_v1_response_sql_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TransactionResponse); 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_v1_response_sql_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_v1_response_sql_proto_goTypes,
+		DependencyIndexes: file_v1_response_sql_proto_depIdxs,
+		MessageInfos:      file_v1_response_sql_proto_msgTypes,
+	}.Build()
+	File_v1_response_sql_proto = out.File
+	file_v1_response_sql_proto_rawDesc = nil
+	file_v1_response_sql_proto_goTypes = nil
+	file_v1_response_sql_proto_depIdxs = nil
+}

+ 78 - 0
infrastructure/database/data_service/grpc_client/v1/sql.pb.go

@@ -0,0 +1,78 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.1
+// 	protoc        v3.12.4
+// source: v1/sql.proto
+
+package v1
+
+import (
+	request "git.sxidc.com/go-framework/baize/infrastructure/database/data_service/grpc_client/v1/request"
+	response "git.sxidc.com/go-framework/baize/infrastructure/database/data_service/grpc_client/v1/response"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+)
+
+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)
+)
+
+var File_v1_sql_proto protoreflect.FileDescriptor
+
+var file_v1_sql_proto_rawDesc = []byte{
+	0x0a, 0x0c, 0x76, 0x31, 0x2f, 0x73, 0x71, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02,
+	0x76, 0x31, 0x1a, 0x14, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2f, 0x73,
+	0x71, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73,
+	0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2f, 0x73, 0x71, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32,
+	0x5f, 0x0a, 0x0a, 0x53, 0x71, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a,
+	0x0b, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x2e, 0x72,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
+	0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x1d, 0x2e, 0x72, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
+	0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01,
+	0x42, 0x17, 0x5a, 0x15, 0x64, 0x73, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f,
+	0x61, 0x70, 0x69, 0x2f, 0x70, 0x62, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x33,
+}
+
+var file_v1_sql_proto_goTypes = []interface{}{
+	(*request.TransactionOperation)(nil), // 0: request.TransactionOperation
+	(*response.TransactionResponse)(nil), // 1: response.TransactionResponse
+}
+var file_v1_sql_proto_depIdxs = []int32{
+	0, // 0: v1.SqlService.Transaction:input_type -> request.TransactionOperation
+	1, // 1: v1.SqlService.Transaction:output_type -> response.TransactionResponse
+	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_v1_sql_proto_init() }
+func file_v1_sql_proto_init() {
+	if File_v1_sql_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_v1_sql_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   0,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_v1_sql_proto_goTypes,
+		DependencyIndexes: file_v1_sql_proto_depIdxs,
+	}.Build()
+	File_v1_sql_proto = out.File
+	file_v1_sql_proto_rawDesc = nil
+	file_v1_sql_proto_goTypes = nil
+	file_v1_sql_proto_depIdxs = nil
+}

+ 139 - 0
infrastructure/database/data_service/grpc_client/v1/sql_grpc.pb.go

@@ -0,0 +1,139 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.2.0
+// - protoc             v3.12.4
+// source: v1/sql.proto
+
+package v1
+
+import (
+	context "context"
+	request "git.sxidc.com/go-framework/baize/infrastructure/database/data_service/grpc_client/v1/request"
+	response "git.sxidc.com/go-framework/baize/infrastructure/database/data_service/grpc_client/v1/response"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// SqlServiceClient is the client API for SqlService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type SqlServiceClient interface {
+	Transaction(ctx context.Context, opts ...grpc.CallOption) (SqlService_TransactionClient, error)
+}
+
+type sqlServiceClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewSqlServiceClient(cc grpc.ClientConnInterface) SqlServiceClient {
+	return &sqlServiceClient{cc}
+}
+
+func (c *sqlServiceClient) Transaction(ctx context.Context, opts ...grpc.CallOption) (SqlService_TransactionClient, error) {
+	stream, err := c.cc.NewStream(ctx, &SqlService_ServiceDesc.Streams[0], "/v1.SqlService/Transaction", opts...)
+	if err != nil {
+		return nil, err
+	}
+	x := &sqlServiceTransactionClient{stream}
+	return x, nil
+}
+
+type SqlService_TransactionClient interface {
+	Send(*request.TransactionOperation) error
+	Recv() (*response.TransactionResponse, error)
+	grpc.ClientStream
+}
+
+type sqlServiceTransactionClient struct {
+	grpc.ClientStream
+}
+
+func (x *sqlServiceTransactionClient) Send(m *request.TransactionOperation) error {
+	return x.ClientStream.SendMsg(m)
+}
+
+func (x *sqlServiceTransactionClient) Recv() (*response.TransactionResponse, error) {
+	m := new(response.TransactionResponse)
+	if err := x.ClientStream.RecvMsg(m); err != nil {
+		return nil, err
+	}
+	return m, nil
+}
+
+// SqlServiceServer is the server API for SqlService service.
+// All implementations must embed UnimplementedSqlServiceServer
+// for forward compatibility
+type SqlServiceServer interface {
+	Transaction(SqlService_TransactionServer) error
+	mustEmbedUnimplementedSqlServiceServer()
+}
+
+// UnimplementedSqlServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedSqlServiceServer struct {
+}
+
+func (UnimplementedSqlServiceServer) Transaction(SqlService_TransactionServer) error {
+	return status.Errorf(codes.Unimplemented, "method Transaction not implemented")
+}
+func (UnimplementedSqlServiceServer) mustEmbedUnimplementedSqlServiceServer() {}
+
+// UnsafeSqlServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to SqlServiceServer will
+// result in compilation errors.
+type UnsafeSqlServiceServer interface {
+	mustEmbedUnimplementedSqlServiceServer()
+}
+
+func RegisterSqlServiceServer(s grpc.ServiceRegistrar, srv SqlServiceServer) {
+	s.RegisterService(&SqlService_ServiceDesc, srv)
+}
+
+func _SqlService_Transaction_Handler(srv interface{}, stream grpc.ServerStream) error {
+	return srv.(SqlServiceServer).Transaction(&sqlServiceTransactionServer{stream})
+}
+
+type SqlService_TransactionServer interface {
+	Send(*response.TransactionResponse) error
+	Recv() (*request.TransactionOperation, error)
+	grpc.ServerStream
+}
+
+type sqlServiceTransactionServer struct {
+	grpc.ServerStream
+}
+
+func (x *sqlServiceTransactionServer) Send(m *response.TransactionResponse) error {
+	return x.ServerStream.SendMsg(m)
+}
+
+func (x *sqlServiceTransactionServer) Recv() (*request.TransactionOperation, error) {
+	m := new(request.TransactionOperation)
+	if err := x.ServerStream.RecvMsg(m); err != nil {
+		return nil, err
+	}
+	return m, nil
+}
+
+// SqlService_ServiceDesc is the grpc.ServiceDesc for SqlService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var SqlService_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "v1.SqlService",
+	HandlerType: (*SqlServiceServer)(nil),
+	Methods:     []grpc.MethodDesc{},
+	Streams: []grpc.StreamDesc{
+		{
+			StreamName:    "Transaction",
+			Handler:       _SqlService_Transaction_Handler,
+			ServerStreams: true,
+			ClientStreams: true,
+		},
+	},
+	Metadata: "v1/sql.proto",
+}

+ 129 - 0
infrastructure/database/data_service/transaction.go

@@ -0,0 +1,129 @@
+package data_service
+
+import (
+	"encoding/json"
+	"git.sxidc.com/go-framework/baize/infrastructure/database/data_service/grpc_client/v1"
+	"git.sxidc.com/go-framework/baize/infrastructure/database/data_service/grpc_client/v1/request"
+	"git.sxidc.com/go-framework/baize/infrastructure/database/sql"
+	"git.sxidc.com/service-supports/fserr"
+)
+
+type TxFunc func(tx *Transaction) error
+
+type Transaction struct {
+	stream v1.SqlService_TransactionClient
+}
+
+func (tx *Transaction) ExecuteRawSql(sqlStr string, executeParams map[string]any) ([]sql.Result, error) {
+	var retErr error
+
+	defer func() {
+		if retErr != nil {
+			innerErr := tx.stream.CloseSend()
+			if innerErr != nil {
+				panic(innerErr)
+			}
+		}
+	}()
+
+	executeParamsJsonBytes, err := json.Marshal(executeParams)
+	if err != nil {
+		retErr = err
+		return nil, retErr
+	}
+
+	err = tx.stream.SendMsg(&request.TransactionOperation{
+		Request: &request.TransactionOperation_ExecuteRawSqlRequest{
+			ExecuteRawSqlRequest: &request.ExecuteRawSqlRequest{
+				SQL:           sqlStr,
+				ExecuteParams: string(executeParamsJsonBytes),
+			},
+		},
+	})
+	if err != nil {
+		retErr = err
+		return nil, retErr
+	}
+
+	resp, err := tx.stream.Recv()
+	if err != nil {
+		retErr = err
+		return nil, retErr
+	}
+
+	if !resp.Success {
+		retErr = fserr.New(resp.Msg)
+		return nil, retErr
+	}
+
+	tableRows := make([]map[string]any, 0)
+	err = json.Unmarshal([]byte(resp.Results), &tableRows)
+	if err != nil {
+		retErr = err
+		return nil, retErr
+	}
+
+	results := make([]sql.Result, len(tableRows))
+	for i, row := range tableRows {
+		results[i] = row
+	}
+
+	return results, nil
+}
+
+func (tx *Transaction) ExecuteSql(name string, executeParams map[string]any) ([]sql.Result, error) {
+	var retErr error
+
+	defer func() {
+		if retErr != nil {
+			innerErr := tx.stream.CloseSend()
+			if innerErr != nil {
+				panic(innerErr)
+			}
+		}
+	}()
+
+	executeParamsJsonBytes, err := json.Marshal(executeParams)
+	if err != nil {
+		retErr = err
+		return nil, retErr
+	}
+
+	err = tx.stream.Send(&request.TransactionOperation{
+		Request: &request.TransactionOperation_ExecuteSqlRequest{
+			ExecuteSqlRequest: &request.ExecuteSqlRequest{
+				Name:          name,
+				ExecuteParams: string(executeParamsJsonBytes),
+			},
+		},
+	})
+	if err != nil {
+		retErr = err
+		return nil, retErr
+	}
+
+	resp, err := tx.stream.Recv()
+	if err != nil {
+		retErr = err
+		return nil, retErr
+	}
+
+	if !resp.Success {
+		retErr = fserr.New(resp.Msg)
+		return nil, retErr
+	}
+
+	tableRows := make([]map[string]any, 0)
+	err = json.Unmarshal([]byte(resp.Results), &tableRows)
+	if err != nil {
+		retErr = err
+		return nil, retErr
+	}
+
+	results := make([]sql.Result, len(tableRows))
+	for i, row := range tableRows {
+		results[i] = row
+	}
+
+	return results, nil
+}

+ 3 - 3
infrastructure/database/error.go

@@ -1,13 +1,13 @@
 package database
 
 import (
-	"errors"
+	"git.sxidc.com/service-supports/fserr"
 	"strings"
 )
 
 var (
-	ErrDBRecordHasExist = errors.New("记录已存在")
-	ErrDBRecordNotExist = errors.New("记录不存在")
+	ErrDBRecordHasExist = fserr.New("记录已存在")
+	ErrDBRecordNotExist = fserr.New("记录不存在")
 )
 
 func IsErrorDBRecordHasExist(err error) bool {

+ 10 - 3
infrastructure/database/operations/db.go

@@ -1,8 +1,8 @@
 package operations
 
 import (
-	"errors"
 	"fmt"
+	"git.sxidc.com/service-supports/fserr"
 	"gorm.io/driver/postgres"
 	"gorm.io/gorm"
 	"gorm.io/gorm/logger"
@@ -10,7 +10,7 @@ import (
 
 func newGormDB(dbConfig *Config) (*gorm.DB, error) {
 	if dbConfig == nil {
-		return nil, errors.New("没有传递数据库配置")
+		return nil, fserr.New("没有传递数据库配置")
 	}
 
 	gormDB, err := newPostgresGormDB(dbConfig)
@@ -40,5 +40,12 @@ func destroyGormDB(gormDB *gorm.DB) error {
 		return err
 	}
 
-	return db.Close()
+	err = db.Close()
+	if err != nil {
+		return err
+	}
+
+	db = nil
+
+	return nil
 }

+ 9 - 1
infrastructure/database/operations/operations.go

@@ -68,7 +68,14 @@ func DestroyOperation(op *Operations) error {
 
 	op.stopBeatHeart()
 
-	return destroyGormDB(op.db)
+	err := destroyGormDB(op.db)
+	if err != nil {
+		return err
+	}
+
+	op = nil
+
+	return nil
 }
 
 func (op *Operations) startBeatHeart(sqlDB *dbSql.DB) {
@@ -92,6 +99,7 @@ func (op *Operations) startBeatHeart(sqlDB *dbSql.DB) {
 
 func (op *Operations) stopBeatHeart() {
 	if op.stopPingChan != nil {
+		op.stopPingChan <- nil
 		close(op.stopPingChan)
 		op.stopPingChan = nil
 	}

+ 3 - 3
infrastructure/database/sql/result.go

@@ -1,10 +1,10 @@
 package sql
 
 import (
-	"errors"
 	"fmt"
 	"git.sxidc.com/go-framework/baize/tag/sql/sql_result"
 	"git.sxidc.com/go-tools/utils/reflectutils"
+	"git.sxidc.com/service-supports/fserr"
 	"reflect"
 	"strings"
 	"time"
@@ -29,13 +29,13 @@ func ParseSqlResult(input any, e any) error {
 	if !ok {
 		tableRow, ok := input.(Result)
 		if !ok {
-			return errors.New("输入数据应该为sdk.SqlResult或[]sdk.SqlResult")
+			return fserr.New("输入数据应该为sdk.SqlResult或[]sdk.SqlResult")
 		}
 
 		results = []Result{tableRow}
 	}
 
-	typeCheckErr := errors.New("可以接受的输出类型为结构指针或者结构slice的指针")
+	typeCheckErr := fserr.New("可以接受的输出类型为结构指针或者结构slice的指针")
 	outputValue := reflect.ValueOf(e)
 
 	if outputValue.Kind() != reflect.Pointer {