-
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcrud-example.pony
More file actions
161 lines (148 loc) · 5.22 KB
/
crud-example.pony
File metadata and controls
161 lines (148 loc) · 5.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use "cli"
use "collections"
use lori = "lori"
// in your code this `use` statement would be:
// use "postgres"
use "../../postgres"
actor Main
new create(env: Env) =>
let server_info = ServerInfo(env.vars)
let auth = lori.TCPConnectAuth(env.root)
let client = Client(auth, server_info, env.out)
// This example packs all the queries into a single actor using a _phase
// counter to sequence them. This keeps the example self-contained, but it's
// not how you'd structure a real application. Normally your application has
// its own state machine and issues queries as needed from different parts of
// your code rather than cramming everything into one client.
actor Client is (SessionStatusNotify & ResultReceiver)
let _session: Session
let _out: OutStream
var _phase: USize = 0
new create(auth: lori.TCPConnectAuth, info: ServerInfo, out: OutStream) =>
_out = out
_session = Session(
ServerConnectInfo(auth, info.host, info.port),
DatabaseConnectInfo(info.username, info.password, info.database),
this)
be close() =>
_session.close()
be pg_session_authenticated(session: Session) =>
_out.print("Authenticated.")
// Drop the table first in case a previous run was interrupted.
_phase = 0
session.execute(
SimpleQuery("DROP TABLE IF EXISTS crud_example"), this)
be pg_session_authentication_failed(
s: Session,
reason: AuthenticationFailureReason)
=>
_out.print("Failed to authenticate.")
be pg_query_result(session: Session, result: Result) =>
_phase = _phase + 1
match \exhaustive\ _phase
| 1 =>
// Table dropped (or didn't exist). Create it.
_out.print("Creating table...")
_session.execute(
SimpleQuery(
"""
CREATE TABLE crud_example (
name VARCHAR(50) NOT NULL,
age INT NOT NULL
)
"""),
this)
| 2 =>
// Table created (SimpleResult). Insert first row with PreparedQuery.
_out.print("Table created.")
_out.print("Inserting rows...")
_session.execute(
PreparedQuery(
"INSERT INTO crud_example (name, age) VALUES ($1, $2)",
recover val [as (String | None): "Alice"; "30"] end),
this)
| 3 =>
// First insert done. Show impacted count and insert second row.
_print_row_modifying(result)
_session.execute(
PreparedQuery(
"INSERT INTO crud_example (name, age) VALUES ($1, $2)",
recover val [as (String | None): "Bob"; "25"] end),
this)
| 4 =>
// Second insert done. Select all rows.
_print_row_modifying(result)
_out.print("Selecting rows...")
_session.execute(
PreparedQuery(
"SELECT name, age FROM crud_example WHERE age >= $1 ORDER BY name",
recover val [as (String | None): "0"] end),
this)
| 5 =>
// Select done. Print results and delete all rows.
match \exhaustive\ result
| let r: ResultSet =>
_out.print("ResultSet (" + r.rows().size().string() + " rows):")
for row in r.rows().values() do
_out.write(" ")
for field in row.fields.values() do
_out.write(" " + field.name + "=")
match \exhaustive\ field.value
| let v: String => _out.write(v)
| let v: I16 => _out.write(v.string())
| let v: I32 => _out.write(v.string())
| let v: I64 => _out.write(v.string())
| let v: F32 => _out.write(v.string())
| let v: F64 => _out.write(v.string())
| let v: Bool => _out.write(v.string())
| let v: Array[U8] val =>
_out.write(v.size().string() + " bytes")
| None => _out.write("NULL")
end
end
_out.print("")
end
end
_out.print("Deleting rows...")
_session.execute(
SimpleQuery("DELETE FROM crud_example"), this)
| 6 =>
// Delete done. Show count and drop table.
_print_row_modifying(result)
_out.print("Dropping table...")
_session.execute(
SimpleQuery("DROP TABLE crud_example"), this)
| 7 =>
// Table dropped. Done.
_out.print("Done.")
close()
end
fun _print_row_modifying(result: Result) =>
match \exhaustive\ result
| let r: RowModifying =>
_out.print(r.command() + " " + r.impacted().string() + " rows")
end
be pg_query_failed(session: Session, query: Query,
failure: (ErrorResponseMessage | ClientQueryError))
=>
match \exhaustive\ failure
| let e: ErrorResponseMessage =>
_out.print("Query failed: [" + e.severity + "] " + e.code + ": "
+ e.message)
| let e: ClientQueryError =>
_out.print("Query failed: client error")
end
close()
class val ServerInfo
let host: String
let port: String
let username: String
let password: String
let database: String
new val create(vars: (Array[String] val | None)) =>
let e = EnvVars(vars)
host = try e("POSTGRES_HOST")? else "127.0.0.1" end
port = try e("POSTGRES_PORT")? else "5432" end
username = try e("POSTGRES_USERNAME")? else "postgres" end
password = try e("POSTGRES_PASSWORD")? else "postgres" end
database = try e("POSTGRES_DATABASE")? else "postgres" end