Skip to content

Commit 0443534

Browse files
committed
Copy docs/snippets/ to assets/svelte/mdx
1 parent 34eb8f9 commit 0443534

File tree

5 files changed

+132
-139
lines changed

5 files changed

+132
-139
lines changed

Dockerfile

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,8 @@ COPY lib lib
6565

6666
COPY assets assets
6767

68-
# Copy shared MDX files to both svelte and snippets directories
69-
COPY shared_mdx/*.mdx assets/svelte/mdx/
70-
COPY shared_mdx/*.mdx docs/snippets/
68+
# Copy MDX snippets from docs to assets for CopyForChatGPT button
69+
COPY docs/snippets/function-transform-snippet.mdx assets/svelte/mdx/function-transform-snippet.mdx
7170

7271
# install all npm packages in assets directory
7372
WORKDIR /app/assets
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
../../../shared_mdx/function-transform-snippet.mdx
1+
../../../docs/snippets/function-transform-snippet.mdx

docs/snippets/function-transform-snippet.mdx

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
## Function transform
2+
3+
Function transforms allow you to write custom [Elixir](https://elixir-lang.org/) code to transform your messages. This is useful for more complex transformations that are not possible with the path transform, such as:
4+
5+
- Specifying a format that is necessary for your sink destination
6+
- Sanitizing sensitive data, such as PII or payment card data
7+
- Converting timestamp formats
8+
- Adding computed fields
9+
- And much more!
10+
11+
### Function syntax
12+
13+
Every function transform is implemented as an Elixir `transform/4` function:
14+
15+
```Elixir
16+
def transform(action, record, changes, metadata) do
17+
# Your transform here
18+
end
19+
```
20+
21+
The `transform/4` function receives each key from the [message object](/reference/messages) as an argument:
22+
23+
- `record`: The full record object
24+
- `changes`: The changes object
25+
- `action`: The action type (insert, update, delete)
26+
- `metadata`: The metadata object
27+
28+
<Info>
29+
Your transform must define the `transform/4` function and may not define any other functions.
30+
</Info>
31+
32+
### Elixir standard library
33+
34+
The function transform allows you to use a subset of the Elixir standard library, including:
35+
36+
- [String](https://hexdocs.pm/elixir/String.html)
37+
- [Map](https://hexdocs.pm/elixir/Map.html)
38+
- [Enum](https://hexdocs.pm/elixir/Enum.html)
39+
- [Date](https://hexdocs.pm/elixir/Date.html), [DateTime](https://hexdocs.pm/elixir/DateTime.html), and [NaiveDateTime](https://hexdocs.pm/elixir/NaiveDateTime.html)
40+
- [Kernel](https://hexdocs.pm/elixir/Kernel.html)
41+
- [Decimal](https://hexdocs.pm/decimal/readme.html)
42+
- [URI](https://hexdocs.pm/elixir/URI.html)
43+
44+
Other parts of the Elixir standard library are not yet supported. If you need something specific, please [let us know](https://github.com/sequinstream/sequin/issues/new/choose)
45+
and we will be happy to help.
46+
47+
### Examples
48+
49+
Here are some examples of how to use the function transform:
50+
51+
#### Extract the record ID
52+
53+
```Elixir
54+
def transform(action, record, changes, metadata) do
55+
record["id"]
56+
end
57+
```
58+
59+
#### Format for webhook
60+
61+
```Elixir
62+
# Format the record for ElastiCache with a specific key structure
63+
def transform(action, record, changes, metadata) do
64+
record_id = record["id"]
65+
66+
%{
67+
key: "#{metadata.table_schema}.#{metadata.table_name}.#{record_id}",
68+
value: record,
69+
ttl: 3600 # 1 hour TTL
70+
}
71+
end
72+
```
73+
74+
<Note>
75+
Both `record` and `changes` use string keys for access (ie. `record["id"]`).
76+
77+
In contrast, the `metadata` object uses atom keys (ie. `metadata.table_schema`).
78+
79+
This is because the `record` and `changes` objects are dynamically typed- they depend on the schema of the connected Postgres table. Metadata, on the other hand, is statically typed and will always have the same keys.
80+
81+
See the [Elixir Map docs](https://hexdocs.pm/elixir/1.12/Map.html) for more information on the difference between string and atom keys.
82+
</Note>
83+
84+
#### Sanitize sensitive data
85+
86+
```Elixir
87+
# Remove or mask sensitive fields
88+
def transform(action, record, changes, metadata) do
89+
record
90+
|> Map.drop(["password", "credit_card", "ssn"])
91+
|> Map.update!("email", fn email ->
92+
[name, domain] = String.split(email, "@")
93+
masked_name = String.slice(name, 0, 2) <> String.duplicate("*", String.length(name) - 2)
94+
masked_name <> "@" <> domain
95+
end)
96+
end
97+
```
98+
99+
#### Add computed property
100+
101+
```Elixir
102+
# Add a computed full name field
103+
def transform(action, record, changes, metadata) do
104+
first_name = record["first_name"]
105+
last_name = record["last_name"]
106+
full_name = first_name <> " " <> last_name
107+
name_length = String.length(full_name)
108+
109+
%{
110+
full_name: full_name,
111+
name_length: name_length
112+
}
113+
end
114+
```
115+
116+
#### Convert timestamp formats
117+
118+
```Elixir
119+
# Convert timestamp formats
120+
def transform(action, record, changes, metadata) do
121+
timestamp = record["timestamp"]
122+
123+
%{
124+
unix_timestamp: DateTime.to_unix(timestamp),
125+
truncated_timestamp: DateTime.truncate(timestamp, :second),
126+
iso8601_timestamp: DateTime.to_iso8601(timestamp)
127+
}
128+
end
129+
```

shared_mdx/README.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

shared_mdx/function-transform-snippet.mdx

Lines changed: 0 additions & 129 deletions
This file was deleted.

0 commit comments

Comments
 (0)