udt_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // +build all integration
  2. package gocql
  3. import (
  4. "fmt"
  5. "strings"
  6. "testing"
  7. )
  8. type position struct {
  9. Lat int `cql:"lat"`
  10. Lon int `cql:"lon"`
  11. Padding string `json:"padding"`
  12. }
  13. // NOTE: due to current implementation details it is not currently possible to use
  14. // a pointer receiver type for the UDTMarshaler interface to handle UDT's
  15. func (p position) MarshalUDT(name string, info TypeInfo) ([]byte, error) {
  16. switch name {
  17. case "lat":
  18. return Marshal(info, p.Lat)
  19. case "lon":
  20. return Marshal(info, p.Lon)
  21. case "padding":
  22. return Marshal(info, p.Padding)
  23. default:
  24. return nil, fmt.Errorf("unknown column for position: %q", name)
  25. }
  26. }
  27. func (p *position) UnmarshalUDT(name string, info TypeInfo, data []byte) error {
  28. switch name {
  29. case "lat":
  30. return Unmarshal(info, data, &p.Lat)
  31. case "lon":
  32. return Unmarshal(info, data, &p.Lon)
  33. case "padding":
  34. return Unmarshal(info, data, &p.Padding)
  35. default:
  36. return fmt.Errorf("unknown column for position: %q", name)
  37. }
  38. }
  39. func TestUDT_Marshaler(t *testing.T) {
  40. if *flagProto < protoVersion3 {
  41. t.Skip("UDT are only available on protocol >= 3")
  42. }
  43. session := createSession(t)
  44. defer session.Close()
  45. err := createTable(session, `CREATE TYPE position(
  46. lat int,
  47. lon int,
  48. padding text);`)
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. err = createTable(session, `CREATE TABLE houses(
  53. id int,
  54. name text,
  55. loc frozen<position>,
  56. primary key(id)
  57. );`)
  58. if err != nil {
  59. t.Fatal(err)
  60. }
  61. const (
  62. expLat = -1
  63. expLon = 2
  64. )
  65. pad := strings.Repeat("X", 1000)
  66. err = session.Query("INSERT INTO houses(id, name, loc) VALUES(?, ?, ?)", 1, "test", &position{expLat, expLon, pad}).Exec()
  67. if err != nil {
  68. t.Fatal(err)
  69. }
  70. pos := &position{}
  71. err = session.Query("SELECT loc FROM houses WHERE id = ?", 1).Scan(pos)
  72. if err != nil {
  73. t.Fatal(err)
  74. }
  75. if pos.Lat != expLat {
  76. t.Errorf("expeceted lat to be be %d got %d", expLat, pos.Lat)
  77. }
  78. if pos.Lon != expLon {
  79. t.Errorf("expeceted lon to be be %d got %d", expLon, pos.Lon)
  80. }
  81. if pos.Padding != pad {
  82. t.Errorf("expected to get padding %q got %q\n", pad, pos.Padding)
  83. }
  84. }
  85. func TestUDT_Reflect(t *testing.T) {
  86. if *flagProto < protoVersion3 {
  87. t.Skip("UDT are only available on protocol >= 3")
  88. }
  89. // Uses reflection instead of implementing the marshaling type
  90. session := createSession(t)
  91. defer session.Close()
  92. err := createTable(session, `CREATE TYPE horse(
  93. name text,
  94. owner text);`)
  95. if err != nil {
  96. t.Fatal(err)
  97. }
  98. err = createTable(session, `CREATE TABLE horse_race(
  99. position int,
  100. horse frozen<horse>,
  101. primary key(position)
  102. );`)
  103. if err != nil {
  104. t.Fatal(err)
  105. }
  106. type horse struct {
  107. Name string `cql:"name"`
  108. Owner string `cql:"owner"`
  109. }
  110. insertedHorse := &horse{
  111. Name: "pony",
  112. Owner: "jim",
  113. }
  114. err = session.Query("INSERT INTO horse_race(position, horse) VALUES(?, ?)", 1, insertedHorse).Exec()
  115. if err != nil {
  116. t.Fatal(err)
  117. }
  118. retrievedHorse := &horse{}
  119. err = session.Query("SELECT horse FROM horse_race WHERE position = ?", 1).Scan(retrievedHorse)
  120. if err != nil {
  121. t.Fatal(err)
  122. }
  123. if *retrievedHorse != *insertedHorse {
  124. t.Fatal("exepcted to get %+v got %+v", insertedHorse, retrievedHorse)
  125. }
  126. }
  127. func TestUDT_Proto2error(t *testing.T) {
  128. if *flagProto < protoVersion3 {
  129. t.Skip("UDT are only available on protocol >= 3")
  130. }
  131. cluster := createCluster()
  132. cluster.ProtoVersion = 2
  133. cluster.Keyspace = "gocql_test"
  134. // Uses reflection instead of implementing the marshaling type
  135. session, err := cluster.CreateSession()
  136. if err != nil {
  137. t.Fatal(err)
  138. }
  139. defer session.Close()
  140. err = createTable(session, `CREATE TYPE fish(
  141. name text,
  142. owner text);`)
  143. if err != nil {
  144. t.Fatal(err)
  145. }
  146. err = createTable(session, `CREATE TABLE fish_race(
  147. position int,
  148. fish frozen<fish>,
  149. primary key(position)
  150. );`)
  151. if err != nil {
  152. t.Fatal(err)
  153. }
  154. type fish struct {
  155. Name string `cql:"name"`
  156. Owner string `cql:"owner"`
  157. }
  158. insertedFish := &fish{
  159. Name: "pony",
  160. Owner: "jim",
  161. }
  162. err = session.Query("INSERT INTO fish_race(position, fish) VALUES(?, ?)", 1, insertedFish).Exec()
  163. if err != ErrorUDTUnavailable {
  164. t.Fatalf("expected to get %v got %v", ErrorUDTUnavailable, err)
  165. }
  166. }
  167. func TestUDT_NullObject(t *testing.T) {
  168. if *flagProto < protoVersion3 {
  169. t.Skip("UDT are only available on protocol >= 3")
  170. }
  171. session := createSession(t)
  172. defer session.Close()
  173. err := createTable(session, `CREATE TYPE udt_null_type(
  174. name text,
  175. owner text);`)
  176. if err != nil {
  177. t.Fatal(err)
  178. }
  179. err = createTable(session, `CREATE TABLE udt_null_table(
  180. id uuid,
  181. udt_col frozen<udt_null_type>,
  182. primary key(id)
  183. );`)
  184. if err != nil {
  185. t.Fatal(err)
  186. }
  187. type col struct {
  188. Name string `cql:"name"`
  189. Owner string `cql:"owner"`
  190. }
  191. id := TimeUUID()
  192. err = session.Query("INSERT INTO udt_null_table(id) VALUES(?)", id).Exec()
  193. if err != nil {
  194. t.Fatal(err)
  195. }
  196. readCol := &col{
  197. Name: "temp",
  198. Owner: "temp",
  199. }
  200. err = session.Query("SELECT udt_col FROM udt_null_table WHERE id = ?", id).Scan(readCol)
  201. if err != nil {
  202. t.Fatal(err)
  203. }
  204. if readCol.Name != "" {
  205. t.Errorf("expected empty string to be returned for null udt: got %q", readCol.Name)
  206. }
  207. if readCol.Owner != "" {
  208. t.Errorf("expected empty string to be returned for null udt: got %q", readCol.Owner)
  209. }
  210. }