fix: fix version of sqlchemy to v1.0.0 for release/3.6

This commit is contained in:
Qiu Jian
2021-11-17 14:55:06 +08:00
parent c1f309d151
commit acef78070d
36 changed files with 1164 additions and 494 deletions

View File

@@ -225,7 +225,8 @@ dep:
@$(MAKE) mod
mod:
go get -d $(patsubst %,%@master,$(shell GO111MODULE=on go mod edit -print | sed -n -e 's|.*\(yunion.io/x/[a-z].*\) v.*|\1|p'))
go get -d $(patsubst %,%@master,$(shell GO111MODULE=on go mod edit -print | sed -n -e 's|.*\(yunion.io/x/[a-z].*\) v.*|\1|p' | grep -v sqlchemy))
go get -d yunion.io/x/sqlchemy@v1.0.0
go mod tidy
go mod vendor -v

8
go.mod
View File

@@ -140,13 +140,13 @@ require (
k8s.io/apimachinery v0.19.3
k8s.io/client-go v0.19.3
k8s.io/cluster-bootstrap v0.19.3
yunion.io/x/executor v0.0.0-20210310041834-3fcd1574f68e
yunion.io/x/jsonutils v0.0.0-20201110084044-3e4e1cb49769
yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656
yunion.io/x/jsonutils v0.0.0-20211105163012-d846c05a3c9a
yunion.io/x/log v0.0.0-20201210064738-43181789dc74
yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7
yunion.io/x/pkg v0.0.0-20210218105412-13a69f60034c
yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e
yunion.io/x/sqlchemy v0.0.0-20210329171939-2c520f93aee3
yunion.io/x/sqlchemy v1.0.0
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce
)

48
go.sum
View File

@@ -2,14 +2,12 @@ bazil.org/fuse v0.0.0-20180421153158-65cc252bf669 h1:FNCRpXiquG1aoyqcIWVFmpTSKVc
bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0 h1:0E3eE8MX426vUOs7aHfI7aN1BrIzzzf4ccKCSfSjGmc=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM=
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
@@ -32,16 +30,12 @@ github.com/Azure/azure-sdk-for-go v36.1.0+incompatible h1:smHlbChr/JDmsyUqELZXLs
github.com/Azure/azure-sdk-for-go v36.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest v0.9.3 h1:OZEIaBbMdUE/Js+BQKlpO81XlISgipr6yDJ+PSwsgi4=
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
github.com/Azure/go-autorest/autorest v0.9.6 h1:5YWtOnckcudzIw8lPPBcWOnmIFWMtHci1ZWAZulMSx0=
github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
github.com/Azure/go-autorest/autorest/adal v0.8.1 h1:pZdL8o72rK+avFWl+p9nE8RWi1JInZrWJYlnpfXJwHk=
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0=
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
@@ -49,12 +43,10 @@ github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwp
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM=
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U=
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw=
github.com/Azure/go-autorest/autorest/date v0.1.0 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=
github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0 h1:Ww5g4zThfD/6cLb4z6xxgeyDa7QDkizMkJKe0ysZXp0=
github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc=
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
@@ -87,9 +79,7 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/a8m/mark v0.1.1-0.20170507133748-44f2db618845/go.mod h1:c8Mh99Cw82nrsAnPgxQSZHkswVOJF7/MqZb1ZdvriLM=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.684 h1:MHqPW0la4Op96JGMkpB7Kxrz0Se5nowF6rLhHTZBUn4=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.684/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
@@ -216,7 +206,6 @@ github.com/fernet/fernet-go v0.0.0-20180830025343-9eac43b88a5e h1:P10tZmVD2XclAa
github.com/fernet/fernet-go v0.0.0-20180830025343-9eac43b88a5e/go.mod h1:2H9hjfbpSMHwY503FclkV/lZTBh2YlOmLLSda12uL8c=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
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=
@@ -282,7 +271,6 @@ github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
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/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
@@ -301,13 +289,11 @@ github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -366,7 +352,6 @@ github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
@@ -375,7 +360,6 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -397,7 +381,6 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGi
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
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=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -508,7 +491,6 @@ github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -576,7 +558,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
@@ -644,7 +625,6 @@ golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -696,10 +676,8 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
@@ -744,20 +722,17 @@ golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 h1:JA8d3MPx/IToSyXZG/RhwYEtfrKO1Fxrqe8KrkiLXKM=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8=
golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
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/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -786,7 +761,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4 h1:Toz2IK7k8rbltAXwNAxKcn9OzqyNfMUhUNjz3sL0NMk=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200417140056-c07e33ef3290/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 h1:vmsb6v0zUdmUlXfwKaYrHPPRCV0lHq/IwNIf0ASGjyQ=
@@ -824,7 +798,6 @@ google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBr
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb h1:ADPHZzpzM4tk4V4S5cnCrr5SwzvlrPRmqqCuJDB8UTs=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
@@ -833,7 +806,6 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
@@ -847,12 +819,10 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -886,7 +856,6 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
@@ -908,15 +877,14 @@ k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA=
sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
yunion.io/x/executor v0.0.0-20210310041834-3fcd1574f68e h1:uGmKmmHm4zeLXhc/MEbAFtEDtGtyEYhC0OaBRGFi+fQ=
yunion.io/x/executor v0.0.0-20210310041834-3fcd1574f68e/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656 h1:0zlZD5uhZoIHgLVAWCz2aHaYk2ZrNsACCYD7R6EIBII=
yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
yunion.io/x/jsonutils v0.0.0-20201110084044-3e4e1cb49769 h1:LIQ4hhLGQuQK+XxlV+8JrKBuL37WUT+5ZTVxBwHOTD4=
yunion.io/x/jsonutils v0.0.0-20201110084044-3e4e1cb49769/go.mod h1:p0nyMqGA/apTxxyLIU/o1k4V7Vujl2O6ey30L594sYE=
yunion.io/x/jsonutils v0.0.0-20211105163012-d846c05a3c9a h1:X/ucfLNcYsCfc4GFEX7R7GNWiDPr3vopLdnE4PuU46U=
yunion.io/x/jsonutils v0.0.0-20211105163012-d846c05a3c9a/go.mod h1:p0nyMqGA/apTxxyLIU/o1k4V7Vujl2O6ey30L594sYE=
yunion.io/x/log v0.0.0-20190514041436-04ce53b17c6b/go.mod h1:+gauLs73omeJAPlsXcevLsJLKixV+sR/E7WSYTSx1fE=
yunion.io/x/log v0.0.0-20190629062853-9f6483a7103d/go.mod h1:LC6f/4FozL0iaAbnFt2eDX9jlsyo3WiOUPm03d7+U4U=
yunion.io/x/log v0.0.0-20201210064738-43181789dc74 h1:7D+sQ/XaUTUEm+NCrKXOhXBKlzEd0RyS2qZ4vBGjx2o=
@@ -926,11 +894,11 @@ yunion.io/x/ovsdb v0.0.0-20200526071744-27bf0940cbc7/go.mod h1:0vLkNEhlmA64HViPB
yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v0.0.0-20200814072949-4f1b541857d6/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v0.0.0-20210218105412-13a69f60034c h1:J/joqbA1N2mAlOl0Uqd4LpAq3+DK5aoFMdz+p9Ld7pQ=
yunion.io/x/pkg v0.0.0-20210218105412-13a69f60034c/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97 h1:lY+5NlWwO2aIkfNnVOGKHmZvMt6m4ZuGtarIjwNfUsg=
yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e h1:v+EzIadodSwkdZ/7bremd7J8J50Cise/HCylsOJngmo=
yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo=
yunion.io/x/sqlchemy v0.0.0-20210329171939-2c520f93aee3 h1:C4yasW3gXronDIlIVUqHSbkA38PM1X9gxUWTYGsuIuI=
yunion.io/x/sqlchemy v0.0.0-20210329171939-2c520f93aee3/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI=
yunion.io/x/sqlchemy v1.0.0 h1:fRtWxe1xxMR+NDVKYNuI89m2HGSl6aad2DZ+Bn/mZ4Q=
yunion.io/x/sqlchemy v1.0.0/go.mod h1:FTdwPdGhMgh4E+UFXc9klI1Ok34fMuybTT+jLhOaIjI=
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce h1:kU8xE7O5uZ1GSJVMZHoJ+jrNL7csUQHYGyAPW9QfNpE=
yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce/go.mod h1:EP6NSv2C0zzqBDTKumv8hPWLb3XvgMZDHQRfyuOrQng=

8
vendor/modules.txt vendored
View File

@@ -1102,11 +1102,11 @@ k8s.io/utils/integer
sigs.k8s.io/structured-merge-diff/v4/value
# sigs.k8s.io/yaml v1.2.0
sigs.k8s.io/yaml
# yunion.io/x/executor v0.0.0-20210310041834-3fcd1574f68e
# yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656
yunion.io/x/executor/apis
yunion.io/x/executor/client
yunion.io/x/executor/server
# yunion.io/x/jsonutils v0.0.0-20201110084044-3e4e1cb49769
# yunion.io/x/jsonutils v0.0.0-20211105163012-d846c05a3c9a
yunion.io/x/jsonutils
# yunion.io/x/log v0.0.0-20201210064738-43181789dc74
yunion.io/x/log
@@ -1115,7 +1115,7 @@ yunion.io/x/log/hooks
yunion.io/x/ovsdb/cli_util
yunion.io/x/ovsdb/schema/ovn_nb
yunion.io/x/ovsdb/types
# yunion.io/x/pkg v0.0.0-20210218105412-13a69f60034c
# yunion.io/x/pkg v0.0.0-20211116020154-6a76ba2f7e97
yunion.io/x/pkg/errors
yunion.io/x/pkg/gotypes
yunion.io/x/pkg/prettytable
@@ -1149,7 +1149,7 @@ yunion.io/x/pkg/util/workqueue
yunion.io/x/pkg/utils
# yunion.io/x/s3cli v0.0.0-20190917004522-13ac36d8687e
yunion.io/x/s3cli
# yunion.io/x/sqlchemy v0.0.0-20210329171939-2c520f93aee3
# yunion.io/x/sqlchemy v1.0.0
yunion.io/x/sqlchemy
# yunion.io/x/structarg v0.0.0-20200720093445-9f850fa222ce
yunion.io/x/structarg

View File

