You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`skunk.data.Identifier` represents a Postgres SQL identifier — the name of a table, column, schema, channel, etc. Skunk validates identifiers up front so they can be safely spliced into SQL without risking injection.
8
+
9
+
Postgres recognises two flavours of identifier, and `Identifier` supports both.
10
+
11
+
## Unquoted identifiers
12
+
13
+
An *unquoted* identifier matches `[A-Za-z_][A-Za-z_0-9$]*`, is at most 63 characters, and is not a reserved keyword. Postgres folds unquoted identifiers to lower case, so `FOO`, `Foo`, and `foo` all refer to the same object.
14
+
15
+
Construct one with `Identifier.fromString` or the `id"…"` interpolator:
The `id"…"` form validates at compile time and fails the build for malformed input.
23
+
24
+
## Quoted (delimited) identifiers
25
+
26
+
A *quoted* (delimited) identifier is any non-empty character sequence that does not contain the NUL byte. Quoting preserves case and lets you use characters or reserved words that an unquoted identifier cannot.
27
+
28
+
Construct one with `Identifier.fromStringQuoted` or the `qid"…"` interpolator:
29
+
30
+
```scala mdoc:compile-only
31
+
vala:Either[String, Identifier] =Identifier.fromStringQuoted("MyTable") // case preserved
Like `id"…"`, the `qid"…"` form validates at compile time and fails the build for malformed input (empty string, embedded space, or > 63 bytes).
36
+
37
+
Length is checked in **bytes** (Postgres' `NAMEDATALEN-1` is byte-counted), so multibyte characters are accounted for correctly.
38
+
39
+
## Rendering as SQL
40
+
41
+
`Identifier#asSql` returns the SQL-ready form: the bare value for unquoted identifiers, or the value wrapped in double quotes (with any embedded `"` doubled) for quoted ones. `toString` returns `asSql`, so logged identifiers show their SQL-correct form. `value` always returns the bare, unescaped name.
42
+
43
+
```scala mdoc:compile-only
44
+
valunq=id"my_table"
45
+
valunqRendered= unq.asSql // "my_table"
46
+
47
+
valq=qid"My.Channel"
48
+
valqBare= q.value // "My.Channel"
49
+
valqRendered= q.asSql // "\"My.Channel\""
50
+
```
51
+
52
+
`Channel` uses `asSql` internally when issuing `LISTEN`/`UNLISTEN`/`NOTIFY`, so quoted channel names round-trip correctly.
Copy file name to clipboardExpand all lines: modules/docs/src/main/laika/tutorial/Channels.md
+9Lines changed: 9 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,6 +27,15 @@ Observe the following:
27
27
-`ch` is a `Channel` which consumes `String`s and emits `Notification[String]`s. A notification is a structure that includes the process ID and channel identifier as well as the payload.
28
28
-`Channel` is a profunctor and thus can be contramapped to change the input type, and mapped to change the output type.
29
29
30
+
If the channel name contains characters that are not valid in an unquoted identifier, use the `qid"…"` interpolator (or `Identifier.fromStringQuoted`) to build a quoted identifier:
31
+
32
+
```scala mdoc:compile-only
33
+
// assume s: Session[IO]
34
+
valch= s.channel(qid"q_my_queue.INSERT")
35
+
```
36
+
37
+
The resulting `LISTEN`/`UNLISTEN`/`NOTIFY` statements wrap the name in double quotes so Postgres parses it correctly.
38
+
30
39
## Listening to a Channel
31
40
32
41
To listen on a channel, construct a stream via `.listen`.
0 commit comments