v / vlib / db / pg / pg_test.v
164 lines · 137 sloc · 4.22 KB · 2b04a6ecbf16697b4a6ae2e1e02d3a381967e8f0
Raw
1// vtest build: started_postgres?
2module main
3
4import db.pg
5import orm
6
7fn test_large_exec() {
8 $if !network ? {
9 eprintln('> Skipping test ${@FN}, since `-d network` is not passed.')
10 eprintln('> This test requires a working postgres server running on localhost.')
11 return
12 }
13
14 mut db := pg.connect(pg.Config{ user: 'postgres', password: '12345678', dbname: 'postgres' })!
15 defer {
16 db.close() or {}
17 }
18
19 assert db.validate()!
20
21 rows := db.exec('
22SELECT ischema.table_schema, c.relname, a.attname, t.typname, t.typalign, t.typlen
23 FROM pg_class c
24 JOIN information_schema.tables ischema on ischema.table_name = c.relname
25 JOIN pg_attribute a ON (a.attrelid = c.oid)
26 JOIN pg_type t ON (t.oid = a.atttypid)
27WHERE
28 a.attnum >= 0
29 ')!
30 for row in rows {
31 // We just need to access the memory to ensure it's properly allocated
32 row.str()
33 }
34}
35
36fn test_prepared() {
37 $if !network ? {
38 eprintln('> Skipping test ${@FN}, since `-d network` is not passed.')
39 eprintln('> This test requires a working postgres server running on localhost.')
40 return
41 }
42 mut db := pg.connect(pg.Config{ user: 'postgres', password: '12345678', dbname: 'postgres' })!
43 defer {
44 db.close() or {}
45 }
46
47 // Prepared statements are session-scoped, so pin a single conn.
48 mut c := db.conn()!
49 defer {
50 c.close() or {}
51 }
52 c.prepare('test_prepared', 'SELECT NOW(), $1 AS NAME', 1) or { panic(err) }
53
54 result := c.exec_prepared('test_prepared', ['hello world']) or { panic(err) }
55
56 assert result.len == 1
57}
58
59fn test_transaction() {
60 $if !network ? {
61 eprintln('> Skipping test ${@FN}, since `-d network` is not passed.')
62 eprintln('> This test requires a working postgres server running on localhost.')
63 return
64 }
65
66 mut db := pg.connect(pg.Config{ user: 'postgres', password: '12345678', dbname: 'postgres' })!
67 defer {
68 db.close() or {}
69 }
70 db.exec('drop table if exists users')!
71 db.exec('create table if not exists users (
72 id SERIAL PRIMARY KEY,
73 username TEXT,
74 last_name TEXT NULL DEFAULT NULL
75 )')!
76
77 // orm.TransactionalConnection requires a pinned conn (DB is pool-backed
78 // and cannot guarantee BEGIN/COMMIT land on the same physical conn).
79 mut c := db.conn()!
80 mut tc := orm.TransactionalConnection(c)
81 mut otx := orm.begin(mut tc)!
82 otx.transaction[int](fn (mut tx orm.Tx) !int {
83 return 1
84 })!
85 otx.commit()!
86 c.close()!
87
88 mut tx := db.begin()!
89 tx.exec("insert into users (username) values ('jackson')")!
90 tx.savepoint('savepoint1')!
91 tx.exec("insert into users (username) values ('kitty')")!
92 tx.rollback_to('savepoint1')!
93 tx.exec("insert into users (username) values ('mars')")!
94 tx.commit()!
95
96 rows := db.exec('select * from users')!
97 for row in rows {
98 // We just need to access the memory to ensure it's properly allocated
99 dump(row.str())
100 }
101}
102
103fn test_listen_notify() {
104 $if !network ? {
105 eprintln('> Skipping test ${@FN}, since `-d network` is not passed.')
106 eprintln('> This test requires a working postgres server running on localhost.')
107 return
108 }
109
110 mut db := pg.connect(pg.Config{ user: 'postgres', password: '12345678', dbname: 'postgres' })!
111 defer {
112 db.close() or {}
113 }
114
115 // LISTEN/NOTIFY is session-scoped; pin a single conn for the test.
116 mut c := db.conn()!
117 defer {
118 c.close() or {}
119 }
120
121 // Test listen
122 c.listen('test_channel')!
123
124 // Test notify with payload
125 c.notify('test_channel', 'hello world')!
126
127 // Consume input to process the notification
128 c.consume_input()!
129
130 // Get the notification
131 if notification := c.get_notification() {
132 assert notification.channel == 'test_channel'
133 assert notification.payload == 'hello world'
134 assert notification.pid > 0
135 } else {
136 assert false, 'Expected a notification but got none'
137 }
138
139 // Test notify without payload
140 c.notify('test_channel', '')!
141 c.consume_input()!
142
143 if notification := c.get_notification() {
144 assert notification.channel == 'test_channel'
145 assert notification.payload == ''
146 } else {
147 assert false, 'Expected a notification but got none'
148 }
149
150 // Test that no more notifications are pending
151 assert c.get_notification() == none
152
153 // Test unlisten
154 c.unlisten('test_channel')!
155
156 // Test unlisten_all
157 c.listen('channel1')!
158 c.listen('channel2')!
159 c.unlisten_all()!
160
161 // Test socket (should return valid fd)
162 socket_fd := c.socket()
163 assert socket_fd >= 0
164}
165