@@ -239,7 +239,7 @@ func parseString(str []byte, offset int) (string, bool, int, error) {
ret2:
for i < len(str) {
switch str[i] {
case ' ', ':', ',', '\t', '\n', '}', ']':
case ' ', ':', ',', '\t', '\r', '\n', '}', ']':
break ret2
default:
i++

View File

@@ -33,13 +33,23 @@ import (
"yunion.io/x/pkg/util/timeutils"
)
func marshalSlice(val reflect.Value, info *reflectutils.SStructFieldInfo) JSONObject {
if val.Len() == 0 && info != nil && info.OmitEmpty {
func marshalSlice(val reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
if val.Kind() == reflect.Slice && val.IsNil() {
if !omitEmpty {
return JSONNull
} else {
return nil
}
objs := make([]JSONObject, val.Len())
}
if val.Len() == 0 && info != nil && info.OmitEmpty && omitEmpty {
return nil
}
objs := make([]JSONObject, 0)
for i := 0; i < val.Len(); i += 1 {
objs[i] = marshalValue(val.Index(i), nil)
val := marshalValue(val.Index(i), nil, omitEmpty)
if val != nil {
objs = append(objs, val)
}
}
arr := NewArray(objs...)
if info != nil && info.ForceString {
@@ -49,16 +59,23 @@ func marshalSlice(val reflect.Value, info *reflectutils.SStructFieldInfo) JSONOb
}
}
func marshalMap(val reflect.Value, info *reflectutils.SStructFieldInfo) JSONObject {
keys := val.MapKeys()
if len(keys) == 0 && info != nil && info.OmitEmpty {
func marshalMap(val reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
if val.IsNil() {
if !omitEmpty {
return JSONNull
} else {
return nil
}
}
keys := val.MapKeys()
if len(keys) == 0 && info != nil && info.OmitEmpty && omitEmpty {
return nil
}
objPairs := make([]JSONPair, 0)
for i := 0; i < len(keys); i += 1 {
key := keys[i]
val := marshalValue(val.MapIndex(key), nil)
if val != JSONNull {
val := marshalValue(val.MapIndex(key), nil, omitEmpty)
if val != nil {
objPairs = append(objPairs, JSONPair{key: fmt.Sprintf("%s", key), val: val})
}
}
@@ -70,10 +87,10 @@ func marshalMap(val reflect.Value, info *reflectutils.SStructFieldInfo) JSONObje
}
}
func marshalStruct(val reflect.Value, info *reflectutils.SStructFieldInfo) JSONObject {
objPairs := struct2JSONPairs(val)
if len(objPairs) == 0 && info != nil && info.OmitEmpty {
return JSONNull
func marshalStruct(val reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
objPairs := struct2JSONPairs(val, omitEmpty)
if len(objPairs) == 0 && info != nil && info.OmitEmpty && omitEmpty {
return nil
}
dict := NewDict(objPairs...)
if info != nil && info.ForceString {
@@ -92,7 +109,7 @@ func findValueByKey(pairs []JSONPair, key string) JSONObject {
return nil
}
func struct2JSONPairs(val reflect.Value) []JSONPair {
func struct2JSONPairs(val reflect.Value, omitEmpty bool) []JSONPair {
fields := reflectutils.FetchStructFieldValueSet(val)
objPairs := make([]JSONPair, 0, len(fields))
depFields := make(map[string]string)
@@ -106,8 +123,8 @@ func struct2JSONPairs(val reflect.Value) []JSONPair {
depFields[key] = deprecatedBy
continue
}
val := marshalValue(fields[i].Value, jsonInfo)
if val != nil && val != JSONNull {
val := marshalValue(fields[i].Value, jsonInfo, omitEmpty)
if val != nil {
objPair := JSONPair{key: key, val: val}
objPairs = append(objPairs, objPair)
}
@@ -140,9 +157,9 @@ func struct2JSONPairs(val reflect.Value) []JSONPair {
return objPairs
}
func marshalInt64(val int64, info *reflectutils.SStructFieldInfo) JSONObject {
if val == 0 && info != nil && info.OmitZero {
return JSONNull
func marshalInt64(val int64, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
if val == 0 && info != nil && info.OmitZero && omitEmpty {
return nil
} else if info != nil && info.ForceString {
return NewString(fmt.Sprintf("%d", val))
} else {
@@ -150,9 +167,9 @@ func marshalInt64(val int64, info *reflectutils.SStructFieldInfo) JSONObject {
}
}
func marshalFloat64(val float64, info *reflectutils.SStructFieldInfo, bit int) JSONObject {
if val == 0.0 && info != nil && info.OmitZero {
return JSONNull
func marshalFloat64(val float64, info *reflectutils.SStructFieldInfo, bit int, omitEmpty bool) JSONObject {
if val == 0.0 && info != nil && info.OmitZero && omitEmpty {
return nil
} else if info != nil && info.ForceString {
return NewString(fmt.Sprintf("%f", val))
} else {
@@ -160,9 +177,9 @@ func marshalFloat64(val float64, info *reflectutils.SStructFieldInfo, bit int) J
}
}
func marshalFloat32(val float32, info *reflectutils.SStructFieldInfo, bit int) JSONObject {
if val == 0.0 && info != nil && info.OmitZero {
return JSONNull
func marshalFloat32(val float32, info *reflectutils.SStructFieldInfo, bit int, omitEmpty bool) JSONObject {
if val == 0.0 && info != nil && info.OmitZero && omitEmpty {
return nil
} else if info != nil && info.ForceString {
return NewString(fmt.Sprintf("%f", val))
} else {
@@ -170,9 +187,9 @@ func marshalFloat32(val float32, info *reflectutils.SStructFieldInfo, bit int) J
}
}
func marshalBoolean(val bool, info *reflectutils.SStructFieldInfo) JSONObject {
if !val && info != nil && info.OmitFalse {
return JSONNull
func marshalBoolean(val bool, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
if !val && info != nil && info.OmitFalse && omitEmpty {
return nil
} else if info != nil && info.ForceString {
return NewString(fmt.Sprintf("%v", val))
} else {
@@ -184,28 +201,32 @@ func marshalBoolean(val bool, info *reflectutils.SStructFieldInfo) JSONObject {
}
}
func marshalTristate(val tristate.TriState, info *reflectutils.SStructFieldInfo) JSONObject {
func marshalTristate(val tristate.TriState, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
if val.IsTrue() {
return JSONTrue
} else if val.IsFalse() {
return JSONFalse
} else {
if omitEmpty {
return nil
} else {
return JSONNull
}
}
}
func marshalString(val string, info *reflectutils.SStructFieldInfo) JSONObject {
if len(val) == 0 && info != nil && info.OmitEmpty {
return JSONNull
func marshalString(val string, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
if len(val) == 0 && info != nil && info.OmitEmpty && omitEmpty {
return nil
} else {
return NewString(val)
}
}
func marshalTime(val time.Time, info *reflectutils.SStructFieldInfo) JSONObject {
func marshalTime(val time.Time, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
if val.IsZero() {
if info != nil && info.OmitEmpty {
return JSONNull
if info != nil && info.OmitEmpty && omitEmpty {
return nil
}
return NewString("")
} else {
@@ -222,123 +243,151 @@ func Marshal(obj interface{}) JSONObject {
return JSONNull
}
objValue := reflect.Indirect(val)
return marshalValue(objValue, nil)
mval := marshalValue(objValue, nil, true)
if mval == nil {
return JSONNull
}
return mval
}
func marshalValue(objValue reflect.Value, info *reflectutils.SStructFieldInfo) JSONObject {
func marshalValue(objValue reflect.Value, info *reflectutils.SStructFieldInfo, omitEmpty bool) JSONObject {
switch objValue.Type() {
case JSONDictPtrType, JSONArrayPtrType, JSONBoolPtrType, JSONIntPtrType, JSONFloatPtrType, JSONStringPtrType, JSONObjectType:
if objValue.IsNil() {
if omitEmpty {
return nil
} else {
return JSONNull
}
}
return objValue.Interface().(JSONObject)
case JSONDictType:
json, ok := objValue.Interface().(JSONDict)
if ok {
if len(json.data) == 0 && info != nil && info.OmitEmpty {
return JSONNull
if len(json.data) == 0 && info != nil && info.OmitEmpty && omitEmpty {
return nil
} else {
return &json
}
} else {
return JSONNull
return nil
}
case JSONArrayType:
json, ok := objValue.Interface().(JSONArray)
if ok {
if len(json.data) == 0 && info != nil && info.OmitEmpty {
return JSONNull
if len(json.data) == 0 && info != nil && info.OmitEmpty && omitEmpty {
return nil
} else {
return &json
}
} else {
return JSONNull
return nil
}
case JSONBoolType:
json, ok := objValue.Interface().(JSONBool)
if ok {
if !json.data && info != nil && info.OmitEmpty {
return JSONNull
if !json.data && info != nil && info.OmitEmpty && omitEmpty {
return nil
} else {
return &json
}
} else {
return JSONNull
return nil
}
case JSONIntType:
json, ok := objValue.Interface().(JSONInt)
if ok {
if json.data == 0 && info != nil && info.OmitEmpty {
return JSONNull
if json.data == 0 && info != nil && info.OmitEmpty && omitEmpty {
return nil
} else {
return &json
}
} else {
return JSONNull
return nil
}
case JSONFloatType:
json, ok := objValue.Interface().(JSONFloat)
if ok {
if json.data == 0.0 && info != nil && info.OmitEmpty {
return JSONNull
if json.data == 0.0 && info != nil && info.OmitEmpty && omitEmpty {
return nil
} else {
return &json
}
} else {
return JSONNull
return nil
}
case JSONStringType:
json, ok := objValue.Interface().(JSONString)
if ok {
if len(json.data) == 0 && info != nil && info.OmitEmpty {
return JSONNull
if len(json.data) == 0 && info != nil && info.OmitEmpty && omitEmpty {
return nil
} else {
return &json
}
} else {
return JSONNull
return nil
}
case tristate.TriStateType:
tri, ok := objValue.Interface().(tristate.TriState)
if ok {
return marshalTristate(tri, info)
return marshalTristate(tri, info, omitEmpty)
} else {
return JSONNull
return nil
}
}
switch objValue.Kind() {
case reflect.Slice, reflect.Array:
return marshalSlice(objValue, info)
return marshalSlice(objValue, info, omitEmpty)
case reflect.Struct:
if objValue.Type() == gotypes.TimeType {
return marshalTime(objValue.Interface().(time.Time), info)
return marshalTime(objValue.Interface().(time.Time), info, omitEmpty)
} else {
return marshalStruct(objValue, info)
return marshalStruct(objValue, info, omitEmpty)
}
case reflect.Map:
return marshalMap(objValue, info)
return marshalMap(objValue, info, omitEmpty)
case reflect.String:
strValue := objValue.Convert(gotypes.StringType)
return marshalString(strValue.Interface().(string), info)
return marshalString(strValue.Interface().(string), info, omitEmpty)
case reflect.Bool:
return marshalBoolean(objValue.Interface().(bool), info)
return marshalBoolean(objValue.Interface().(bool), info, omitEmpty)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
intValue := objValue.Convert(gotypes.Int64Type)
return marshalInt64(intValue.Interface().(int64), info)
return marshalInt64(intValue.Interface().(int64), info, omitEmpty)
case reflect.Float32:
floatVal := objValue.Convert(gotypes.Float32Type)
return marshalFloat32(floatVal.Interface().(float32), info, 32)
return marshalFloat32(floatVal.Interface().(float32), info, 32, omitEmpty)
case reflect.Float64:
floatVal := objValue.Convert(gotypes.Float64Type)
return marshalFloat64(floatVal.Interface().(float64), info, 64)
return marshalFloat64(floatVal.Interface().(float64), info, 64, omitEmpty)
case reflect.Interface, reflect.Ptr:
if objValue.IsNil() {
if omitEmpty {
return nil
} else {
return JSONNull
}
return marshalValue(objValue.Elem(), info)
}
return marshalValue(objValue.Elem(), info, omitEmpty)
default:
log.Errorf("unsupport object %s %s", objValue.Type(), objValue.Interface())
return JSONNull
}
}
func MarshalAll(obj interface{}) JSONObject {
if obj == nil {
return JSONNull
}
val := reflect.ValueOf(obj)
if kind := val.Kind(); val.IsZero() && kind == reflect.Ptr {
return JSONNull
}
objValue := reflect.Indirect(val)
mval := marshalValue(objValue, nil, false)
if mval == nil {
return JSONNull
}
return mval
}

View File

@@ -5,10 +5,16 @@ const (
ErrClient = Error("ClientError")
ErrUnclassified = Error("UnclassifiedError")
// network error
ErrDNS = Error("DNSError")
ErrEOF = Error("EOFError")
ErrNetwork = Error("NetworkError")
ErrConnectRefused = Error("ConnectRefusedError")
ErrTimeout = Error("TimeoutError")
ErrNotFound = Error("NotFoundError")
ErrDuplicateId = Error("DuplicateIdError")
ErrInvalidStatus = Error("InvalidStatusError")
ErrTimeout = Error("TimeoutError")
ErrNotImplemented = Error("NotImplementedError")
ErrNotSupported = Error("NotSupportedError")

View File

@@ -69,12 +69,19 @@ func valueSet2Array(dbSet interface{}, field string) ([]valueElement, error) {
return ret, nil
}
func CompareSets(dbSet interface{}, extSet interface{}, removed interface{}, commonDB interface{}, commonExt interface{}, added interface{}) error {
dbSetArray, err := valueSet2Array(dbSet, "GetExternalId")
type SCompareSet struct {
DBFunc string
DBSet interface{}
ExtFunc string
ExtSet interface{}
}
func CompareSetsFunc(cs SCompareSet, removed interface{}, commonDB interface{}, commonExt interface{}, added interface{}) error {
dbSetArray, err := valueSet2Array(cs.DBSet, cs.DBFunc)
if err != nil {
return err
}
extSetArray, err := valueSet2Array(extSet, "GetGlobalId")
extSetArray, err := valueSet2Array(cs.ExtSet, cs.ExtFunc)
if err != nil {
return err
}
@@ -135,4 +142,14 @@ func CompareSets(dbSet interface{}, extSet interface{}, removed interface{}, com
}
}
return nil
}
func CompareSets(dbSet interface{}, extSet interface{}, removed interface{}, commonDB interface{}, commonExt interface{}, added interface{}) error {
return CompareSetsFunc(SCompareSet{
DBFunc: "GetExternalId",
DBSet: dbSet,
ExtFunc: "GetGlobalId",
ExtSet: extSet,
}, removed, commonDB, commonExt, added)
}

View File

@@ -38,6 +38,9 @@ var DATE_COMPACT_REG *regexp.Regexp
var ISO_TIME_REG *regexp.Regexp
var ISO_NO_SECOND_TIME_REG *regexp.Regexp
var FULLISO_TIME_REG *regexp.Regexp
var ISO_TIME_REG2 *regexp.Regexp
var ISO_NO_SECOND_TIME_REG2 *regexp.Regexp
var FULLISO_TIME_REG2 *regexp.Regexp
var ZSTACK_TIME_REG *regexp.Regexp
var COMPACT_TIME_REG *regexp.Regexp
var MYSQL_TIME_REG *regexp.Regexp
@@ -68,6 +71,9 @@ func init() {
ISO_TIME_REG = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$`)
ISO_NO_SECOND_TIME_REG = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$`)
FULLISO_TIME_REG = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3,9}(Z|[+-]\d{2}:\d{2})$`)
ISO_TIME_REG2 = regexp.MustCompile(`^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$`)
ISO_NO_SECOND_TIME_REG2 = regexp.MustCompile(`^\d{4}-\d{2}-\d{2} \d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$`)
FULLISO_TIME_REG2 = regexp.MustCompile(`^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3,9}(Z|[+-]\d{2}:\d{2})$`)
COMPACT_TIME_REG = regexp.MustCompile(`^\d{14}$`)
ZSTACK_TIME_REG = regexp.MustCompile(`^\w+ \d{1,2}, \d{4} \d{1,2}:\d{1,2}:\d{1,2} (AM|PM)$`) //ZStack time format "Apr 1, 2019 3:23:17 PM"
MYSQL_TIME_REG = regexp.MustCompile(`^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$`)
@@ -202,6 +208,18 @@ func MatchFullISOTime(str string) bool {
return FULLISO_TIME_REG.MatchString(str)
}
func MatchISOTime2(str string) bool {
return ISO_TIME_REG2.MatchString(str)
}
func MatchISONoSecondTime2(str string) bool {
return ISO_NO_SECOND_TIME_REG2.MatchString(str)
}
func MatchFullISOTime2(str string) bool {
return FULLISO_TIME_REG2.MatchString(str)
}
func MatchCompactTime(str string) bool {
return COMPACT_TIME_REG.MatchString(str)
}

View File

@@ -58,6 +58,10 @@ const (
ShortMonthFormat = "200601"
ZStackTimeFormat = "Jan 2, 2006 15:04:05 PM"
IsoTimeFormat2 = "2006-01-02 15:04:05Z07:00"
IsoNoSecondTimeFormat2 = "2006-01-02 15:04Z07:00"
FullIsoNanoTimeFormat2 = "2006-01-02 15:04:05.000000000Z07:00"
RFC2882Format = time.RFC1123
)
@@ -113,10 +117,18 @@ func ParseIsoTime(str string) (time.Time, error) {
return time.Parse(IsoTimeFormat, str)
}
func ParseIsoTime2(str string) (time.Time, error) {
return time.Parse(IsoTimeFormat2, str)
}
func ParseIsoNoSecondTime(str string) (time.Time, error) {
return time.Parse(IsoNoSecondTimeFormat, str)
}
func ParseIsoNoSecondTime2(str string) (time.Time, error) {
return time.Parse(IsoNoSecondTimeFormat2, str)
}
func toFullIsoNanoTimeFormat(str string) string {
// 2019-09-17T20:50:17.66667134+08:00
// 2019-11-19T18:54:48.084-08:00
@@ -143,6 +155,10 @@ func ParseFullIsoTime(str string) (time.Time, error) {
return time.Parse(FullIsoNanoTimeFormat, toFullIsoNanoTimeFormat(str))
}
func ParseFullIsoTime2(str string) (time.Time, error) {
return time.Parse(FullIsoNanoTimeFormat2, toFullIsoNanoTimeFormat(str))
}
func ParseMysqlTime(str string) (time.Time, error) {
return time.Parse(MysqlTimeFormat, str)
}
@@ -183,6 +199,12 @@ func ParseTimeStr(str string) (time.Time, error) {
return ParseIsoTime(str)
} else if regutils.MatchISONoSecondTime(str) {
return ParseIsoNoSecondTime(str)
} else if regutils.MatchFullISOTime2(str) {
return ParseFullIsoTime2(str)
} else if regutils.MatchISOTime2(str) {
return ParseIsoTime2(str)
} else if regutils.MatchISONoSecondTime2(str) {
return ParseIsoNoSecondTime2(str)
} else if regutils.MatchMySQLTime(str) {
return ParseMysqlTime(str)
} else if regutils.MatchNormalTime(str) {

18
vendor/yunion.io/x/pkg/utils/tags.go generated vendored
View File

@@ -148,3 +148,21 @@ func TagPop(m map[string]string, key string) (map[string]string, string, bool) {
}
return m, val, ok
}
func SplitCSV(csv string) []string {
offset := 0
words := make([]string, 0)
str := []byte(csv)
for offset < len(str) {
var word string
word, offset = _findWord(str, offset, ",\r\n")
words = append(words, word)
if offset < len(str) {
offset++
if offset >= len(str) {
words = append(words, "")
}
}
}
return words
}

146
vendor/yunion.io/x/sqlchemy/README.md generated vendored
View File

@@ -1,6 +1,7 @@
# sqlchemy
[![CircleCI](https://circleci.com/gh/yunionio/sqlchemy.svg?style=svg)](https://circleci.com/gh/yunionio/sqlchemy)
[![codecov](https://codecov.io/gh/yunionio/sqlchemy/branch/master/graph/badge.svg?token=K8cSYZzLbc)](https://codecov.io/gh/yunionio/sqlchemy)
[![Go Report Card](https://goreportcard.com/badge/github.com/yunionio/sqlchemy)](https://goreportcard.com/report/github.com/yunionio/sqlchemy)
A lightweight golang ORM library inspired by python sqlalchemy.
@@ -20,7 +21,8 @@ Quick Examples
Table schema is defined by struct field tags
type TestTable struct {
```go
type TestTable struct {
Id string `primary:"true" width:"128" charset:"ascii" nullable:"false"`
Name string `width:"64" charset:"utf8" index:"true"`
Gender string `width:"10" charset:"ascii"`
@@ -33,121 +35,137 @@ Table schema is defined by struct field tags
DeletedAt time.Time ``
Deleted bool `nullable:"false" default:"false"`
Notes string `default:"default notes"`
}
}
````
## Table initialization
Create a table from a struct schema
tablespec := sqlchemy.NewTableSpecFromStruct(TestTable{}, "testtable")
```go
tablespec := sqlchemy.NewTableSpecFromStruct(TestTable{}, "testtable")
```
Check whether table schema definition is consistent with schema in database.
if !tablespec.CheckSync() {
```go
if !tablespec.CheckSync() {
log.Fatalf("table not in sync")
}
}
```
Synchronize database table schema and make it consistent with the struct defintion.
err := tablespec.Sync()
if err != nil {
```go
err := tablespec.Sync()
if err != nil {
log.Fataf("synchronize table schema failed: %s", er)
}
}
```
## Query
### Construct query
ti := tablespec.Instance()
```go
ti := tablespec.Instance()
// select * from testtable
q := ti.Query()
// select * from testtable
q := ti.Query()
// select * from testtable where id = '981b10ed-b6f9-4120-8a77-a3b03e343143'
// query by field name, in which the name is unique in the query
q := ti.Query().Equals("id", "981b10ed-b6f9-4120-8a77-a3b03e343143")
// select * from testtable where id = '981b10ed-b6f9-4120-8a77-a3b03e343143'
// query by field name, in which the name is unique in the query
q := ti.Query().Equals("id", "981b10ed-b6f9-4120-8a77-a3b03e343143")
// query by field instance, in which the field name might be ambiguous
q := ti.Query().Filter(sqlchemy.Equals(ti.Field("id"), "981b10ed-b6f9-4120-8a77-a3b03e343143"))
// query by field instance, in which the field name might be ambiguous
q := ti.Query().Filter(sqlchemy.Equals(ti.Field("id"), "981b10ed-b6f9-4120-8a77-a3b03e343143"))
// joint query
// joint query
// select * from t1 join t2 on t1.id=t2.testtable_id where t2.created_at > '2019-11-02'
q := ti.Query("name").Join(t2, sqlchemy.Equals(ti.Field("id"), t2.Field("testtable_id"))).Filter(sqlchermy.GT(t2.Field("created_at"), '2019-11-02')
// select * from t1 join t2 on t1.id=t2.testtable_id where t2.created_at > '2019-11-02'
q := ti.Query("name").Join(t2, sqlchemy.Equals(ti.Field("id"), t2.Field("testtable_id"))).Filter(sqlchermy.GT(t2.Field("created_at"), '2019-11-02')
// union query
// select id, name from testtable where id = '981b10ed-b6f9-4120-8a77-a3b03e343143' union select id, name from testtable where id='6fcc87ca-c1da-40ab-849a-305ff2663901'
q1 := t1.Query("id", "name").Equals("id", "981b10ed-b6f9-4120-8a77-a3b03e343143")
q2 := t1.Query("id", "name").Equals("id", "6fcc87ca-c1da-40ab-849a-305ff2663901")
qu := sqlchemy.Union(q1, q2)
// union query
// select id, name from testtable where id = '981b10ed-b6f9-4120-8a77-a3b03e343143' union select id, name from testtable where id='6fcc87ca-c1da-40ab-849a-305ff2663901'
q1 := t1.Query("id", "name").Equals("id", "981b10ed-b6f9-4120-8a77-a3b03e343143")
q2 := t1.Query("id", "name").Equals("id", "6fcc87ca-c1da-40ab-849a-305ff2663901")
qu := sqlchemy.Union(q1, q2)
```
### Fetch data
q := ti.Query().Equals("id", "e2bc9b659cec407590dc2f3fcb009acb")
```go
q := ti.Query().Equals("id", "e2bc9b659cec407590dc2f3fcb009acb")
// fetch single row into object
row := TestTable{}
err := q.First(&row)
if err != nil {
// fetch single row into object
row := TestTable{}
err := q.First(&row)
if err != nil {
log.Fatalf("fetch object error %s", err)
}
}
// fetch single row into a string map, where strMap is map[string]string
strMap, err := q.FirstStringMap()
if err != nil {
// fetch single row into a string map, where strMap is map[string]string
strMap, err := q.FirstStringMap()
if err != nil {
log.Fatalf("fetch object error %s", err)
}
}
q := ti.Query().Startswith("id", "abc")
// fetch rows
rows := make([]TestTable, 0)
err := q.All(&rows)
if err != nil {
q := ti.Query().Startswith("id", "abc")
// fetch rows
rows := make([]TestTable, 0)
err := q.All(&rows)
if err != nil {
log.Fatalf("query failure: %s", err)
}
}
// fetch rows into string maps, where maps is []map[string]string
maps, err := q.AllStringMap()
if err != nil {
// fetch rows into string maps, where maps is []map[string]string
maps, err := q.AllStringMap()
if err != nil {
log.Fatalf("query failure: %s", err)
}
}
```
### SubQuery
Query can be used as a subquery in other queries.
// derive a subquery from an ordinary query
subq := t1.Query("id").Equals("version", "v2.0").SubQuery()
// use subquery
q := t1.Query().In("id", subq)
```go
// derive a subquery from an ordinary query
subq := t1.Query("id").Equals("version", "v2.0").SubQuery()
// use subquery
q := t1.Query().In("id", subq)
```
## Insert
// hook to initialize data field before insert
func (t *TestTable) BeforeInsert() {
```go
// hook to initialize data field before insert
func (t *TestTable) BeforeInsert() {
t.Id = uuid4()
}
// initialize data struct
dt1 := TestTable{
}
// initialize data struct
dt1 := TestTable{
Name: "Test",
}
// insert the data, primary key fields must be populated
// the primary key has been populated by the BeforeInsert hook
err = tablespec.Insert(&dt1)
// insert or update
// insert the object if no primary key conflict, otherwise, update the record
err = tablespec.InsertOrUpdate(&dt1)
}
// insert the data, primary key fields must be populated
// the primary key has been populated by the BeforeInsert hook
err = tablespec.Insert(&dt1)
// insert or update
// insert the object if no primary key conflict, otherwise, update the record
err = tablespec.InsertOrUpdate(&dt1)
```
## Update
// update the field
_, err = tablespec.Update(&dt3, func() error {
```go
// update the field
_, err = tablespec.Update(&dt3, func() error {
dt3.Name = "New name 4"
dt3.Compond = &SCompondStruct{Id: "998822333", Age: 80}
return nil
})
})
```
Please refer to sqltest/main.go for more examples.

View File

@@ -23,11 +23,14 @@ type sCaseFieldBranch struct {
thenField IQueryField
}
// SCaseFunction represents function of case ... when ... branch
type SCaseFunction struct {
branches []sCaseFieldBranch
elseField IQueryField
}
// NewFunction creates a field with SQL function
// for example: SUM(count) as total
func NewFunction(ifunc IFunction, name string) IQueryField {
return &SFunctionFieldBase{
IFunction: ifunc,
@@ -35,11 +38,13 @@ func NewFunction(ifunc IFunction, name string) IQueryField {
}
}
// Else adds else clause for case when function
func (cf *SCaseFunction) Else(field IQueryField) *SCaseFunction {
cf.elseField = field
return cf
}
// When adds when clause for case when function
func (cf *SCaseFunction) When(when ICondition, then IQueryField) *SCaseFunction {
cf.branches = append(cf.branches, sCaseFieldBranch{
whenCondition: when,
@@ -48,6 +53,7 @@ func (cf *SCaseFunction) When(when ICondition, then IQueryField) *SCaseFunction
return cf
}
// NewCase creates a case... when...else... representation instance
func NewCase() *SCaseFunction {
return &SCaseFunction{}
}

174
vendor/yunion.io/x/sqlchemy/column.go generated vendored
View File

@@ -28,36 +28,82 @@ import (
"yunion.io/x/pkg/utils"
)
// IColumnSpec is an interface that represents a column of a table
type IColumnSpec interface {
// Name returns the name of the column
Name() string
// ColType returns type of the column, e.g. INTEGER, VARCHAR
ColType() string
// Default returns default value of the column, represents in string
Default() string
// IsSupportDefault returns whether this column supports being given a default value
IsSupportDefault() bool
// IsNullable returns whether this column is nullable
IsNullable() bool
// SetNullable sets this column as nullable
SetNullable(on bool)
// IsPrimary returns whether this column is part of the primary keys
IsPrimary() bool
// IsUnique returns whether the value of this column unique for each row
IsUnique() bool
// IsIndex returns whether this column is indexable, if it is true, a index of this column will be automatically created
IsIndex() bool
// ExtraDefs returns some extra column attribute definitions, not covered by the standard fields
ExtraDefs() string
// DefinitionString return the SQL presentation of this column
DefinitionString() string
// IsText returns whether this column is actually a text, such a Datetime column is actually a text
IsText() bool
// IsSearchable returns whether this column is searchable, e.g. a integer column is not searchable, but a text field is searchable
IsSearchable() bool
// IsAscii returns whether this column is an ASCII type text, if true, the column should be compared with a UTF8 string
IsAscii() bool
// IsNumeric returns whether this column is a numeric type column, e.g. integer or float
IsNumeric() bool
// ConvertFromString returns the SQL representation of a value in string format for this column
ConvertFromString(str string) string
// ConvertToString(str string) string
// ConvertFromValue returns the SQL representation of a value for this column
ConvertFromValue(val interface{}) interface{}
// ConvertToValue(str interface{}) interface{}
// IsZero is used to determine a value is the zero value for this column
IsZero(val interface{}) bool
// AllowZero returns whether this column allow a zero value
AllowZero() bool
// IsEqual(v1, v2 interface{}) bool
// Tags returns the field tags for this column, which is in the struct definition
Tags() map[string]string
// IsPointer returns whether this column is a pointer type definition, e.g. *int, *bool
IsPointer() bool
// SetDefault sets the default value in the format of string for this column
SetDefault(defStr string)
}
// SBaseColumn is the base structure represents a column
type SBaseColumn struct {
name string
dbName string
@@ -72,98 +118,118 @@ type SBaseColumn struct {
tags map[string]string
}
// IsPointer implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) IsPointer() bool {
return c.isPointer
}
// Name implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) Name() string {
if len(c.dbName) > 0 {
return c.dbName
} else {
return c.name
}
return c.name
}
// ColType implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) ColType() string {
return c.sqlType
}
// Default implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) Default() string {
return c.defaultString
}
// SetDefault implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) SetDefault(defStr string) {
c.defaultString = defStr
}
// IsSupportDefault implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) IsSupportDefault() bool {
return true
}
// IsNullable implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) IsNullable() bool {
return c.isNullable
}
// SetNullable implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) SetNullable(on bool) {
c.isNullable = on
}
// IsPrimary implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) IsPrimary() bool {
return c.isPrimary
}
// IsUnique implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) IsUnique() bool {
return c.isUnique
}
// IsIndex implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) IsIndex() bool {
return c.isIndex
}
// ExtraDefs implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) ExtraDefs() string {
return ""
}
// IsText implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) IsText() bool {
return false
}
// IsAscii implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) IsAscii() bool {
return false
}
// IsSearchable implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) IsSearchable() bool {
return false
}
// IsNumeric implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) IsNumeric() bool {
return false
}
// AllowZero implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) AllowZero() bool {
return c.isAllowZero
}
// ConvertFromString implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) ConvertFromString(str string) string {
return str
}
func (c *SBaseColumn) ConvertToString(str string) string {
/*func (c *SBaseColumn) ConvertToString(str string) string {
return str
}
}*/
// ConvertFromValue implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) ConvertFromValue(val interface{}) interface{} {
return val
}
func (c *SBaseColumn) ConvertToValue(val interface{}) interface{} {
/*func (c *SBaseColumn) ConvertToValue(val interface{}) interface{} {
return val
}
}*/
// Tags implementation of SBaseColumn for IColumnSpec
func (c *SBaseColumn) Tags() map[string]string {
return c.tags
}
// generate SQL representation of a column
func definitionBuffer(c IColumnSpec) bytes.Buffer {
var buf bytes.Buffer
buf.WriteByte('`')
@@ -204,6 +270,7 @@ func definitionBuffer(c IColumnSpec) bytes.Buffer {
return buf
}
// NewBaseColumn returns an instance of SBaseColumn
func NewBaseColumn(name string, sqltype string, tagmap map[string]string, isPointer bool) SBaseColumn {
var val string
var ok bool
@@ -260,19 +327,21 @@ func NewBaseColumn(name string, sqltype string, tagmap map[string]string, isPoin
}
}
// SBaseWidthColumn represents a type of column that with width attribute, such as VARCHAR(20), INT(10)
type SBaseWidthColumn struct {
SBaseColumn
width int
}
// ColType implementation of SBaseWidthColumn for IColumnSpec
func (c *SBaseWidthColumn) ColType() string {
if c.width > 0 {
return fmt.Sprintf("%s(%d)", c.sqlType, c.width)
} else {
return c.sqlType
}
return c.sqlType
}
// NewBaseWidthColumn return an instance of SBaseWidthColumn
func NewBaseWidthColumn(name string, sqltype string, tagmap map[string]string, isPointer bool) SBaseWidthColumn {
width := 0
tagmap, v, ok := utils.TagPop(tagmap, TAG_WIDTH)
@@ -286,15 +355,18 @@ func NewBaseWidthColumn(name string, sqltype string, tagmap map[string]string, i
return wc
}
// SBooleanColumn represents a boolean type column, which is a int(1) for mysql, with value of true or false
type SBooleanColumn struct {
SBaseWidthColumn
}
// DefinitionString implementation of SBooleanColumn for IColumnSpec
func (c *SBooleanColumn) DefinitionString() string {
buf := definitionBuffer(c)
return buf.String()
}
// ConvertFromString implementation of SBooleanColumn for IColumnSpec
func (c *SBooleanColumn) ConvertFromString(str string) string {
switch strings.ToLower(str) {
case "true", "yes", "on", "ok", "1":
@@ -304,7 +376,7 @@ func (c *SBooleanColumn) ConvertFromString(str string) string {
}
}
func (c *SBooleanColumn) ConvertFromValue(val interface{}) interface{} {
/*func (c *SBooleanColumn) ConvertFromValue(val interface{}) interface{} {
switch bVal := val.(type) {
case bool:
if bVal {
@@ -323,18 +395,19 @@ func (c *SBooleanColumn) ConvertFromValue(val interface{}) interface{} {
default:
return 0
}
}
}*/
// IsZero implementation of SBooleanColumn for IColumnSpec
func (c *SBooleanColumn) IsZero(val interface{}) bool {
if c.isPointer {
bVal := val.(*bool)
return bVal == nil
} else {
}
bVal := val.(bool)
return bVal == false
}
}
// NewBooleanColumn return an instance of SBooleanColumn
func NewBooleanColumn(name string, tagmap map[string]string, isPointer bool) SBooleanColumn {
bc := SBooleanColumn{SBaseWidthColumn: NewBaseWidthColumn(name, "TINYINT", tagmap, isPointer)}
if !bc.IsPointer() && len(bc.Default()) > 0 && bc.ConvertFromString(bc.Default()) == "1" {
@@ -344,15 +417,18 @@ func NewBooleanColumn(name string, tagmap map[string]string, isPointer bool) SBo
return bc
}
// STristateColumn represents a tristate type column, with value of true, false or none
type STristateColumn struct {
SBaseWidthColumn
}
// DefinitionString implementation of STristateColumn for IColumnSpec
func (c *STristateColumn) DefinitionString() string {
buf := definitionBuffer(c)
return buf.String()
}
// ConvertFromString implementation of STristateColumn for IColumnSpec
func (c *STristateColumn) ConvertFromString(str string) string {
switch strings.ToLower(str) {
case "true", "yes", "on", "ok", "1":
@@ -364,43 +440,54 @@ func (c *STristateColumn) ConvertFromString(str string) string {
}
}
// ConvertFromValue implementation of STristateColumn for IColumnSpec
func (c *STristateColumn) ConvertFromValue(val interface{}) interface{} {
bVal := val.(tristate.TriState)
if bVal == tristate.True {
return 1
} else {
return 0
}
return 0
}
// IsZero implementation of STristateColumn for IColumnSpec
func (c *STristateColumn) IsZero(val interface{}) bool {
if c.isPointer {
bVal := val.(*tristate.TriState)
return bVal == nil
} else {
}
bVal := val.(tristate.TriState)
return bVal == tristate.None
}
}
// NewTristateColumn return an instance of STristateColumn
func NewTristateColumn(name string, tagmap map[string]string, isPointer bool) STristateColumn {
bc := STristateColumn{SBaseWidthColumn: NewBaseWidthColumn(name, "TINYINT", tagmap, isPointer)}
return bc
}
// SIntegerColumn represents an integer type of column, with value of integer
type SIntegerColumn struct {
SBaseWidthColumn
// Is this column an autoincrement colmn
IsAutoIncrement bool
// Is this column is a version column for this records
IsAutoVersion bool
// Is this column a unsigned integer?
IsUnsigned bool
// If this column is an autoincrement column, AutoIncrementOffset records the initial offset
AutoIncrementOffset int64
}
// IsNumeric implementation of SIntegerColumn for IColumnSpec
func (c *SIntegerColumn) IsNumeric() bool {
return true
}
// ExtraDefs implementation of SIntegerColumn for IColumnSpec
func (c *SIntegerColumn) ExtraDefs() string {
if c.IsAutoIncrement {
return "AUTO_INCREMENT"
@@ -408,11 +495,13 @@ func (c *SIntegerColumn) ExtraDefs() string {
return ""
}
// DefinitionString implementation of SIntegerColumn for IColumnSpec
func (c *SIntegerColumn) DefinitionString() string {
buf := definitionBuffer(c)
return buf.String()
}
// IsZero implementation of SIntegerColumn for IColumnSpec
func (c *SIntegerColumn) IsZero(val interface{}) bool {
if val == nil || (c.isPointer && reflect.ValueOf(val).IsNil()) {
return true
@@ -424,6 +513,7 @@ func (c *SIntegerColumn) IsZero(val interface{}) bool {
return true
}
// ColType implementation of SIntegerColumn for IColumnSpec
func (c *SIntegerColumn) ColType() string {
str := (&c.SBaseWidthColumn).ColType()
if c.IsUnsigned {
@@ -432,6 +522,7 @@ func (c *SIntegerColumn) ColType() string {
return str
}
// NewIntegerColumn return an instance of SIntegerColumn
func NewIntegerColumn(name string, sqltype string, unsigned bool, tagmap map[string]string, isPointer bool) SIntegerColumn {
autoinc := false
autoincBase := int64(0)
@@ -471,19 +562,23 @@ func NewIntegerColumn(name string, sqltype string, unsigned bool, tagmap map[str
return c
}
// SFloatColumn represents a float type column, e.g. float32 or float64
type SFloatColumn struct {
SBaseColumn
}
// IsNumeric implementation of SFloatColumn for IColumnSpec
func (c *SFloatColumn) IsNumeric() bool {
return true
}
// DefinitionString implementation of SFloatColumn for IColumnSpec
func (c *SFloatColumn) DefinitionString() string {
buf := definitionBuffer(c)
return buf.String()
}
// IsZero implementation of SFloatColumn for IColumnSpec
func (c *SFloatColumn) IsZero(val interface{}) bool {
if c.isPointer {
switch val.(type) {
@@ -503,28 +598,34 @@ func (c *SFloatColumn) IsZero(val interface{}) bool {
return true
}
// NewFloatColumn returns an instance of SFloatColumn
func NewFloatColumn(name string, sqlType string, tagmap map[string]string, isPointer bool) SFloatColumn {
return SFloatColumn{SBaseColumn: NewBaseColumn(name, sqlType, tagmap, isPointer)}
}
// SDecimalColumn represents a DECIMAL type of column, i.e. a float with fixed width of digits
type SDecimalColumn struct {
SBaseWidthColumn
Precision int
}
// ColType implementation of SDecimalColumn for IColumnSpec
func (c *SDecimalColumn) ColType() string {
return fmt.Sprintf("%s(%d, %d)", c.sqlType, c.width, c.Precision)
}
// IsNumeric implementation of SDecimalColumn for IColumnSpec
func (c *SDecimalColumn) IsNumeric() bool {
return true
}
// DefinitionString implementation of SDecimalColumn for IColumnSpec
func (c *SDecimalColumn) DefinitionString() string {
buf := definitionBuffer(c)
return buf.String()
}
// IsZero implementation of SDecimalColumn for IColumnSpec
func (c *SDecimalColumn) IsZero(val interface{}) bool {
if c.isPointer {
switch val.(type) {
@@ -544,6 +645,7 @@ func (c *SDecimalColumn) IsZero(val interface{}) bool {
return true
}
// NewDecimalColumn returns an instance of SDecimalColumn
func NewDecimalColumn(name string, tagmap map[string]string, isPointer bool) SDecimalColumn {
tagmap, v, ok := utils.TagPop(tagmap, TAG_PRECISION)
if !ok {
@@ -559,21 +661,23 @@ func NewDecimalColumn(name string, tagmap map[string]string, isPointer bool) SDe
}
}
// STextColumn represents a text type of column
type STextColumn struct {
SBaseWidthColumn
Charset string
}
// IsSupportDefault implementation of STextColumn for IColumnSpec
func (c *STextColumn) IsSupportDefault() bool {
// https://stackoverflow.com/questions/3466872/why-cant-a-text-column-have-a-default-value-in-mysql
// MySQL does not support default for TEXT/BLOB
if c.sqlType == "VARCHAR" {
return true
} else {
return false
}
return false
}
// ColType implementation of STextColumn for IColumnSpec
func (c *STextColumn) ColType() string {
var charset string
var collate string
@@ -588,35 +692,39 @@ func (c *STextColumn) ColType() string {
return fmt.Sprintf("%s CHARACTER SET '%s' COLLATE '%s'", c.SBaseWidthColumn.ColType(), charset, collate)
}
// IsText implementation of STextColumn for IColumnSpec
func (c *STextColumn) IsText() bool {
return true
}
// IsSearchable implementation of STextColumn for IColumnSpec
func (c *STextColumn) IsSearchable() bool {
return true
}
// IsAscii implementation of STextColumn for IColumnSpec
func (c *STextColumn) IsAscii() bool {
if c.Charset == "ascii" {
return true
} else {
return false
}
return false
}
// DefinitionString implementation of STextColumn for IColumnSpec
func (c *STextColumn) DefinitionString() string {
buf := definitionBuffer(c)
return buf.String()
}
// IsZero implementation of STextColumn for IColumnSpec
func (c *STextColumn) IsZero(val interface{}) bool {
if c.isPointer {
return gotypes.IsNil(val)
} else {
return reflect.ValueOf(val).Len() == 0
}
return reflect.ValueOf(val).Len() == 0
}
// NewTextColumn return an instance of STextColumn
func NewTextColumn(name string, tagmap map[string]string, isPointer bool) STextColumn {
var width int
var sqltype string
@@ -666,29 +774,33 @@ func NewStringColumn(name string, sqltype string, tagmap map[string]string) SStr
return sc
}*/
// STimeTypeColumn represents a Detetime type of column, e.g. DateTime
type STimeTypeColumn struct {
SBaseColumn
}
// IsText implementation of STimeTypeColumn for IColumnSpec
func (c *STimeTypeColumn) IsText() bool {
return true
}
// DefinitionString implementation of STimeTypeColumn for IColumnSpec
func (c *STimeTypeColumn) DefinitionString() string {
buf := definitionBuffer(c)
return buf.String()
}
// IsZero implementation of STimeTypeColumn for IColumnSpec
func (c *STimeTypeColumn) IsZero(val interface{}) bool {
if c.isPointer {
bVal := val.(*time.Time)
return bVal == nil
} else {
}
bVal := val.(time.Time)
return bVal.IsZero()
}
}
// NewTimeTypeColumn return an instance of STimeTypeColumn
func NewTimeTypeColumn(name string, typeStr string, tagmap map[string]string, isPointer bool) STimeTypeColumn {
dc := STimeTypeColumn{
NewBaseColumn(name, typeStr, tagmap, isPointer),
@@ -696,12 +808,18 @@ func NewTimeTypeColumn(name string, typeStr string, tagmap map[string]string, is
return dc
}
// SDateTimeColumn represents a DateTime type of column
type SDateTimeColumn struct {
STimeTypeColumn
// Is this column a 'created_at' field, whichi records the time of create this record
IsCreatedAt bool
// Is this column a 'updated_at' field, whichi records the time when this record was updated
IsUpdatedAt bool
}
// NewDateTimeColumn returns an instance of DateTime column
func NewDateTimeColumn(name string, tagmap map[string]string, isPointer bool) SDateTimeColumn {
createdAt := false
updatedAt := false
@@ -720,15 +838,18 @@ func NewDateTimeColumn(name string, tagmap map[string]string, isPointer bool) SD
return dtc
}
// CompoundColumn represents a column of compound tye, e.g. a JSON, an Array, or a struct
type CompoundColumn struct {
STextColumn
}
// DefinitionString implementation of CompoundColumn for IColumnSpec
func (c *CompoundColumn) DefinitionString() string {
buf := definitionBuffer(c)
return buf.String()
}
// IsZero implementation of CompoundColumn for IColumnSpec
func (c *CompoundColumn) IsZero(val interface{}) bool {
if val == nil {
return true
@@ -739,15 +860,16 @@ func (c *CompoundColumn) IsZero(val interface{}) bool {
return false
}
// ConvertFromValue implementation of CompoundColumn for IColumnSpec
func (c *CompoundColumn) ConvertFromValue(val interface{}) interface{} {
bVal, ok := val.(gotypes.ISerializable)
if ok && bVal != nil {
return bVal.String()
} else {
return ""
}
return ""
}
// NewCompoundColumn returns an instance of CompoundColumn
func NewCompoundColumn(name string, tagmap map[string]string, isPointer bool) CompoundColumn {
dtc := CompoundColumn{NewTextColumn(name, tagmap, isPointer)}
return dtc

View File

@@ -21,11 +21,16 @@ import (
"yunion.io/x/pkg/util/reflectutils"
)
// ICondition is the interface representing a condition for SQL query
// e.g. WHERE a1 = b1 is a condition of equal
// the condition support nested condition, with AND, OR and NOT boolean operators
type ICondition interface {
WhereClause() string
Variables() []interface{}
}
// SCompoundConditions is a Compound condition represents AND or OR boolean operation
// Compound condition also follows the ICondition interface
type SCompoundConditions struct {
conditions []ICondition
}
@@ -45,10 +50,12 @@ func compoundWhereClause(c *SCompoundConditions, op string) string {
return buf.String()
}
// WhereClause implementation of SCompoundConditions for ICondition
func (c *SCompoundConditions) WhereClause() string {
return ""
}
// Variables implementation of SCompoundConditions for ICondition
func (c *SCompoundConditions) Variables() []interface{} {
vars := make([]interface{}, 0)
for _, cond := range c.conditions {
@@ -60,22 +67,27 @@ func (c *SCompoundConditions) Variables() []interface{} {
return vars
}
// SAndConditions represents the AND condition, which is a SCompoundConditions
type SAndConditions struct {
SCompoundConditions
}
// WhereClause implementation of SAndConditions for IConditionq
func (c *SAndConditions) WhereClause() string {
return compoundWhereClause(&c.SCompoundConditions, SQL_OP_AND)
}
// SOrConditions represents the OR condition, which is a SCompoundConditions
type SOrConditions struct {
SCompoundConditions
}
// WhereClause implementation of SOrConditions for ICondition
func (c *SOrConditions) WhereClause() string {
return compoundWhereClause(&c.SCompoundConditions, SQL_OP_OR)
}
// AND method that combines many conditions with AND operator
func AND(cond ...ICondition) ICondition {
conds := make([]ICondition, 0)
for _, c := range cond {
@@ -90,6 +102,7 @@ func AND(cond ...ICondition) ICondition {
return &cc
}
// OR method that combines many conditions with OR operator
func OR(cond ...ICondition) ICondition {
conds := make([]ICondition, 0)
for _, c := range cond {
@@ -104,152 +117,187 @@ func OR(cond ...ICondition) ICondition {
return &cc
}
// SNotCondition represents the NOT condition, which is a boolean operator
type SNotCondition struct {
condition ICondition
}
// WhereClause implementationq of SNotCondition for ICondition
func (c *SNotCondition) WhereClause() string {
return fmt.Sprintf("%s (%s)", SQL_OP_NOT, c.condition.WhereClause())
}
// Variables implementation of SNotCondition for ICondition
func (c *SNotCondition) Variables() []interface{} {
return c.condition.Variables()
}
// NOT method that makes negative operator on a condition
func NOT(cond ICondition) ICondition {
cc := SNotCondition{condition: cond}
return &cc
}
// SSingleCondition represents a kind of condition that composed of one query field
type SSingleCondition struct {
field IQueryField
}
// Variables implementation of SSingleCondition for ICondition
func (c *SSingleCondition) Variables() []interface{} {
return []interface{}{}
}
// NewSingleCondition returns an instance of SSingleCondition
func NewSingleCondition(field IQueryField) SSingleCondition {
return SSingleCondition{field: field}
}
// SIsNullCondition is a condition representing a comparison with null, e.g. a is null
type SIsNullCondition struct {
SSingleCondition
}
// WhereClause implementation for SIsNullCondition for ICondition
func (c *SIsNullCondition) WhereClause() string {
return fmt.Sprintf("%s IS NULL", c.field.Reference())
}
// IsNull methods that justifies a field is null
func IsNull(f IQueryField) ICondition {
c := SIsNullCondition{NewSingleCondition(f)}
return &c
}
// SIsNotNullCondition is a condition represents a comparison with not null, e.g. a is not null
type SIsNotNullCondition struct {
SSingleCondition
}
// WhereClause implementation of SIsNotNullCondition for ICondition
func (c *SIsNotNullCondition) WhereClause() string {
return fmt.Sprintf("%s IS NOT NULL", c.field.Reference())
}
// IsNotNull methods that justifies a field is not null
func IsNotNull(f IQueryField) ICondition {
c := SIsNotNullCondition{NewSingleCondition(f)}
return &c
}
// SIsEmptyCondition is a condition representing the empty status of a field
type SIsEmptyCondition struct {
SSingleCondition
}
// WhereClause implementation of SIsEmptyCondition for ICondition
func (c *SIsEmptyCondition) WhereClause() string {
return fmt.Sprintf("LENGTH(%s) = 0", c.field.Reference())
}
// IsEmpty method that justifies where a text field is empty, e.g. length is zero
func IsEmpty(f IQueryField) ICondition {
c := SIsEmptyCondition{NewSingleCondition(f)}
return &c
}
// SIsNullOrEmptyCondition is a condition that justifies a field is null or empty
type SIsNullOrEmptyCondition struct {
SSingleCondition
}
// WhereClause implementation of SIsNullOrEmptyCondition for ICondition
func (c *SIsNullOrEmptyCondition) WhereClause() string {
return fmt.Sprintf("%s IS NULL OR LENGTH(%s) = 0", c.field.Reference(), c.field.Reference())
}
// IsNullOrEmpty is the ethod justifies a field is null or empty, e.g. a is null or length(a) == 0
func IsNullOrEmpty(f IQueryField) ICondition {
c := SIsNullOrEmptyCondition{NewSingleCondition(f)}
return &c
}
// SIsNotEmptyCondition represents a condition that represents a field is not empty
type SIsNotEmptyCondition struct {
SSingleCondition
}
// WhereClause implementation of SIsNotEmptyCondition for ICondition
func (c *SIsNotEmptyCondition) WhereClause() string {
return fmt.Sprintf("%s IS NOT NULL AND LENGTH(%s) > 0", c.field.Reference(), c.field.Reference())
}
// IsNotEmpty method justifies a field is not empty
func IsNotEmpty(f IQueryField) ICondition {
c := SIsNotEmptyCondition{NewSingleCondition(f)}
return &c
}
// SIsTrueCondition represents a boolean field (TINYINT) is true, e.g. a == 1
type SIsTrueCondition struct {
SSingleCondition
}
// WhereClause implementation of SIsTrueCondition for ICondition
func (c *SIsTrueCondition) WhereClause() string {
return fmt.Sprintf("%s = 1", c.field.Reference())
}
// IsTrue method that justifies a field is true, e.g. field == 1
func IsTrue(f IQueryField) ICondition {
c := SIsTrueCondition{NewSingleCondition(f)}
return &c
}
// SIsFalseCondition represents a boolean is false
type SIsFalseCondition struct {
SSingleCondition
}
// WhereClause implementation of SIsFalseCondition for ICondition
func (c *SIsFalseCondition) WhereClause() string {
return fmt.Sprintf("%s = 0", c.field.Reference())
}
// IsFalse method justifies a boolean is false
func IsFalse(f IQueryField) ICondition {
c := SIsFalseCondition{NewSingleCondition(f)}
return &c
}
// SNoLaterThanCondition coompares a DATETIME field with current time and ensure the field is no later than now, e.g. a <= NOW()
type SNoLaterThanCondition struct {
SSingleCondition
}
// WhereClause implementation of SNoLaterThanCondition for ICondition
func (c *SNoLaterThanCondition) WhereClause() string {
return fmt.Sprintf("%s >= NOW()", c.field.Reference())
return fmt.Sprintf("%s <= NOW()", c.field.Reference())
}
// NoLaterThan method justifies a DATETIME field is before current time
func NoLaterThan(f IQueryField) ICondition {
c := SNoLaterThanCondition{NewSingleCondition(f)}
return &c
}
// SNoEarlierThanCondition compares a field with current time and ensure the field is no earlier than NOW, e.g. a >= NOW()
type SNoEarlierThanCondition struct {
SSingleCondition
}
// WhereClause implementation of SNoEarlierThanCondition for ICondition
func (c *SNoEarlierThanCondition) WhereClause() string {
return fmt.Sprintf("%s <= NOW()", c.field.Reference())
return fmt.Sprintf("%s >= NOW()", c.field.Reference())
}
// NoEarlierThan justifies a field is no earlier than current time
func NoEarlierThan(f IQueryField) ICondition {
c := SNoEarlierThanCondition{NewSingleCondition(f)}
return &c
}
// STupleCondition is a base condition that composed of two fields
type STupleCondition struct {
left IQueryField
right interface{}
@@ -273,7 +321,7 @@ func questionMark(count int) string {
} else {
var buf bytes.Buffer
buf.WriteString("( ")
for i := 0; i < count; i += 1 {
for i := 0; i < count; i++ {
if i > 0 {
buf.WriteString(", ")
}
@@ -313,14 +361,17 @@ func varConditionVariables(v interface{}) []interface{} {
}
}
// NewTupleCondition returns an instance of tuple condition
func NewTupleCondition(l IQueryField, r interface{}) STupleCondition {
return STupleCondition{left: l, right: r}
}
// Variables implementation of STupleCondition for ICondition
func (t *STupleCondition) Variables() []interface{} {
return varConditionVariables(t.right)
}
// SInCondition represents a IN operation in SQL query
type SInCondition struct {
STupleCondition
op string
@@ -334,10 +385,12 @@ func inConditionWhereClause(t *STupleCondition, op string) string {
return "0"
}
// WhereClause implementation of SInCondition for ICondition
func (t *SInCondition) WhereClause() string {
return inConditionWhereClause(&t.STupleCondition, t.op)
}
// In SQL operator
func In(f IQueryField, v interface{}) ICondition {
c := SInCondition{
NewTupleCondition(f, v),
@@ -346,6 +399,7 @@ func In(f IQueryField, v interface{}) ICondition {
return &c
}
// NotIn SQL operator
func NotIn(f IQueryField, v interface{}) ICondition {
c := SInCondition{
NewTupleCondition(f, v),
@@ -354,6 +408,7 @@ func NotIn(f IQueryField, v interface{}) ICondition {
return &c
}
// SLikeCondition represents LIKE operation in a SQL query
type SLikeCondition struct {
STupleCondition
}
@@ -369,15 +424,18 @@ func likeEscape(s string) string {
return res.String()
}
// WhereClause implementation for SLikeCondition for ICondition
func (t *SLikeCondition) WhereClause() string {
return tupleConditionWhereClause(&t.STupleCondition, SQL_OP_LIKE)
}
// Like SQL operator
func Like(f IQueryField, v string) ICondition {
c := SLikeCondition{NewTupleCondition(f, v)}
return &c
}
// ContainsAny is a OR combination of serveral Contains conditions
func ContainsAny(f IQueryField, v []string) ICondition {
conds := make([]ICondition, len(v))
for i := range v {
@@ -386,107 +444,130 @@ func ContainsAny(f IQueryField, v []string) ICondition {
return OR(conds...)
}
// Contains method is a shortcut of LIKE method, Contains represents the condtion that a field contains a substring
func Contains(f IQueryField, v string) ICondition {
v = likeEscape(v)
nv := fmt.Sprintf("%%%s%%", v)
return Like(f, nv)
}
// Startswith method is a shortcut of LIKE method, Startswith represents the condition that field starts with a substring
func Startswith(f IQueryField, v string) ICondition {
v = likeEscape(v)
nv := fmt.Sprintf("%s%%", v)
return Like(f, nv)
}
// Endswith method is a shortcut of LIKE condition, Endswith represents that condition that field endswith a substring
func Endswith(f IQueryField, v string) ICondition {
v = likeEscape(v)
nv := fmt.Sprintf("%%%s", v)
return Like(f, nv)
}
// SEqualsCondition represents equal operation between two fields
type SEqualsCondition struct {
STupleCondition
}
// WhereClause implementation of SEqualsCondition for ICondition
func (t *SEqualsCondition) WhereClause() string {
return tupleConditionWhereClause(&t.STupleCondition, SQL_OP_EQUAL)
}
// Equals method represents equal of two fields
func Equals(f IQueryField, v interface{}) ICondition {
c := SEqualsCondition{NewTupleCondition(f, v)}
return &c
}
// SNotEqualsCondition is the opposite of equal condition
type SNotEqualsCondition struct {
STupleCondition
}
// WhereClause implementation of SNotEqualsCondition for ICondition
func (t *SNotEqualsCondition) WhereClause() string {
return tupleConditionWhereClause(&t.STupleCondition, SQL_OP_NOTEQUAL)
}
// NotEquals method represents not equal of two fields
func NotEquals(f IQueryField, v interface{}) ICondition {
c := SNotEqualsCondition{NewTupleCondition(f, v)}
return &c
}
// SGreatEqualCondition represents >= operation on two fields
type SGreatEqualCondition struct {
STupleCondition
}
// WhereClause implementation of SGreatEqualCondition for ICondition
func (t *SGreatEqualCondition) WhereClause() string {
return tupleConditionWhereClause(&t.STupleCondition, SQL_OP_GE)
}
// GE method represetns operation of Greate Than Or Equal to, e.g. a >= b
func GE(f IQueryField, v interface{}) ICondition {
c := SGreatEqualCondition{NewTupleCondition(f, v)}
return &c
}
// SGreatThanCondition represetns > operation on two fields
type SGreatThanCondition struct {
STupleCondition
}
// WhereClause implementation of SGreatThanCondition for ICondition
func (t *SGreatThanCondition) WhereClause() string {
return tupleConditionWhereClause(&t.STupleCondition, SQL_OP_GT)
}
// GT method represents operation of Great Than, e.g. a > b
func GT(f IQueryField, v interface{}) ICondition {
c := SGreatThanCondition{NewTupleCondition(f, v)}
return &c
}
// SLessEqualCondition represents <= operation on two fields
type SLessEqualCondition struct {
STupleCondition
}
// WhereClause implementation of SLessEqualCondition for ICondition
func (t *SLessEqualCondition) WhereClause() string {
return tupleConditionWhereClause(&t.STupleCondition, SQL_OP_LE)
}
// LE method represents operation of Less Than Or Equal to, e.q. a <= b
func LE(f IQueryField, v interface{}) ICondition {
c := SLessEqualCondition{NewTupleCondition(f, v)}
return &c
}
// SLessThanCondition represents < operation on two fields
type SLessThanCondition struct {
STupleCondition
}
// WhereClause implementation of SLessThanCondition for ICondition
func (t *SLessThanCondition) WhereClause() string {
return tupleConditionWhereClause(&t.STupleCondition, SQL_OP_LT)
}
// LT method represents operation of Less Than, e.g. a < b
func LT(f IQueryField, v interface{}) ICondition {
c := SLessThanCondition{NewTupleCondition(f, v)}
return &c
}
// STripleCondition represents a base condition that composed of THREE fields
type STripleCondition struct {
STupleCondition
right2 interface{}
}
// Variables implementation of STripleCondition for ICondition
func (t *STripleCondition) Variables() []interface{} {
ret := make([]interface{}, 0)
vars := varConditionVariables(t.right)
@@ -496,41 +577,51 @@ func (t *STripleCondition) Variables() []interface{} {
return ret
}
// NewTripleCondition return an instance of STripleCondition
func NewTripleCondition(l IQueryField, r interface{}, r2 interface{}) STripleCondition {
return STripleCondition{STupleCondition: NewTupleCondition(l, r),
right2: r2}
}
// SBetweenCondition represents BETWEEN operator, e.g. c between a and b
type SBetweenCondition struct {
STripleCondition
}
// WhereClause implementation of SBetweenCondition for ICondition
func (t *SBetweenCondition) WhereClause() string {
ret := tupleConditionWhereClause(&t.STupleCondition, SQL_OP_BETWEEN)
return fmt.Sprintf("%s AND %s", ret, varConditionWhereClause(t.right2))
}
// Between SQL operator
func Between(f IQueryField, r1, r2 interface{}) ICondition {
c := SBetweenCondition{NewTripleCondition(f, r1, r2)}
return &c
}
// STrueCondition represents a dummy condition that is always true
type STrueCondition struct{}
// WhereClause implementation of STrueCondition for ICondition
func (t *STrueCondition) WhereClause() string {
return "1"
}
// Variables implementation of STrueCondition for ICondition
func (t *STrueCondition) Variables() []interface{} {
return nil
}
// SFalseCondition is a dummy condition that is always false
type SFalseCondition struct{}
// WhereClause implementation of SFalseCondition for ICondition
func (t *SFalseCondition) WhereClause() string {
return "0"
}
// Variables implementation of SFalseCondition for ICondition
func (t *SFalseCondition) Variables() []interface{} {
return nil
}

31
vendor/yunion.io/x/sqlchemy/const.go generated vendored
View File

@@ -20,47 +20,78 @@ import (
)
const (
// SQL_OP_AND represents AND operator
SQL_OP_AND = "AND"
// SQL_OP_OR represents OR operator
SQL_OP_OR = "OR"
// SQL_OP_NOT represents NOT operator
SQL_OP_NOT = "NOT"
// SQL_OP_LIKE represents LIKE operator
SQL_OP_LIKE = "LIKE"
// SQL_OP_IN represents IN operator
SQL_OP_IN = "IN"
// SQL_OP_NOTIN represents NOT IN operator
SQL_OP_NOTIN = "NOT IN"
// SQL_OP_EQUAL represents EQUAL operator
SQL_OP_EQUAL = "="
// SQL_OP_LT represents < operator
SQL_OP_LT = "<"
// SQL_OP_LE represents <= operator
SQL_OP_LE = "<="
// SQL_OP_GT represents > operator
SQL_OP_GT = ">"
// SQL_OP_GE represents >= operator
SQL_OP_GE = ">="
// SQL_OP_BETWEEN represents BETWEEN operator
SQL_OP_BETWEEN = "BETWEEN"
// SQL_OP_NOTEQUAL represents NOT EQUAL operator
SQL_OP_NOTEQUAL = "<>"
)
const (
// TAG_IGNORE is a field tag that indicates the field is ignored, not represents a table column
TAG_IGNORE = "ignore"
// TAG_NAME is a field tag that indicates the column name of this field
TAG_NAME = "name"
// TAG_WIDTH is a field tag that indicates the width of the column, like VARCHAR(15)
TAG_WIDTH = "width"
// TAG_TEXT_LENGTH is a field tag that indicates the length of a text column
TAG_TEXT_LENGTH = "length"
// TAG_CHARSET is a field tag that indicates the charset of a text column
TAG_CHARSET = "charset"
// TAG_PRECISION is a field tag that indicates the precision of a float column
TAG_PRECISION = "precision"
// TAG_DEFAULT is a field tag that indicates the default value of a column
TAG_DEFAULT = "default"
// TAG_UNIQUE is a field tag that indicates the column value is unique
TAG_UNIQUE = "unique"
// TAG_INDEX is a field tag that indicates the column is a indexable column
TAG_INDEX = "index"
// TAG_PRIMARY is a field tag that indicates the column is part of primary key
TAG_PRIMARY = "primary"
// TAG_NULLABLE is a field tag that indicates the column is nullable
TAG_NULLABLE = "nullable"
// TAG_AUTOINCREMENT is a field tag that indicates the integer column is auto_increment, the column should must be primary
TAG_AUTOINCREMENT = "auto_increment"
// TAG_AUTOVERSION is a field tag that indicates the integer column is used to records the update version of a record
TAG_AUTOVERSION = "auto_version"
// TAG_UPDATE_TIMESTAMP is a field tag that indicates the datetime column is the updated_at timestamp
TAG_UPDATE_TIMESTAMP = "updated_at"
// TAG_CREATE_TIMESTAMP is a field tag that indicates the datetime column is the created_at timestamp
TAG_CREATE_TIMESTAMP = "created_at"
// TAG_ALLOW_ZERO is a field tag that indicates whether the column allow zero value
TAG_ALLOW_ZERO = "allow_zero"
)
var (
// INT_WIDTH_DEFAULT records the default width of integer type
INT_WIDTH_DEFAULT = map[string]int{
"TINYINT": 4,
"SMALLINT": 6,
"INT": 11,
"BIGINT": 20,
}
// UNSIGNED_INT_WIDTH_DEFAULT records the default width of unsigned integer type
UNSIGNED_INT_WIDTH_DEFAULT = map[string]int{
"TINYINT": 3,
"SMALLINT": 5,

View File

@@ -19,7 +19,7 @@ import (
"strings"
)
type STableConstraint struct {
type sTableConstraint struct {
name string
columns []string
foreignTable string
@@ -53,11 +53,11 @@ func fetchColumns(match string) []string {
return ret
}
func parseConstraints(defStr string) []STableConstraint {
func parseConstraints(defStr string) []sTableConstraint {
matches := constraintRegexp.FindAllStringSubmatch(defStr, -1)
tcs := make([]STableConstraint, len(matches))
tcs := make([]sTableConstraint, len(matches))
for i := range matches {
tcs[i] = STableConstraint{
tcs[i] = sTableConstraint{
name: matches[i][1],
foreignTable: matches[i][4],
columns: fetchColumns(matches[i][2]),
@@ -67,11 +67,11 @@ func parseConstraints(defStr string) []STableConstraint {
return tcs
}
func parseIndexes(defStr string) []STableIndex {
func parseIndexes(defStr string) []sTableIndex {
matches := indexRegexp.FindAllStringSubmatch(defStr, -1)
tcs := make([]STableIndex, len(matches))
tcs := make([]sTableIndex, len(matches))
for i := range matches {
tcs[i] = STableIndex{
tcs[i] = sTableIndex{
name: matches[i][2],
isUnique: len(matches[i][1]) > 0,
columns: fetchColumns(matches[i][3]),

32
vendor/yunion.io/x/sqlchemy/debug.go generated vendored
View File

@@ -15,33 +15,57 @@
package sqlchemy
import (
"fmt"
"strings"
"time"
"yunion.io/x/log"
)
var (
// DEBUG_SQLCHEMY is a global constant that indicates turn on SQL debug
DEBUG_SQLCHEMY = false
)
func sqlDebug(sqlstr string, variables []interface{}) {
for _, v := range variables {
switch v.(type) {
case bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
sqlstr = strings.Replace(sqlstr, "?", fmt.Sprintf(`%v`, v), 1)
case string, time.Time:
sqlstr = strings.Replace(sqlstr, "?", fmt.Sprintf(`"%s"`, v), 1)
default:
sqlstr = strings.Replace(sqlstr, "?", fmt.Sprintf(`"%v"`, v), 1)
}
}
log.Debugln("SQuery ", sqlstr)
}
// DebugQuery show the full query string for debug
func (tq *SQuery) DebugQuery() {
sqlstr := tq.String()
vars := tq.Variables()
log.Debugf("SQuery %s with vars: %s", sqlstr, vars)
sqlDebug(sqlstr, vars)
}
// DebugQuery show the full query string for a subquery for debug
func (sqf *SSubQuery) DebugQuery() {
sqlstr := sqf.Expression()
vars := sqf.query.Variables()
log.Debugf("SQuery %s with vars: %s", sqlstr, vars)
sqlDebug(sqlstr, vars)
}
// DebugInsert does insert with debug mode on
func (t *STableSpec) DebugInsert(dt interface{}) error {
return t.insert(dt, false, true)
}
// DebugInsertOrUpdate does insertOrUpdate with debug mode on
func (t *STableSpec) DebugInsertOrUpdate(dt interface{}) error {
return t.insert(dt, true, true)
}
func (ts *STableSpec) DebugUpdateFields(dt interface{}, fields map[string]interface{}) error {
return ts.updateFields(dt, fields, true)
// DebugUpdateFields does update with debug mode on
func (t *STableSpec) DebugUpdateFields(dt interface{}, fields map[string]interface{}) error {
return t.updateFields(dt, fields, true)
}

View File

@@ -21,19 +21,38 @@ import (
)
const (
// ErrNoDataToUpdate is an Error constant: no data to update
ErrNoDataToUpdate = errors.Error("No data to update")
// ErrDuplicateEntry is an Error constant: duplicate entry
ErrDuplicateEntry = errors.Error("duplicate entry")
// ErrEmptyQuery is an Error constant: empty query
ErrEmptyQuery = errors.Error("empty query")
// ErrEmptyPrimaryKey is an Error constant: no primary key
ErrEmptyPrimaryKey = errors.Error("empty primary keys")
// ErrUnexpectRowCount is an Error constant: the number of rows impacted by modification unexpected
ErrUnexpectRowCount = errors.Error("unexpected row count")
// ErrNeedsPointer is an Error constant: input should be a pointer
ErrNeedsPointer = errors.Error("input needs pointer input")
// ErrNeedsArray is an Error constant: input should be an Array or Slice
ErrNeedsArray = errors.Error("input needs slice or array")
// ErrReadOnly is an Error constant: database is read-only
ErrReadOnly = errors.Error("read only input")
// ErrNotSupported is an Error constant: method not supported yet
ErrNotSupported = errors.ErrNotSupported
// ErrTableNotExists is an Error constant: table not exists
ErrTableNotExists = errors.Error("TableNotExists")
// ErrUnionFieldsNotMatch is an Error constant: fields of union queries not match
ErrUnionFieldsNotMatch = errors.Error("cannot union, name of fields not match")
)
const (

10
vendor/yunion.io/x/sqlchemy/fetch.go generated vendored
View File

@@ -24,7 +24,7 @@ import (
"yunion.io/x/pkg/util/reflectutils"
)
// fetch the values of a struct whose primary key values have been set
// Fetch method fetches the values of a struct whose primary key values have been set
// input is a pointer to the model to be populated
func (ts *STableSpec) Fetch(dt interface{}) error {
q := ts.Query()
@@ -39,7 +39,7 @@ func (ts *STableSpec) Fetch(dt interface{}) error {
return q.First(dt)
}
// fetch the values of an array of structs whose primary key values have been set
// FetchAll method fetches the values of an array of structs whose primary key values have been set
// input is a pointer to the array of models to be populated
func (ts *STableSpec) FetchAll(dest interface{}) error {
arrayType := reflect.TypeOf(dest).Elem()
@@ -56,7 +56,7 @@ func (ts *STableSpec) FetchAll(dest interface{}) error {
primaryCol := primaryCols[0]
keyValues := make([]interface{}, arrayValue.Len())
for i := 0; i < arrayValue.Len(); i += 1 {
for i := 0; i < arrayValue.Len(); i++ {
eleValue := arrayValue.Index(i)
fields := reflectutils.FetchStructFieldValueSet(eleValue)
keyValues[i], _ = fields.GetInterface(primaryCol.Name())
@@ -69,11 +69,11 @@ func (ts *STableSpec) FetchAll(dest interface{}) error {
}
tmpDestMapMap := make(map[string]map[string]string)
for i := 0; i < len(tmpDestMaps); i += 1 {
for i := 0; i < len(tmpDestMaps); i++ {
tmpDestMapMap[tmpDestMaps[i][primaryCol.Name()]] = tmpDestMaps[i]
}
for i := 0; i < arrayValue.Len(); i += 1 {
for i := 0; i < arrayValue.Len(); i++ {
keyValueStr := getStringValue(keyValues[i])
if tmpMap, ok := tmpDestMapMap[keyValueStr]; ok {
err = mapString2Struct(tmpMap, arrayValue.Index(i))

View File

@@ -51,6 +51,8 @@ func (ts *STableSpec) GetUpdateColumnValue(dataType reflect.Type, dataValue refl
}
*/
// UpdateFields update a record with the values provided by fields stringmap
// params dt: model struct, fileds: {struct-field-name-string: update-value}
func (ts *STableSpec) UpdateFields(dt interface{}, fields map[string]interface{}) error {
return ts.updateFields(dt, fields, false)
}

158
vendor/yunion.io/x/sqlchemy/filter.go generated vendored
View File

@@ -14,6 +14,8 @@
package sqlchemy
// Filter method filters a SQL query with given ICondition
// equivalent to add a clause in where conditions
func (tq *SQuery) Filter(cond ICondition) *SQuery {
if tq.groupBy != nil && len(tq.groupBy) > 0 {
if tq.having == nil {
@@ -31,120 +33,144 @@ func (tq *SQuery) Filter(cond ICondition) *SQuery {
return tq
}
// FilterByTrue filters query with a true condition
func (tq *SQuery) FilterByTrue() *SQuery {
return tq.Filter(&STrueCondition{})
}
// FilterByFalse filters query with a false condition
func (tq *SQuery) FilterByFalse() *SQuery {
return tq.Filter(&SFalseCondition{})
}
func (q *SQuery) Like(f string, v string) *SQuery {
cond := Like(q.Field(f), v)
return q.Filter(cond)
// Like filters query with a like condition
func (tq *SQuery) Like(f string, v string) *SQuery {
cond := Like(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) Contains(f string, v string) *SQuery {
cond := Contains(q.Field(f), v)
return q.Filter(cond)
// Contains filters query with a contains condition
func (tq *SQuery) Contains(f string, v string) *SQuery {
cond := Contains(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) Startswith(f string, v string) *SQuery {
cond := Startswith(q.Field(f), v)
return q.Filter(cond)
// Startswith filters query with a startswith condition
func (tq *SQuery) Startswith(f string, v string) *SQuery {
cond := Startswith(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) Endswith(f string, v string) *SQuery {
cond := Endswith(q.Field(f), v)
return q.Filter(cond)
// Endswith filters query with a endswith condition
func (tq *SQuery) Endswith(f string, v string) *SQuery {
cond := Endswith(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) NotLike(f string, v string) *SQuery {
cond := Like(q.Field(f), v)
return q.Filter(NOT(cond))
// NotLike filters query with a not like condition
func (tq *SQuery) NotLike(f string, v string) *SQuery {
cond := Like(tq.Field(f), v)
return tq.Filter(NOT(cond))
}
func (q *SQuery) In(f string, v interface{}) *SQuery {
cond := In(q.Field(f), v)
return q.Filter(cond)
// In filters query with a in condition
func (tq *SQuery) In(f string, v interface{}) *SQuery {
cond := In(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) NotIn(f string, v interface{}) *SQuery {
cond := In(q.Field(f), v)
return q.Filter(NOT(cond))
// NotIn filters query with a not in condition
func (tq *SQuery) NotIn(f string, v interface{}) *SQuery {
cond := In(tq.Field(f), v)
return tq.Filter(NOT(cond))
}
func (q *SQuery) Between(f string, v1, v2 interface{}) *SQuery {
cond := Between(q.Field(f), v1, v2)
return q.Filter(cond)
// Between filters query with a between condition
func (tq *SQuery) Between(f string, v1, v2 interface{}) *SQuery {
cond := Between(tq.Field(f), v1, v2)
return tq.Filter(cond)
}
func (q *SQuery) NotBetween(f string, v1, v2 interface{}) *SQuery {
cond := Between(q.Field(f), v1, v2)
return q.Filter(NOT(cond))
// NotBetween filters query with a not between condition
func (tq *SQuery) NotBetween(f string, v1, v2 interface{}) *SQuery {
cond := Between(tq.Field(f), v1, v2)
return tq.Filter(NOT(cond))
}
func (q *SQuery) Equals(f string, v interface{}) *SQuery {
cond := Equals(q.Field(f), v)
return q.Filter(cond)
// Equals filters query with a equals condition
func (tq *SQuery) Equals(f string, v interface{}) *SQuery {
cond := Equals(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) NotEquals(f string, v interface{}) *SQuery {
cond := NotEquals(q.Field(f), v)
return q.Filter(cond)
// NotEquals filters the query with a not equals condition
func (tq *SQuery) NotEquals(f string, v interface{}) *SQuery {
cond := NotEquals(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) GE(f string, v interface{}) *SQuery {
cond := GE(q.Field(f), v)
return q.Filter(cond)
// GE filters the query with a >= condition
func (tq *SQuery) GE(f string, v interface{}) *SQuery {
cond := GE(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) LE(f string, v interface{}) *SQuery {
cond := LE(q.Field(f), v)
return q.Filter(cond)
// LE filters the query with a <= condition
func (tq *SQuery) LE(f string, v interface{}) *SQuery {
cond := LE(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) GT(f string, v interface{}) *SQuery {
cond := GT(q.Field(f), v)
return q.Filter(cond)
// GT filters the query with a > condition
func (tq *SQuery) GT(f string, v interface{}) *SQuery {
cond := GT(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) LT(f string, v interface{}) *SQuery {
cond := LT(q.Field(f), v)
return q.Filter(cond)
// LT filters the query with a < condition
func (tq *SQuery) LT(f string, v interface{}) *SQuery {
cond := LT(tq.Field(f), v)
return tq.Filter(cond)
}
func (q *SQuery) IsNull(f string) *SQuery {
cond := IsNull(q.Field(f))
return q.Filter(cond)
// IsNull filters the query with a is null condition
func (tq *SQuery) IsNull(f string) *SQuery {
cond := IsNull(tq.Field(f))
return tq.Filter(cond)
}
func (q *SQuery) IsNotNull(f string) *SQuery {
cond := IsNotNull(q.Field(f))
return q.Filter(cond)
// IsNotNull filters the query with a is not null condition
func (tq *SQuery) IsNotNull(f string) *SQuery {
cond := IsNotNull(tq.Field(f))
return tq.Filter(cond)
}
func (q *SQuery) IsEmpty(f string) *SQuery {
cond := IsEmpty(q.Field(f))
return q.Filter(cond)
// IsEmpty filters the query with a is_empty condition
func (tq *SQuery) IsEmpty(f string) *SQuery {
cond := IsEmpty(tq.Field(f))
return tq.Filter(cond)
}
func (q *SQuery) IsNullOrEmpty(f string) *SQuery {
cond := IsNullOrEmpty(q.Field(f))
return q.Filter(cond)
// IsNullOrEmpty filters the query with a is null or empty condition
func (tq *SQuery) IsNullOrEmpty(f string) *SQuery {
cond := IsNullOrEmpty(tq.Field(f))
return tq.Filter(cond)
}
func (q *SQuery) IsNotEmpty(f string) *SQuery {
cond := IsNotEmpty(q.Field(f))
return q.Filter(cond)
// IsNotEmpty filters the query with a is not empty condition
func (tq *SQuery) IsNotEmpty(f string) *SQuery {
cond := IsNotEmpty(tq.Field(f))
return tq.Filter(cond)
}
func (q *SQuery) IsTrue(f string) *SQuery {
cond := IsTrue(q.Field(f))
return q.Filter(cond)
// IsTrue filters the query with a is true condition
func (tq *SQuery) IsTrue(f string) *SQuery {
cond := IsTrue(tq.Field(f))
return tq.Filter(cond)
}
func (q *SQuery) IsFalse(f string) *SQuery {
cond := IsFalse(q.Field(f))
return q.Filter(cond)
// IsFalse filters the query with a is false condition
func (tq *SQuery) IsFalse(f string) *SQuery {
cond := IsFalse(tq.Field(f))
return tq.Filter(cond)
}

View File

@@ -22,43 +22,46 @@ import (
"yunion.io/x/log"
)
// IFunction is the interface for a SQL embedded function, such as MIN, MAX, NOW, etc.
type IFunction interface {
expression() string
variables() []interface{}
}
// SFunctionFieldBase is a query field that is the result of a SQL embedded function, e.g. COUNT(*) as count
type SFunctionFieldBase struct {
IFunction
alias string
}
// Reference implementation of SFunctionFieldBase for IQueryField
func (ff *SFunctionFieldBase) Reference() string {
if len(ff.alias) == 0 {
log.Warningf("reference a function field without alias! %s", ff.expression())
return ff.expression()
} else {
return fmt.Sprintf("`%s`", ff.alias)
}
return fmt.Sprintf("`%s`", ff.alias)
}
// Expression implementation of SFunctionFieldBase for IQueryField
func (ff *SFunctionFieldBase) Expression() string {
if len(ff.alias) > 0 {
// add alias
return fmt.Sprintf("%s AS `%s`", ff.expression(), ff.alias)
} else {
}
// no alias
return ff.expression()
}
}
// Name implementation of SFunctionFieldBase for IQueryField
func (ff *SFunctionFieldBase) Name() string {
if len(ff.alias) > 0 {
return ff.alias
} else {
return ff.expression()
}
return ff.expression()
}
// Label implementation of SFunctionFieldBase for IQueryField
func (ff *SFunctionFieldBase) Label(label string) IQueryField {
if len(label) > 0 && label != ff.alias {
ff.alias = label
@@ -66,16 +69,17 @@ func (ff *SFunctionFieldBase) Label(label string) IQueryField {
return ff
}
// Variables implementation of SFunctionFieldBase for IQueryField
func (ff *SFunctionFieldBase) Variables() []interface{} {
return ff.variables()
}
type SExprFunction struct {
type sExprFunction struct {
fields []IQueryField
function string
}
func (ff *SExprFunction) expression() string {
func (ff *sExprFunction) expression() string {
fieldRefs := make([]interface{}, 0)
for _, f := range ff.fields {
fieldRefs = append(fieldRefs, f.Reference())
@@ -83,7 +87,7 @@ func (ff *SExprFunction) expression() string {
return fmt.Sprintf(ff.function, fieldRefs...)
}
func (ff *SExprFunction) variables() []interface{} {
func (ff *sExprFunction) variables() []interface{} {
vars := make([]interface{}, 0)
for _, f := range ff.fields {
fromVars := f.Variables()
@@ -92,8 +96,9 @@ func (ff *SExprFunction) variables() []interface{} {
return vars
}
// NewFunctionField returns an instance of query field by calling a SQL embedded function
func NewFunctionField(name string, funcexp string, fields ...IQueryField) IQueryField {
funcBase := &SExprFunction{
funcBase := &sExprFunction{
fields: fields,
function: funcexp,
}
@@ -103,6 +108,7 @@ func NewFunctionField(name string, funcexp string, fields ...IQueryField) IQuery
}
}
// COUNT represents the SQL function COUNT
func COUNT(name string, field ...IQueryField) IQueryField {
var expr string
if len(field) == 0 {
@@ -113,47 +119,58 @@ func COUNT(name string, field ...IQueryField) IQueryField {
return NewFunctionField(name, expr, field...)
}
// MAX represents the SQL function MAX
func MAX(name string, field IQueryField) IQueryField {
return NewFunctionField(name, "MAX(%s)", field)
}
// MIN represents the SQL function MIN
func MIN(name string, field IQueryField) IQueryField {
return NewFunctionField(name, "MIN(%s)", field)
}
// SUM represents the SQL function SUM
func SUM(name string, field IQueryField) IQueryField {
return NewFunctionField(name, "SUM(%s)", field)
}
// DISTINCT represents the SQL function DISTINCT
func DISTINCT(name string, field IQueryField) IQueryField {
return NewFunctionField(name, "DISTINCT(%s)", field)
}
// GROUP_CONCAT represents the SQL function GROUP_CONCAT
func GROUP_CONCAT(name string, field IQueryField) IQueryField {
return NewFunctionField(name, "GROUP_CONCAT(%s)", field)
}
// REPLACE represents the SQL function REPLACE
func REPLACE(name string, field IQueryField, old string, new string) IQueryField {
return NewFunctionField(name, fmt.Sprintf(`REPLACE(%s, "%s", "%s")`, "%s", old, new), field)
}
// SConstField is a query field of a constant
type SConstField struct {
constVar interface{}
alias string
}
// Expression implementation of SConstField for IQueryField
func (s *SConstField) Expression() string {
return fmt.Sprintf("%s AS `%s`", s.Reference(), s.Name())
}
// Name implementation of SConstField for IQueryField
func (s *SConstField) Name() string {
return s.alias
}
// Reference implementation of SConstField for IQueryField
func (s *SConstField) Reference() string {
return getQuoteStringValue(s.constVar)
}
// Label implementation of SConstField for IQueryField
func (s *SConstField) Label(label string) IQueryField {
if len(label) > 0 {
s.alias = label
@@ -161,31 +178,38 @@ func (s *SConstField) Label(label string) IQueryField {
return s
}
// Variables implementation of SConstField for IQueryField
func (s *SConstField) Variables() []interface{} {
return nil
}
// NewConstField returns an instance of SConstField
func NewConstField(variable interface{}) *SConstField {
return &SConstField{constVar: variable}
}
// SStringField is a query field of a string constant
type SStringField struct {
strConst string
alias string
}
// Expression implementation of SStringField for IQueryField
func (s *SStringField) Expression() string {
return fmt.Sprintf("%s AS `%s`", s.Reference(), s.Name())
}
// Name implementation of SStringField for IQueryField
func (s *SStringField) Name() string {
return s.alias
}
// Reference implementation of SStringField for IQueryField
func (s *SStringField) Reference() string {
return strconv.Quote(s.strConst)
}
// Label implementation of SStringField for IQueryField
func (s *SStringField) Label(label string) IQueryField {
if len(label) > 0 {
s.alias = label
@@ -193,14 +217,17 @@ func (s *SStringField) Label(label string) IQueryField {
return s
}
// Variables implementation of SStringField for IQueryField
func (s *SStringField) Variables() []interface{} {
return nil
}
// NewStringField returns an instance of SStringField
func NewStringField(name string) *SStringField {
return &SStringField{strConst: name}
}
// CONCAT represents a SQL function CONCAT
func CONCAT(name string, fields ...IQueryField) IQueryField {
params := []string{}
for i := 0; i < len(fields); i++ {
@@ -209,6 +236,7 @@ func CONCAT(name string, fields ...IQueryField) IQueryField {
return NewFunctionField(name, `CONCAT(`+strings.Join(params, ",")+`)`, fields...)
}
// SubStr represents a SQL function SUBSTR
func SubStr(name string, field IQueryField, pos, length int) IQueryField {
var rightStr string
if length <= 0 {
@@ -219,20 +247,24 @@ func SubStr(name string, field IQueryField, pos, length int) IQueryField {
return NewFunctionField(name, `SUBSTR(%s, `+rightStr, field)
}
// OR_Val represents a SQL function that does binary | operation on a field
func OR_Val(name string, field IQueryField, v interface{}) IQueryField {
rightStr := fmt.Sprintf("|%v", v)
return NewFunctionField(name, "%s"+rightStr, field)
}
// AND_Val represents a SQL function that does binary & operation on a field
func AND_Val(name string, field IQueryField, v interface{}) IQueryField {
rightStr := fmt.Sprintf("&%v", v)
return NewFunctionField(name, "%s"+rightStr, field)
}
// INET_ATON represents a SQL function INET_ATON
func INET_ATON(field IQueryField) IQueryField {
return NewFunctionField("", `INET_ATON(%s)`, field)
}
// TimestampAdd represents a SQL function TimestampAdd
func TimestampAdd(name string, field IQueryField, offsetSeconds int) IQueryField {
return NewFunctionField(name, `TIMESTAMPADD(SECOND, `+fmt.Sprintf("%d", offsetSeconds)+`, %s)`, field)
}

9
vendor/yunion.io/x/sqlchemy/inc.go generated vendored
View File

@@ -26,10 +26,16 @@ import (
"yunion.io/x/pkg/util/reflectutils"
)
// Increment perform an incremental update on a record, the primary key of the record is specified in diff,
// the numeric fields of this record will be atomically added by the value of the corresponding field in diff
// if target is given as a pointer to a variable, the result will be stored in the target
// if target is not given, the updated result will be stored in diff
func (t *STableSpec) Increment(diff interface{}, target interface{}) error {
return t.incrementInternal(diff, "+", target)
}
// Decrement is similar to Increment methods, the difference is that this method will atomically decrease the numeric fields
// with the value of diff
func (t *STableSpec) Decrement(diff interface{}, target interface{}) error {
return t.incrementInternal(diff, "-", target)
}
@@ -144,9 +150,8 @@ func (t *STableSpec) incrementInternal(diff interface{}, opcode string, target i
if aCnt != 1 {
if aCnt == 0 {
return sql.ErrNoRows
} else {
return errors.Wrapf(ErrUnexpectRowCount, "affected rows %d != 1", aCnt)
}
return errors.Wrapf(ErrUnexpectRowCount, "affected rows %d != 1", aCnt)
}
q := t.Query()
for k, v := range primaries {

20
vendor/yunion.io/x/sqlchemy/index.go generated vendored
View File

@@ -19,13 +19,13 @@ import (
"strings"
)
type STableIndex struct {
type sTableIndex struct {
name string
columns []string
isUnique bool
}
type TColumnNames []string
/*type TColumnNames []string
func (cols TColumnNames) Len() int {
return len(cols)
@@ -41,13 +41,13 @@ func (cols TColumnNames) Less(i, j int) bool {
} else {
return false
}
}
}*/
func (index *STableIndex) IsIdentical(cols ...string) bool {
func (index *sTableIndex) IsIdentical(cols ...string) bool {
if len(index.columns) != len(cols) {
return false
}
for i := 0; i < len(index.columns); i += 1 {
for i := 0; i < len(index.columns); i++ {
if index.columns[i] != cols[i] {
return false
}
@@ -55,22 +55,24 @@ func (index *STableIndex) IsIdentical(cols ...string) bool {
return true
}
func (index *STableIndex) QuotedColumns() []string {
func (index *sTableIndex) QuotedColumns() []string {
ret := make([]string, len(index.columns))
for i := 0; i < len(ret); i += 1 {
for i := 0; i < len(ret); i++ {
ret[i] = fmt.Sprintf("`%s`", index.columns[i])
}
return ret
}
// AddIndex adds a SQL index over multiple columns for a Table
// param unique: indicates a unique index cols: name of columns
func (ts *STableSpec) AddIndex(unique bool, cols ...string) bool {
for i := 0; i < len(ts.indexes); i += 1 {
for i := 0; i < len(ts.indexes); i++ {
if ts.indexes[i].IsIdentical(cols...) {
return false
}
}
name := fmt.Sprintf("ix_%s_%s", ts.name, strings.Join(cols, "_"))
idx := STableIndex{name: name, columns: cols, isUnique: unique}
idx := sTableIndex{name: name, columns: cols, isUnique: unique}
ts.indexes = append(ts.indexes, idx)
return true
}

View File

@@ -25,11 +25,12 @@ import (
"yunion.io/x/pkg/util/reflectutils"
)
// Insert perform a insert operation, the value of the record is store in dt
func (t *STableSpec) Insert(dt interface{}) error {
return t.insert(dt, false, false)
}
//
// InsertOrUpdate perform a insert or update operation, the value of the record is string in dt
// MySQL: INSERT INTO ... ON DUPLICATE KEY UPDATE ...
// works only for the cases that all values of primary keys are determeted before insert
func (t *STableSpec) InsertOrUpdate(dt interface{}) error {
@@ -148,11 +149,28 @@ func (t *STableSpec) insertSqlPrep(dataFields reflectutils.SStructFieldValueSet,
return insertSql, values, nil
}
func (t *STableSpec) insert(data interface{}, update bool, debug bool) error {
beforeInsertFunc := reflect.ValueOf(data).MethodByName("BeforeInsert")
if beforeInsertFunc.IsValid() && !beforeInsertFunc.IsNil() {
beforeInsertFunc.Call([]reflect.Value{})
func beforeInsert(val reflect.Value) {
switch val.Kind() {
case reflect.Struct:
structType := val.Type()
for i := 0; i < val.NumField(); i++ {
fieldType := structType.Field(i)
if fieldType.Anonymous {
beforeInsert(val.Field(i))
}
}
valPtr := val.Addr()
afterMarshalFunc := valPtr.MethodByName("BeforeInsert")
if afterMarshalFunc.IsValid() && !afterMarshalFunc.IsNil() {
afterMarshalFunc.Call([]reflect.Value{})
}
case reflect.Ptr:
beforeInsert(val.Elem())
}
}
func (t *STableSpec) insert(data interface{}, update bool, debug bool) error {
beforeInsert(reflect.ValueOf(data))
dataValue := reflect.ValueOf(data).Elem()
dataFields := reflectutils.FetchStructFieldValueSet(dataValue)
@@ -205,9 +223,8 @@ func (t *STableSpec) insert(data interface{}, update bool, debug bool) error {
lastId, err := results.LastInsertId()
if err != nil {
return errors.Wrap(err, "fetching lastInsertId failed")
} else {
q = q.Equals(c.Name(), lastId)
}
q = q.Equals(c.Name(), lastId)
} else {
priVal, _ := dataFields.GetInterface(c.Name())
if !gotypes.IsNil(priVal) {

View File

@@ -35,7 +35,7 @@ func structField2ColumnSpec(field *reflectutils.SStructFieldValue) IColumnSpec {
retCol = getFiledTypeCol(fieldType.Elem(), fieldname, tagmap, true)
}
if retCol == nil {
panic("unsupported colume data type %s" + fieldType.Name())
panic(fmt.Sprintf("unsupported colume %s data type %s", fieldname, fieldType.Name()))
}
return retCol
}
@@ -94,7 +94,7 @@ func getFiledTypeCol(fieldType reflect.Type, fieldname string, tagmap map[string
if _, ok := tagmap[TAG_WIDTH]; ok {
col := NewDecimalColumn(fieldname, tagmap, isPointer)
return &col
} else {
}
colType := "FLOAT"
if fieldType == gotypes.Float64Type {
colType = "DOUBLE"
@@ -102,7 +102,6 @@ func getFiledTypeCol(fieldType reflect.Type, fieldname string, tagmap map[string
col := NewFloatColumn(fieldname, colType, tagmap, isPointer)
return &col
}
}
if fieldType.Implements(gotypes.ISerializableType) {
col := NewCompoundColumn(fieldname, tagmap, isPointer)
return &col
@@ -113,11 +112,11 @@ func getFiledTypeCol(fieldType reflect.Type, fieldname string, tagmap map[string
func struct2TableSpec(sv reflect.Value, table *STableSpec) {
fields := reflectutils.FetchStructFieldValueSet(sv)
autoIncCnt := 0
for i := 0; i < len(fields); i += 1 {
for i := 0; i < len(fields); i++ {
column := structField2ColumnSpec(&fields[i])
if column != nil {
if intC, ok := column.(*SIntegerColumn); ok && intC.IsAutoIncrement {
autoIncCnt += 1
autoIncCnt++
if autoIncCnt > 1 {
panic(fmt.Sprintf("Table %s contains multiple autoincremental columns!!", table.name))
}

180
vendor/yunion.io/x/sqlchemy/query.go generated vendored
View File

@@ -27,81 +27,111 @@ import (
"yunion.io/x/pkg/util/reflectutils"
)
// IQuery is an interface that reprsents a SQL query, e.g.
// SELECT ... FROM ... WHERE ...
type IQuery interface {
// queryString
String(fields ...IQueryField) string
// fields after select
// fields in the select clause
QueryFields() []IQueryField
// variables in statement
Variables() []interface{}
// convert to a subquery
// convert this SQL to a subquery
SubQuery() *SSubQuery
// reference to a field by name
Field(name string) IQueryField
}
// IQuerySource is an interface that represents a data source of a SQL query. the source can be a table or a subquery
// e.g. SELECT ... FROM (SELECT * FROM tbl) AS A
type IQuerySource interface {
// string in select ... from (expresson here)
Expression() string
// alias in select ... from (express) as alias
Alias() string
// variables in statement
Variables() []interface{}
// reference to a field by name, optionally giving an alias name
Field(id string, alias ...string) IQueryField
// return all the fields that this source provides
Fields() []IQueryField
}
// IQueryField is an interface that represents a select field in a SQL query
type IQueryField interface {
// the string after select
Expression() string
// the name of thie field
Name() string
// the string in where clause
// the reference string in where clause
Reference() string
// give this field an alias name
Label(label string) IQueryField
// return variables
Variables() []interface{}
}
// Expression implementation of STable for IQuerySource
func (tbl *STable) Expression() string {
return tbl.spec.Expression()
}
// Alias implementation of STable for IQuerySource
func (tbl *STable) Alias() string {
return tbl.alias
}
// Variables implementation of STable for IQuerySource
func (tbl *STable) Variables() []interface{} {
return []interface{}{}
}
// QueryJoinType is the Join type of SQL query, namely, innerjoin, leftjoin and rightjoin
type QueryJoinType string
const (
// INNERJOIN represents innerjoin
INNERJOIN QueryJoinType = "JOIN"
// LEFTJOIN represents left join
LEFTJOIN QueryJoinType = "LEFT JOIN"
// RIGHTJOIN represents right-join
RIGHTJOIN QueryJoinType = "RIGHT JOIN"
// FULLJOIN QueryJoinType = "FULLJOIN"
)
type SQueryJoin struct {
// sQueryJoin represents the state of a Join Query
type sQueryJoin struct {
jointype QueryJoinType
from IQuerySource
condition ICondition
}
// SQuery is a data structure represents a SQL query in the form of
// SELECT ... FROM ... JOIN ... ON ... WHERE ... GROUP BY ... ORDER BY ... HAVING ...
type SQuery struct {
rawSql string
fields []IQueryField
distinct bool
from IQuerySource
joins []SQueryJoin
joins []sQueryJoin
where ICondition
groupBy []IQueryField
orderBy []SQueryOrder
orderBy []sQueryOrder
having ICondition
limit int
offset int
@@ -111,6 +141,9 @@ type SQuery struct {
snapshot string
}
// SSubQuery represents a subquery. A subquery is a query used as a query source
// SSubQuery should implementation IQuerySource
// At the same time, a subquery can be used in condition. e.g. IN condition
type SSubQuery struct {
query IQuery
alias string
@@ -118,32 +151,35 @@ type SSubQuery struct {
referedFields map[string]IQueryField
}
// SSubQueryField represents a field of subquery, which implements IQueryField
type SSubQueryField struct {
field IQueryField
query *SSubQuery
alias string
}
// Expression implementation of SSubQueryField for IQueryField
func (sqf *SSubQueryField) Expression() string {
if len(sqf.alias) > 0 {
return fmt.Sprintf("`%s`.`%s` AS `%s`", sqf.query.alias, sqf.field.Name(), sqf.alias)
} else {
return fmt.Sprintf("`%s`.`%s`", sqf.query.alias, sqf.field.Name())
}
return fmt.Sprintf("`%s`.`%s`", sqf.query.alias, sqf.field.Name())
}
// Name implementation of SSubQueryField for IQueryField
func (sqf *SSubQueryField) Name() string {
if len(sqf.alias) > 0 {
return sqf.alias
} else {
return sqf.field.Name()
}
return sqf.field.Name()
}
// Reference implementation of SSubQueryField for IQueryField
func (sqf *SSubQueryField) Reference() string {
return fmt.Sprintf("`%s`.`%s`", sqf.query.alias, sqf.Name())
}
// Label implementation of SSubQueryField for IQueryField
func (sqf *SSubQueryField) Label(label string) IQueryField {
if len(label) > 0 && label != sqf.field.Name() {
sqf.alias = label
@@ -151,10 +187,12 @@ func (sqf *SSubQueryField) Label(label string) IQueryField {
return sqf
}
// Variables implementation of SSubQueryField for IQueryField
func (sqf *SSubQueryField) Variables() []interface{} {
return nil
}
// Expression implementation of SSubQuery for IQuerySource
func (sq *SSubQuery) Expression() string {
fields := make([]IQueryField, 0)
for k := range sq.referedFields {
@@ -167,10 +205,12 @@ func (sq *SSubQuery) Expression() string {
return fmt.Sprintf("(%s)", sq.query.String(fields...))
}
// Alias implementation of SSubQuery for IQuerySource
func (sq *SSubQuery) Alias() string {
return sq.alias
}
// Variables implementation of SSubQuery for IQuerySource
func (sq *SSubQuery) Variables() []interface{} {
return sq.query.Variables()
}
@@ -192,6 +232,7 @@ func (sq *SSubQuery) findField(id string) IQueryField {
return nil
}
// Field implementation of SSubQuery for IQuerySource
func (sq *SSubQuery) Field(id string, alias ...string) IQueryField {
f := sq.findField(id)
if f == nil {
@@ -204,6 +245,7 @@ func (sq *SSubQuery) Field(id string, alias ...string) IQueryField {
return &sqf
}
// Fields implementation of SSubQuery for IQuerySource
func (sq *SSubQuery) Fields() []IQueryField {
ret := make([]IQueryField, 0)
for _, f := range sq.query.QueryFields() {
@@ -213,6 +255,7 @@ func (sq *SSubQuery) Fields() []IQueryField {
return ret
}
// DoQuery returns a SQuery instance that query specified fields from a query source
func DoQuery(from IQuerySource, f ...IQueryField) *SQuery {
// if len(f) == 0 {
// f = from.Fields()
@@ -221,57 +264,68 @@ func DoQuery(from IQuerySource, f ...IQueryField) *SQuery {
return &tq
}
func (q *SQuery) AppendField(f ...IQueryField) *SQuery {
q.fields = append(q.fields, f...)
return q
// AppendField appends query field to a query
func (tq *SQuery) AppendField(f ...IQueryField) *SQuery {
tq.fields = append(tq.fields, f...)
return tq
}
func (table *SSubQuery) Query(f ...IQueryField) *SQuery {
return DoQuery(table, f...)
// Query of SSubQuery generates a new query from a subquery
func (sq *SSubQuery) Query(f ...IQueryField) *SQuery {
return DoQuery(sq, f...)
}
// Query of STable generates a new query from a table
func (tbl *STable) Query(f ...IQueryField) *SQuery {
return DoQuery(tbl, f...)
}
// Query of STableSpec generates a new query from a STableSpec instance
func (ts *STableSpec) Query(f ...IQueryField) *SQuery {
return ts.Instance().Query(f...)
}
// QueryOrderType indicates the query order type, either ASC or DESC
type QueryOrderType string
const (
// SQL_ORDER_ASC represents Ascending order
SQL_ORDER_ASC QueryOrderType = "ASC"
// SQL_ORDER_DESC represents Descending order
SQL_ORDER_DESC QueryOrderType = "DESC"
)
// Equals of QueryOrderType determines whether two order type identical
func (qot QueryOrderType) Equals(orderType string) bool {
if strings.ToUpper(orderType) == string(qot) {
return true
} else {
return false
}
return false
}
type SQueryOrder struct {
// internal structure to store state of query order
type sQueryOrder struct {
field IQueryField
order QueryOrderType
}
func (tq *SQuery) _orderBy(order QueryOrderType, fields []IQueryField) *SQuery {
if tq.orderBy == nil {
tq.orderBy = make([]SQueryOrder, 0)
tq.orderBy = make([]sQueryOrder, 0)
}
for i := range fields {
tq.orderBy = append(tq.orderBy, SQueryOrder{field: fields[i], order: order})
tq.orderBy = append(tq.orderBy, sQueryOrder{field: fields[i], order: order})
}
return tq
}
// Asc of SQuery does query in ascending order of specified fields
func (tq *SQuery) Asc(fields ...interface{}) *SQuery {
return tq._orderBy(SQL_ORDER_ASC, convertQueryField(tq, fields))
}
// Desc of SQuery does query in descending order of specified fields
func (tq *SQuery) Desc(fields ...interface{}) *SQuery {
return tq._orderBy(SQL_ORDER_DESC, convertQueryField(tq, fields))
}
@@ -291,6 +345,7 @@ func convertQueryField(tq IQuery, fields []interface{}) []IQueryField {
return nFields
}
// GroupBy of SQuery does query group by specified fields
func (tq *SQuery) GroupBy(f ...interface{}) *SQuery {
if tq.groupBy == nil {
tq.groupBy = make([]IQueryField, 0)
@@ -300,24 +355,27 @@ func (tq *SQuery) GroupBy(f ...interface{}) *SQuery {
return tq
}
// Limit of SQuery adds limit to a query
func (tq *SQuery) Limit(limit int) *SQuery {
tq.limit = limit
return tq
}
// Offset of SQuery adds offset to a query
func (tq *SQuery) Offset(offset int) *SQuery {
tq.offset = offset
return tq
}
// QueryFields of SQuery returns fields in SELECT clause of a query
func (tq *SQuery) QueryFields() []IQueryField {
if len(tq.fields) > 0 {
return tq.fields
} else {
return tq.from.Fields()
}
return tq.from.Fields()
}
// String of SQuery implemetation of SQuery for IQuery
func (tq *SQuery) String(fields ...IQueryField) string {
sql := queryString(tq, fields...)
// log.Debugf("Query: %s", sql)
@@ -395,14 +453,17 @@ func queryString(tq *SQuery, tmpFields ...IQueryField) string {
return buf.String()
}
// Join of SQuery joins query with another IQuerySource on specified condition
func (tq *SQuery) Join(from IQuerySource, on ICondition) *SQuery {
return tq._join(from, on, INNERJOIN)
}
// LeftJoin of SQuery left-joins query with another IQuerySource on specified condition
func (tq *SQuery) LeftJoin(from IQuerySource, on ICondition) *SQuery {
return tq._join(from, on, LEFTJOIN)
}
// RightJoin of SQuery right-joins query with another IQuerySource on specified condition
func (tq *SQuery) RightJoin(from IQuerySource, on ICondition) *SQuery {
return tq._join(from, on, RIGHTJOIN)
}
@@ -413,13 +474,14 @@ func (tq *SQuery) RightJoin(from IQuerySource, on ICondition) *SQuery {
func (tq *SQuery) _join(from IQuerySource, on ICondition, joinType QueryJoinType) *SQuery {
if tq.joins == nil {
tq.joins = make([]SQueryJoin, 0)
tq.joins = make([]sQueryJoin, 0)
}
qj := SQueryJoin{jointype: joinType, from: from, condition: on}
qj := sQueryJoin{jointype: joinType, from: from, condition: on}
tq.joins = append(tq.joins, qj)
return tq
}
// Variables implementation of SQuery for IQuery
func (tq *SQuery) Variables() []interface{} {
vars := make([]interface{}, 0)
var fromvars []interface{}
@@ -449,34 +511,40 @@ func (tq *SQuery) Variables() []interface{} {
return vars
}
// Distinct of SQuery indicates a distinct query results
func (tq *SQuery) Distinct() *SQuery {
tq.distinct = true
return tq
}
// SubQuery of SQuery generates a SSubQuery from a Query
func (tq *SQuery) SubQuery() *SSubQuery {
sq := SSubQuery{query: tq, alias: getTableAliasName()}
return &sq
}
// Row of SQuery returns an instance of sql.Row for native data fetching
func (tq *SQuery) Row() *sql.Row {
sqlstr := tq.String()
vars := tq.Variables()
if DEBUG_SQLCHEMY {
log.Debugf("SQuery %s with vars: %s", sqlstr, vars)
sqlDebug(sqlstr, vars)
}
return _db.QueryRow(sqlstr, vars...)
}
// Rows of SQuery returns an instance of sql.Rows for native data fetching
func (tq *SQuery) Rows() (*sql.Rows, error) {
sqlstr := tq.String()
vars := tq.Variables()
if DEBUG_SQLCHEMY {
log.Debugf("SQuery %s with vars: %s", sqlstr, vars)
sqlDebug(sqlstr, vars)
}
return _db.Query(sqlstr, vars...)
}
// Count of SQuery returns the count of a query
// use CountWithError instead
// deprecated
func (tq *SQuery) Count() int {
cnt, _ := tq.CountWithError()
@@ -496,6 +564,7 @@ func (tq *SQuery) countQuery() *SQuery {
return cq
}
// CountWithError of SQuery returns the row count of a query
func (tq *SQuery) CountWithError() (int, error) {
cq := tq.countQuery()
count := 0
@@ -507,6 +576,7 @@ func (tq *SQuery) CountWithError() (int, error) {
return -1, err
}
// Field implementation of SQuery for IQuery
func (tq *SQuery) Field(name string) IQueryField {
f := tq.findField(name)
if DEBUG_SQLCHEMY && f == nil {
@@ -562,6 +632,7 @@ func (tq *SQuery) internalFindField(name string) IQueryField {
return nil
}
// IRowScanner is an interface for sql data fetching
type IRowScanner interface {
Scan(desc ...interface{}) error
}
@@ -590,8 +661,8 @@ func rowScan2StringMap(fields []string, row IRowScanner) (map[string]string, err
return results, nil
}
func (q *SQuery) rowScan2StringMap(row IRowScanner) (map[string]string, error) {
queryFields := q.QueryFields()
func (tq *SQuery) rowScan2StringMap(row IRowScanner) (map[string]string, error) {
queryFields := tq.QueryFields()
fields := make([]string, len(queryFields))
for i, f := range queryFields {
fields[i] = f.Name()
@@ -599,19 +670,21 @@ func (q *SQuery) rowScan2StringMap(row IRowScanner) (map[string]string, error) {
return rowScan2StringMap(fields, row)
}
func (q *SQuery) FirstStringMap() (map[string]string, error) {
return q.rowScan2StringMap(q.Row())
// FirstStringMap returns query result of the first row in a stringmap(map[string]string)
func (tq *SQuery) FirstStringMap() (map[string]string, error) {
return tq.rowScan2StringMap(tq.Row())
}
func (q *SQuery) AllStringMap() ([]map[string]string, error) {
rows, err := q.Rows()
// AllStringMap returns query result of all rows in an array of stringmap(map[string]string)
func (tq *SQuery) AllStringMap() ([]map[string]string, error) {
rows, err := tq.Rows()
if err != nil {
return nil, err
}
defer rows.Close()
results := make([]map[string]string, 0)
for rows.Next() {
result, err := q.rowScan2StringMap(rows)
result, err := tq.rowScan2StringMap(rows)
if err != nil {
return nil, err
}
@@ -644,8 +717,9 @@ func callAfterQuery(val reflect.Value) {
}
}
func (q *SQuery) First(dest interface{}) error {
mapResult, err := q.FirstStringMap()
// First return query result of first row and store the result in a data struct
func (tq *SQuery) First(dest interface{}) error {
mapResult, err := tq.FirstStringMap()
if err != nil {
return err
}
@@ -662,7 +736,8 @@ func (q *SQuery) First(dest interface{}) error {
return nil
}
func (q *SQuery) All(dest interface{}) error {
// All return query results of all rows and store the result in an array of data struct
func (tq *SQuery) All(dest interface{}) error {
arrayType := reflect.TypeOf(dest).Elem()
if arrayType.Kind() != reflect.Array && arrayType.Kind() != reflect.Slice {
@@ -670,7 +745,7 @@ func (q *SQuery) All(dest interface{}) error {
}
elemType := arrayType.Elem()
mapResults, err := q.AllStringMap()
mapResults, err := tq.AllStringMap()
if err != nil {
return err
}
@@ -690,11 +765,13 @@ func (q *SQuery) All(dest interface{}) error {
return err
}
func (q *SQuery) Row2Map(row IRowScanner) (map[string]string, error) {
return q.rowScan2StringMap(row)
// Row2Map is a utility function that fetch stringmap(map[string]string) from a native sql.Row or sql.Rows
func (tq *SQuery) Row2Map(row IRowScanner) (map[string]string, error) {
return tq.rowScan2StringMap(row)
}
func (q *SQuery) RowMap2Struct(result map[string]string, dest interface{}) error {
// RowMap2Struct is a utility function that fetch struct from a native sql.Row or sql.Rows
func (tq *SQuery) RowMap2Struct(result map[string]string, dest interface{}) error {
destPtrValue := reflect.ValueOf(dest)
if destPtrValue.Kind() != reflect.Ptr {
return errors.Wrap(ErrNeedsPointer, "input must be a pointer")
@@ -709,22 +786,25 @@ func (q *SQuery) RowMap2Struct(result map[string]string, dest interface{}) error
return nil
}
func (q *SQuery) Row2Struct(row IRowScanner, dest interface{}) error {
result, err := q.rowScan2StringMap(row)
// Row2Struct is a utility function that fill a struct with the value of a sql.Row or sql.Rows
func (tq *SQuery) Row2Struct(row IRowScanner, dest interface{}) error {
result, err := tq.rowScan2StringMap(row)
if err != nil {
return err
}
return q.RowMap2Struct(result, dest)
return tq.RowMap2Struct(result, dest)
}
func (q *SQuery) Snapshot() *SQuery {
q.snapshot = q.String()
return q
// Snapshot of SQuery take a snapshot of the query, so we can tell wether the query is modified later by comparing the SQL with snapshot
func (tq *SQuery) Snapshot() *SQuery {
tq.snapshot = tq.String()
return tq
}
func (q *SQuery) IsAltered() bool {
if len(q.snapshot) == 0 {
panic(fmt.Sprintf("Query %s has never been snapshot when IsAltered called", q.String()))
// IsAltered of SQuery indicates whether a query was altered. By comparing with the saved query snapshot, we can tell whether a query is altered
func (tq *SQuery) IsAltered() bool {
if len(tq.snapshot) == 0 {
panic(fmt.Sprintf("Query %s has never been snapshot when IsAltered called", tq.String()))
}
return q.String() != q.snapshot
return tq.String() != tq.snapshot
}

View File

@@ -14,30 +14,40 @@
package sqlchemy
// SRawQueryField is a struct represents a field of a raw SQL query
// a raw query is a query that not follow standard SELECT ... FROM ... pattern
// e.g. show tables
// the struct implements IQueryField interface
type SRawQueryField struct {
name string
}
// Expression implementation of SRawQueryField for IQueryField
func (rqf *SRawQueryField) Expression() string {
return rqf.name
}
// Name implementation of SRawQueryField for IQueryField
func (rqf *SRawQueryField) Name() string {
return rqf.name
}
// Reference implementation of SRawQueryField for IQueryField
func (rqf *SRawQueryField) Reference() string {
return rqf.name
}
// Label implementation of SRawQueryField for IQueryField
func (rqf *SRawQueryField) Label(label string) IQueryField {
return rqf
}
// Variables implementation of SRawQueryField for IQueryField
func (rqf *SRawQueryField) Variables() []interface{} {
return nil
}
// NewRawQuery returns an instance of SQuery with raw SQL query. e.g. show tables
func NewRawQuery(sqlStr string, fields ...string) *SQuery {
qfs := make([]IQueryField, len(fields))
for i, f := range fields {

View File

@@ -73,9 +73,8 @@ func getStringValue(dat interface{}) string {
case reflect.Bool:
if value.Bool() {
return "true"
} else {
return "false"
}
return "false"
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return fmt.Sprintf("%d", value.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:

6
vendor/yunion.io/x/sqlchemy/sql.go generated vendored
View File

@@ -20,16 +20,20 @@ import (
"yunion.io/x/log"
)
// the global DB connection
var _db *sql.DB
// SetDB sets global DB instance
func SetDB(db *sql.DB) {
_db = db
}
// GetDB get DB instance
func GetDB() *sql.DB {
return _db
}
// CloseDB close DB connection
func CloseDB() {
_db.Close()
_db = nil
@@ -39,6 +43,7 @@ type tableName struct {
Name string
}
// GetTables get all tables' name in database
func GetTables() []string {
tables := make([]tableName, 0)
q := NewRawQuery("SHOW TABLES", "name")
@@ -54,6 +59,7 @@ func GetTables() []string {
return ret
}
// Exec execute a raw SQL query
func Exec(sql string, args ...interface{}) (sql.Result, error) {
return _db.Exec(sql, args...)
}

40
vendor/yunion.io/x/sqlchemy/sync.go generated vendored
View File

@@ -27,7 +27,7 @@ import (
"yunion.io/x/pkg/utils"
)
type SSqlColumnInfo struct {
type sSqlColumnInfo struct {
Field string
Type string
Collation string
@@ -44,13 +44,12 @@ func decodeSqlTypeString(typeStr string) []string {
matches := typeReg.FindStringSubmatch(typeStr)
if len(matches) >= 3 {
return matches[1:]
} else {
}
parts := strings.Split(typeStr, " ")
return []string{parts[0]}
}
}
func (info *SSqlColumnInfo) toColumnSpec() IColumnSpec {
func (info *sSqlColumnInfo) toColumnSpec() IColumnSpec {
tagmap := make(map[string]string)
matches := decodeSqlTypeString(info.Type)
@@ -151,7 +150,7 @@ func (info *SSqlColumnInfo) toColumnSpec() IColumnSpec {
func (ts *STableSpec) fetchColumnDefs() ([]IColumnSpec, error) {
sql := fmt.Sprintf("SHOW FULL COLUMNS IN `%s`", ts.name)
query := NewRawQuery(sql, "field", "type", "collation", "null", "key", "default", "extra", "privileges", "comment")
infos := make([]SSqlColumnInfo, 0)
infos := make([]sSqlColumnInfo, 0)
err := query.All(&infos)
if err != nil {
return nil, err
@@ -163,7 +162,7 @@ func (ts *STableSpec) fetchColumnDefs() ([]IColumnSpec, error) {
return specs, nil
}
func (ts *STableSpec) fetchIndexesAndConstraints() ([]STableIndex, []STableConstraint, error) {
func (ts *STableSpec) fetchIndexesAndConstraints() ([]sTableIndex, []sTableConstraint, error) {
sql := fmt.Sprintf("SHOW CREATE TABLE `%s`", ts.name)
query := NewRawQuery(sql, "table", "create table")
row := query.Row()
@@ -218,31 +217,31 @@ func diffCols(tableName string, cols1 []IColumnSpec, cols2 []IColumnSpec) ([]ICo
newCol: cols2[j],
})
}
i += 1
j += 1
i++
j++
} else if comp > 0 {
add = append(add, cols2[j])
j += 1
j++
} else {
remove = append(remove, cols1[i])
i += 1
i++
}
} else if i < len(cols1) {
remove = append(remove, cols1[i])
i += 1
i++
} else if j < len(cols2) {
add = append(add, cols2[j])
j += 1
j++
}
}
return remove, update, add
}
func diffIndexes2(exists []STableIndex, defs []STableIndex) (diff []STableIndex) {
diff = make([]STableIndex, 0)
for i := 0; i < len(exists); i += 1 {
func diffIndexes2(exists []sTableIndex, defs []sTableIndex) (diff []sTableIndex) {
diff = make([]sTableIndex, 0)
for i := 0; i < len(exists); i++ {
findDef := false
for j := 0; j < len(defs); j += 1 {
for j := 0; j < len(defs); j++ {
if defs[j].IsIdentical(exists[i].columns...) {
findDef = true
break
@@ -255,10 +254,11 @@ func diffIndexes2(exists []STableIndex, defs []STableIndex) (diff []STableIndex)
return
}
func diffIndexes(exists []STableIndex, defs []STableIndex) (added []STableIndex, removed []STableIndex) {
func diffIndexes(exists []sTableIndex, defs []sTableIndex) (added []sTableIndex, removed []sTableIndex) {
return diffIndexes2(defs, exists), diffIndexes2(exists, defs)
}
// DropForeignKeySQL returns the SQL statements to do droping foreignkey for a TableSpec
func (ts *STableSpec) DropForeignKeySQL() []string {
_, constraints, err := ts.fetchIndexesAndConstraints()
if err != nil {
@@ -278,12 +278,15 @@ func (ts *STableSpec) DropForeignKeySQL() []string {
return ret
}
// Exists checks wheter a table exists
func (ts *STableSpec) Exists() bool {
tables := GetTables()
in, _ := utils.InStringArray(ts.name, tables)
return in
}
// SyncSQL returns SQL statements that make table in database consistent with TableSpec definitions
// by comparing table definition derived from TableSpec and that in database
func (ts *STableSpec) SyncSQL() []string {
if !ts.Exists() {
log.Debugf("table %s not created yet", ts.name)
@@ -408,6 +411,8 @@ func (ts *STableSpec) SyncSQL() []string {
return ret
}
// Sync executes the SQLs to synchronize the DB definion of s SQL database
// by applying the SQL statements generated by SyncSQL()
func (ts *STableSpec) Sync() error {
sqls := ts.SyncSQL()
if sqls != nil {
@@ -422,6 +427,7 @@ func (ts *STableSpec) Sync() error {
return nil
}
// CheckSync checks whether the table in database consistent with TableSpec
func (ts *STableSpec) CheckSync() error {
sqls := ts.SyncSQL()
if len(sqls) > 0 {

61
vendor/yunion.io/x/sqlchemy/table.go generated vendored
View File

@@ -23,48 +23,80 @@ import (
"yunion.io/x/pkg/utils"
)
// ITableSpec is the interface represents a table
type ITableSpec interface {
// Insert performs an insert operation that insert one record at a time
Insert(dt interface{}) error
// InsertOrUpdate performs an atomic insert or update operation that insert a new record to update the record with current value
InsertOrUpdate(dt interface{}) error
// Update performs an update operation
Update(dt interface{}, onUpdate func() error) (UpdateDiffs, error)
// Increment performs a special update that do an atomic incremental update of the numeric fields
Increment(diff, target interface{}) error
// Decrement performs a special update that do an atomic decremental update of the numeric fields
Decrement(diff, target interface{}) error
// DataType returns the data type corresponding to the table
DataType() reflect.Type
// ColumnSpec returns the column definition of a spcific column
ColumnSpec(name string) IColumnSpec
// Name returns the name of the table
Name() string
// Columns returns the array of columns definitions
Columns() []IColumnSpec
// PrimaryColumns returns the array of columns of primary keys
PrimaryColumns() []IColumnSpec
// Expression returns expression of the table
Expression() string
// Instance returns an instance of STable for this spec
Instance() *STable
// DropForeignKeySQL returns the SQL statements to drop foreignkeys for this table
DropForeignKeySQL() []string
// AddIndex adds index to table
AddIndex(unique bool, cols ...string) bool
// SyncSQL forces synchronize the data definition and model definition of the table
SyncSQL() []string
// Fetch query a struct
Fetch(dt interface{}) error
}
// STableSpec defines the table specification, which implements ITableSpec
type STableSpec struct {
structType reflect.Type
name string
columns []IColumnSpec
indexes []STableIndex
contraints []STableConstraint
indexes []sTableIndex
contraints []sTableConstraint
}
// STable is an instance of table for query, system will automatically give a alias to this table
type STable struct {
spec ITableSpec
alias string
}
// STableField represents a field in a table, implements IQueryField
type STableField struct {
table *STable
spec IColumnSpec
alias string
}
// NewTableSpecFromStruct generates STableSpec based on the information of a struct model
func NewTableSpecFromStruct(s interface{}, name string) *STableSpec {
val := reflect.Indirect(reflect.ValueOf(s))
st := val.Type()
@@ -80,14 +112,17 @@ func NewTableSpecFromStruct(s interface{}, name string) *STableSpec {
return table
}
// Name implementation of STableSpec for ITableSpec
func (ts *STableSpec) Name() string {
return ts.name
}
// Expression implementation of STableSpec for ITableSpec
func (ts *STableSpec) Expression() string {
return fmt.Sprintf("`%s`", ts.name)
}
// Clone makes a clone of a table, so we may create a new table of the same schema
func (ts *STableSpec) Clone(name string, autoIncOffset int64) *STableSpec {
newCols := make([]IColumnSpec, len(ts.columns))
for i := range newCols {
@@ -109,10 +144,12 @@ func (ts *STableSpec) Clone(name string, autoIncOffset int64) *STableSpec {
}
}
// Columns implementation of STableSpec for ITableSpec
func (ts *STableSpec) Columns() []IColumnSpec {
return ts.columns
}
// PrimaryColumns implementation of STableSpec for ITableSpec
func (ts *STableSpec) PrimaryColumns() []IColumnSpec {
ret := make([]IColumnSpec, 0)
for i := range ts.columns {
@@ -123,10 +160,12 @@ func (ts *STableSpec) PrimaryColumns() []IColumnSpec {
return ret
}
// DataType implementation of STableSpec for ITableSpec
func (ts *STableSpec) DataType() reflect.Type {
return ts.structType
}
// CreateSQL returns the SQL for creating this table
func (ts *STableSpec) CreateSQL() string {
cols := make([]string, 0)
primaries := make([]string, 0)
@@ -153,15 +192,18 @@ func (ts *STableSpec) CreateSQL() string {
return fmt.Sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n%s\n) ENGINE=InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci%s", ts.name, strings.Join(cols, ",\n"), autoInc)
}
// NewTableInstance return an new table instance from an ITableSpec
func NewTableInstance(ts ITableSpec) *STable {
table := STable{spec: ts, alias: getTableAliasName()}
return &table
}
// Instance return an new table instance from an instance of STableSpec
func (ts *STableSpec) Instance() *STable {
return NewTableInstance(ts)
}
// ColumnSpec implementation of STableSpec for ITableSpec
func (ts *STableSpec) ColumnSpec(name string) IColumnSpec {
for _, c := range ts.Columns() {
if c.Name() == name {
@@ -171,6 +213,7 @@ func (ts *STableSpec) ColumnSpec(name string) IColumnSpec {
return nil
}
// Field implementation of STableSpec for IQuerySource
func (tbl *STable) Field(name string, alias ...string) IQueryField {
// name = reflectutils.StructFieldName(name)
name = utils.CamelSplit(name, "_")
@@ -186,6 +229,7 @@ func (tbl *STable) Field(name string, alias ...string) IQueryField {
return &col
}
// Fields implementation of STable for IQuerySource
func (tbl *STable) Fields() []IQueryField {
ret := make([]IQueryField, 0)
for _, c := range tbl.spec.Columns() {
@@ -194,26 +238,28 @@ func (tbl *STable) Fields() []IQueryField {
return ret
}
// Expression implementation of STableField for IQueryField
func (c *STableField) Expression() string {
if len(c.alias) > 0 {
return fmt.Sprintf("%s.%s as `%s`", c.table.Alias(), c.spec.Name(), c.alias)
} else {
return fmt.Sprintf("%s.%s", c.table.Alias(), c.spec.Name())
return fmt.Sprintf("`%s`.`%s` as `%s`", c.table.Alias(), c.spec.Name(), c.alias)
}
return fmt.Sprintf("`%s`.`%s`", c.table.Alias(), c.spec.Name())
}
// Name implementation of STableField for IQueryField
func (c *STableField) Name() string {
if len(c.alias) > 0 {
return c.alias
} else {
return c.spec.Name()
}
return c.spec.Name()
}
// Reference implementation of STableField for IQueryField
func (c *STableField) Reference() string {
return fmt.Sprintf("`%s`.`%s`", c.table.Alias(), c.Name())
}
// Label implementation of STableField for IQueryField
func (c *STableField) Label(label string) IQueryField {
if len(label) > 0 && label != c.spec.Name() {
c.alias = label
@@ -221,6 +267,7 @@ func (c *STableField) Label(label string) IQueryField {
return c
}
// Variables implementation of STableField for IQueryField
func (c *STableField) Variables() []interface{} {
return nil
}

View File

@@ -27,6 +27,6 @@ var (
func getTableAliasName() string {
tableIDLock.Lock()
defer tableIDLock.Unlock()
tableID += 1
tableID++
return fmt.Sprintf("t%d", tableID)
}

49
vendor/yunion.io/x/sqlchemy/union.go generated vendored
View File

@@ -23,28 +23,35 @@ import (
"yunion.io/x/pkg/errors"
)
// SUnionQueryField represents a field of a union query
type SUnionQueryField struct {
union *SUnion
name string
alias string
}
// Expression implementation of SUnionQueryField for IQueryField
func (sqf *SUnionQueryField) Expression() string {
return sqf.name
}
func (sqf *SUnionQueryField) Name() string {
if len(sqf.alias) > 0 {
return sqf.alias
} else {
return sqf.name
return fmt.Sprintf("`%s`.`%s` as `%s`", sqf.union.Alias(), sqf.name, sqf.alias)
}
}
func (sqf *SUnionQueryField) Reference() string {
return fmt.Sprintf("`%s`.`%s`", sqf.union.Alias(), sqf.name)
}
// Name implementation of SUnionQueryField for IQueryField
func (sqf *SUnionQueryField) Name() string {
if len(sqf.alias) > 0 {
return sqf.alias
}
return sqf.name
}
// Reference implementation of SUnionQueryField for IQueryField
func (sqf *SUnionQueryField) Reference() string {
return fmt.Sprintf("`%s`.`%s`", sqf.union.Alias(), sqf.Name())
}
// Label implementation of SUnionQueryField for IQueryField
func (sqf *SUnionQueryField) Label(label string) IQueryField {
if len(label) > 0 && label != sqf.name {
sqf.alias = label
@@ -52,23 +59,27 @@ func (sqf *SUnionQueryField) Label(label string) IQueryField {
return sqf
}
// Variables implementation of SUnionQueryField for IQueryField
func (sqf *SUnionQueryField) Variables() []interface{} {
return nil
}
// SUnion is the struct to store state of a Union query, which implementation the interface of IQuerySource
type SUnion struct {
alias string
queries []IQuery
fields []IQueryField
orderBy []SQueryOrder
orderBy []sQueryOrder
limit int
offset int
}
// Alias implementation of SUnion for IQuerySource
func (uq *SUnion) Alias() string {
return uq.alias
}
// Expression implementation of SUnion for IQuerySource
func (uq *SUnion) Expression() string {
var buf strings.Builder
buf.WriteByte('(')
@@ -118,20 +129,24 @@ func (tq *SUnion) Desc(fields ...interface{}) *SUnion {
}
*/
// Limit adds limit to a union query
func (uq *SUnion) Limit(limit int) *SUnion {
uq.limit = limit
return uq
}
// Offset adds offset to a union query
func (uq *SUnion) Offset(offset int) *SUnion {
uq.offset = offset
return uq
}
// Fields implementation of SUnion for IQuerySource
func (uq *SUnion) Fields() []IQueryField {
return uq.fields
}
// Field implementation of SUnion for IQuerySource
func (uq *SUnion) Field(name string, alias ...string) IQueryField {
for i := range uq.fields {
if name == uq.fields[i].Name() {
@@ -144,6 +159,7 @@ func (uq *SUnion) Field(name string, alias ...string) IQueryField {
return nil
}
// Variables implementation of SUnion for IQuerySource
func (uq *SUnion) Variables() []interface{} {
ret := make([]interface{}, 0)
for i := range uq.queries {
@@ -152,6 +168,8 @@ func (uq *SUnion) Variables() []interface{} {
return ret
}
// Union method returns union query of several queries.
// Require the fields of all queries should exactly match
// deprecated
func Union(query ...IQuery) *SUnion {
u, err := UnionWithError(query...)
@@ -161,6 +179,8 @@ func Union(query ...IQuery) *SUnion {
return u
}
// UnionWithError constructs union query of several Queries
// Require the fields of all queries should exactly match
func UnionWithError(query ...IQuery) (*SUnion, error) {
if len(query) == 0 {
return nil, errors.Wrap(sql.ErrNoRows, "empty union query")
@@ -171,14 +191,14 @@ func UnionWithError(query ...IQuery) (*SUnion, error) {
fieldNames = append(fieldNames, f.Name())
}
for i := 1; i < len(query); i += 1 {
for i := 1; i < len(query); i++ {
qfields := query[i].QueryFields()
if len(fieldNames) != len(qfields) {
return nil, fmt.Errorf("cannot union, number of fields not match!")
return nil, errors.Wrap(ErrUnionFieldsNotMatch, "number not match")
}
for i := range qfields {
if fieldNames[i] != qfields[i].Name() {
return nil, fmt.Errorf("cannot union, name of fields not match!")
return nil, errors.Wrapf(ErrUnionFieldsNotMatch, "name %s:%s not match", fieldNames[i], qfields[i].Name())
}
}
}
@@ -198,6 +218,7 @@ func UnionWithError(query ...IQuery) (*SUnion, error) {
return uq, nil
}
// Query of SUnion returns a SQuery of a union query
func (uq *SUnion) Query(f ...IQueryField) *SQuery {
return DoQuery(uq, f...)
}

View File

@@ -28,6 +28,7 @@ import (
"yunion.io/x/pkg/utils"
)
// SUpdateSession is a struct to store the state of a update session
type SUpdateSession struct {
oValue reflect.Value
tableSpec *STableSpec
@@ -62,12 +63,14 @@ func (ts *STableSpec) prepareUpdate(dt interface{}) (*SUpdateSession, error) {
return &us, nil
}
// SUpdateDiff is a struct to store the differences for an update of a column
type SUpdateDiff struct {
old interface{}
new interface{}
col IColumnSpec
}
// String of SUpdateDiff returns the string representation of a SUpdateDiff
func (ud *SUpdateDiff) String() string {
return fmt.Sprintf("%s->%s",
utils.TruncateString(ud.old, 32),
@@ -81,8 +84,10 @@ func (ud SUpdateDiff) jsonObj() jsonutils.JSONObject {
return r
}
// UpdateDiffs is a map of SUpdateDiff whose key is the column name
type UpdateDiffs map[string]SUpdateDiff
// String of UpdateDiffs returns the string representation of UpdateDiffs
func (uds UpdateDiffs) String() string {
obj := jsonutils.NewDict()
for k := range uds {
@@ -206,6 +211,9 @@ func (us *SUpdateSession) saveUpdate(dt interface{}) (UpdateDiffs, error) {
return setters, nil
}
// Update method of STableSpec updates a record of a table,
// dt is the point to the struct storing the record
// doUpdate provides method to update the field of the record
func (ts *STableSpec) Update(dt interface{}, doUpdate func() error) (UpdateDiffs, error) {
session, err := ts.prepareUpdate(dt)
if err != nil {