@walkeros/server-destination-clickhouse 0.0.0-bootstrap
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/dev.d.mts +133 -0
- package/dist/dev.d.ts +133 -0
- package/dist/dev.js +1 -0
- package/dist/dev.js.map +1 -0
- package/dist/dev.mjs +1 -0
- package/dist/dev.mjs.map +1 -0
- package/dist/examples/index.d.mts +91 -0
- package/dist/examples/index.d.ts +91 -0
- package/dist/examples/index.js +279 -0
- package/dist/examples/index.mjs +269 -0
- package/dist/index.d.mts +138 -0
- package/dist/index.d.ts +138 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -0
- package/dist/walkerOS.json +379 -0
- package/package.json +73 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { DestinationServer } from '@walkeros/server-core';
|
|
2
|
+
import { ClickHouseClientConfigOptions, ClickHouseClient } from '@clickhouse/client';
|
|
3
|
+
import { Flow } from '@walkeros/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The only two client methods this package is allowed to reach for. Narrowing
|
|
7
|
+
* the seam to them makes the INSERT-only rule a compile-time property rather
|
|
8
|
+
* than a convention: `query`, `command`, `exec` and `ping` are not reachable
|
|
9
|
+
* from a client typed this way, so no code path can read `system.*` or issue
|
|
10
|
+
* DDL. The SDK's own `createClient` stays assignable by structural typing.
|
|
11
|
+
*/
|
|
12
|
+
type ClickHouseClientSurface = Pick<ClickHouseClient, 'insert' | 'close'>;
|
|
13
|
+
/** Creates the client this destination writes through. Matches `createClient`. */
|
|
14
|
+
type ClickHouseClientFactory = (config: ClickHouseClientConfigOptions) => ClickHouseClientSurface;
|
|
15
|
+
/**
|
|
16
|
+
* Env carries the client factory so tests and simulations inject a recording
|
|
17
|
+
* stand-in instead of opening a socket. Production leaves it undefined and the
|
|
18
|
+
* destination uses the SDK's own `createClient`.
|
|
19
|
+
*/
|
|
20
|
+
interface Env extends DestinationServer.Env {
|
|
21
|
+
ClickHouseClient?: ClickHouseClientFactory;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Example environment for the ClickHouse destination.
|
|
26
|
+
*
|
|
27
|
+
* The client factory is the recording stand-in from the package-local
|
|
28
|
+
* __mocks__ folder, so examples, tests and simulations share one source of
|
|
29
|
+
* truth and never reach a ClickHouse server.
|
|
30
|
+
*/
|
|
31
|
+
declare const push: Env;
|
|
32
|
+
declare const simulation: string[];
|
|
33
|
+
|
|
34
|
+
declare const env_push: typeof push;
|
|
35
|
+
declare const env_simulation: typeof simulation;
|
|
36
|
+
declare namespace env {
|
|
37
|
+
export { env_push as push, env_simulation as simulation };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Destination bootstrap.
|
|
42
|
+
*
|
|
43
|
+
* `in` is the config a user copy-pastes into a flow: the endpoint, the
|
|
44
|
+
* database and table to write to, and the credentials slot backed by a managed
|
|
45
|
+
* secret. Init creates exactly one ClickHouse client from it and holds that
|
|
46
|
+
* client on the resolved config, so every insert reuses the same connection
|
|
47
|
+
* pool.
|
|
48
|
+
*
|
|
49
|
+
* Two options the user did not write reach the client. `request_timeout` is
|
|
50
|
+
* derived from the collector's per-delivery timeout (10000 ms by default) minus
|
|
51
|
+
* what the retry delays can take, split across the attempts: at one retry that
|
|
52
|
+
* is 4812 ms, so the second attempt finishes before the collector stops waiting
|
|
53
|
+
* and dead-letters a batch the client would still land. Request compression is
|
|
54
|
+
* off in this client by default and insert bodies are large, repetitive JSON,
|
|
55
|
+
* so it is turned on. Both yield to `settings.clickhouse`.
|
|
56
|
+
*/
|
|
57
|
+
declare const init: Flow.StepExample;
|
|
58
|
+
/**
|
|
59
|
+
* What happens to the raw `settings.clickhouse` passthrough.
|
|
60
|
+
*
|
|
61
|
+
* The merge runs in four layers, lowest first: the passthrough, then the
|
|
62
|
+
* derived defaults where the passthrough left their key unset, then `url` and
|
|
63
|
+
* `database`, then `credentials`. An insert names only the table, so a
|
|
64
|
+
* passthrough `database` that disagreed with the configured one would move
|
|
65
|
+
* every row to a different database in silence; the configured one wins. The
|
|
66
|
+
* credentials slot wins over a username or password left in the passthrough,
|
|
67
|
+
* and an option the destination does not name travels through untouched.
|
|
68
|
+
*/
|
|
69
|
+
declare const initPassthrough: Flow.StepExample;
|
|
70
|
+
/**
|
|
71
|
+
* One event, one row, one insert. Every payload travels as a JSON-encoded
|
|
72
|
+
* string and the timestamp as a `YYYY-MM-DD hh:mm:ss.SSS` UTC literal, the
|
|
73
|
+
* format every ClickHouse date parser reads identically.
|
|
74
|
+
*/
|
|
75
|
+
declare const pageView: Flow.StepExample;
|
|
76
|
+
/**
|
|
77
|
+
* An order carries an array of items. The whole `data` object, array
|
|
78
|
+
* included, is JSON-encoded into the single `data` column, so a flow can send
|
|
79
|
+
* any shape without the table knowing about it.
|
|
80
|
+
*/
|
|
81
|
+
declare const purchase: Flow.StepExample;
|
|
82
|
+
|
|
83
|
+
declare const step_init: typeof init;
|
|
84
|
+
declare const step_initPassthrough: typeof initPassthrough;
|
|
85
|
+
declare const step_pageView: typeof pageView;
|
|
86
|
+
declare const step_purchase: typeof purchase;
|
|
87
|
+
declare namespace step {
|
|
88
|
+
export { step_init as init, step_initPassthrough as initPassthrough, step_pageView as pageView, step_purchase as purchase };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { env, step };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { DestinationServer } from '@walkeros/server-core';
|
|
2
|
+
import { ClickHouseClientConfigOptions, ClickHouseClient } from '@clickhouse/client';
|
|
3
|
+
import { Flow } from '@walkeros/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The only two client methods this package is allowed to reach for. Narrowing
|
|
7
|
+
* the seam to them makes the INSERT-only rule a compile-time property rather
|
|
8
|
+
* than a convention: `query`, `command`, `exec` and `ping` are not reachable
|
|
9
|
+
* from a client typed this way, so no code path can read `system.*` or issue
|
|
10
|
+
* DDL. The SDK's own `createClient` stays assignable by structural typing.
|
|
11
|
+
*/
|
|
12
|
+
type ClickHouseClientSurface = Pick<ClickHouseClient, 'insert' | 'close'>;
|
|
13
|
+
/** Creates the client this destination writes through. Matches `createClient`. */
|
|
14
|
+
type ClickHouseClientFactory = (config: ClickHouseClientConfigOptions) => ClickHouseClientSurface;
|
|
15
|
+
/**
|
|
16
|
+
* Env carries the client factory so tests and simulations inject a recording
|
|
17
|
+
* stand-in instead of opening a socket. Production leaves it undefined and the
|
|
18
|
+
* destination uses the SDK's own `createClient`.
|
|
19
|
+
*/
|
|
20
|
+
interface Env extends DestinationServer.Env {
|
|
21
|
+
ClickHouseClient?: ClickHouseClientFactory;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Example environment for the ClickHouse destination.
|
|
26
|
+
*
|
|
27
|
+
* The client factory is the recording stand-in from the package-local
|
|
28
|
+
* __mocks__ folder, so examples, tests and simulations share one source of
|
|
29
|
+
* truth and never reach a ClickHouse server.
|
|
30
|
+
*/
|
|
31
|
+
declare const push: Env;
|
|
32
|
+
declare const simulation: string[];
|
|
33
|
+
|
|
34
|
+
declare const env_push: typeof push;
|
|
35
|
+
declare const env_simulation: typeof simulation;
|
|
36
|
+
declare namespace env {
|
|
37
|
+
export { env_push as push, env_simulation as simulation };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Destination bootstrap.
|
|
42
|
+
*
|
|
43
|
+
* `in` is the config a user copy-pastes into a flow: the endpoint, the
|
|
44
|
+
* database and table to write to, and the credentials slot backed by a managed
|
|
45
|
+
* secret. Init creates exactly one ClickHouse client from it and holds that
|
|
46
|
+
* client on the resolved config, so every insert reuses the same connection
|
|
47
|
+
* pool.
|
|
48
|
+
*
|
|
49
|
+
* Two options the user did not write reach the client. `request_timeout` is
|
|
50
|
+
* derived from the collector's per-delivery timeout (10000 ms by default) minus
|
|
51
|
+
* what the retry delays can take, split across the attempts: at one retry that
|
|
52
|
+
* is 4812 ms, so the second attempt finishes before the collector stops waiting
|
|
53
|
+
* and dead-letters a batch the client would still land. Request compression is
|
|
54
|
+
* off in this client by default and insert bodies are large, repetitive JSON,
|
|
55
|
+
* so it is turned on. Both yield to `settings.clickhouse`.
|
|
56
|
+
*/
|
|
57
|
+
declare const init: Flow.StepExample;
|
|
58
|
+
/**
|
|
59
|
+
* What happens to the raw `settings.clickhouse` passthrough.
|
|
60
|
+
*
|
|
61
|
+
* The merge runs in four layers, lowest first: the passthrough, then the
|
|
62
|
+
* derived defaults where the passthrough left their key unset, then `url` and
|
|
63
|
+
* `database`, then `credentials`. An insert names only the table, so a
|
|
64
|
+
* passthrough `database` that disagreed with the configured one would move
|
|
65
|
+
* every row to a different database in silence; the configured one wins. The
|
|
66
|
+
* credentials slot wins over a username or password left in the passthrough,
|
|
67
|
+
* and an option the destination does not name travels through untouched.
|
|
68
|
+
*/
|
|
69
|
+
declare const initPassthrough: Flow.StepExample;
|
|
70
|
+
/**
|
|
71
|
+
* One event, one row, one insert. Every payload travels as a JSON-encoded
|
|
72
|
+
* string and the timestamp as a `YYYY-MM-DD hh:mm:ss.SSS` UTC literal, the
|
|
73
|
+
* format every ClickHouse date parser reads identically.
|
|
74
|
+
*/
|
|
75
|
+
declare const pageView: Flow.StepExample;
|
|
76
|
+
/**
|
|
77
|
+
* An order carries an array of items. The whole `data` object, array
|
|
78
|
+
* included, is JSON-encoded into the single `data` column, so a flow can send
|
|
79
|
+
* any shape without the table knowing about it.
|
|
80
|
+
*/
|
|
81
|
+
declare const purchase: Flow.StepExample;
|
|
82
|
+
|
|
83
|
+
declare const step_init: typeof init;
|
|
84
|
+
declare const step_initPassthrough: typeof initPassthrough;
|
|
85
|
+
declare const step_pageView: typeof pageView;
|
|
86
|
+
declare const step_purchase: typeof purchase;
|
|
87
|
+
declare namespace step {
|
|
88
|
+
export { step_init as init, step_initPassthrough as initPassthrough, step_pageView as pageView, step_purchase as purchase };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { env, step };
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/examples/index.ts
|
|
22
|
+
var examples_exports = {};
|
|
23
|
+
__export(examples_exports, {
|
|
24
|
+
env: () => env_exports,
|
|
25
|
+
step: () => step_exports
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(examples_exports);
|
|
28
|
+
|
|
29
|
+
// src/examples/env.ts
|
|
30
|
+
var env_exports = {};
|
|
31
|
+
__export(env_exports, {
|
|
32
|
+
push: () => push,
|
|
33
|
+
simulation: () => simulation
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// src/__mocks__/@clickhouse/client.ts
|
|
37
|
+
var client_exports = {};
|
|
38
|
+
__export(client_exports, {
|
|
39
|
+
__failInsert: () => __failInsert,
|
|
40
|
+
__getCalls: () => __getCalls,
|
|
41
|
+
__reset: () => __reset,
|
|
42
|
+
createClient: () => createClient
|
|
43
|
+
});
|
|
44
|
+
var import_client = require("@clickhouse/client");
|
|
45
|
+
__reExport(client_exports, require("@clickhouse/client"));
|
|
46
|
+
var calls = [];
|
|
47
|
+
var failure;
|
|
48
|
+
function __getCalls() {
|
|
49
|
+
return calls;
|
|
50
|
+
}
|
|
51
|
+
function __reset() {
|
|
52
|
+
calls.length = 0;
|
|
53
|
+
failure = void 0;
|
|
54
|
+
}
|
|
55
|
+
function __failInsert(times, options = {}) {
|
|
56
|
+
failure = {
|
|
57
|
+
remaining: times,
|
|
58
|
+
code: options.code,
|
|
59
|
+
message: options.message ?? "clickhouse insert failed",
|
|
60
|
+
type: options.type
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function nextFailure() {
|
|
64
|
+
if (!failure || failure.remaining < 1) return void 0;
|
|
65
|
+
failure.remaining -= 1;
|
|
66
|
+
const { code, message, type } = failure;
|
|
67
|
+
return code === void 0 ? new Error(message) : new import_client.ClickHouseError({ message, code, type });
|
|
68
|
+
}
|
|
69
|
+
var createClient = (config) => {
|
|
70
|
+
calls.push(["createClient", config]);
|
|
71
|
+
return {
|
|
72
|
+
async insert(params) {
|
|
73
|
+
calls.push(["insert", params]);
|
|
74
|
+
const error = nextFailure();
|
|
75
|
+
if (error) throw error;
|
|
76
|
+
return {
|
|
77
|
+
executed: true,
|
|
78
|
+
query_id: `mock-insert-${calls.length}`,
|
|
79
|
+
response_headers: {}
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
async close() {
|
|
83
|
+
calls.push(["close"]);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/examples/env.ts
|
|
89
|
+
var push = {
|
|
90
|
+
ClickHouseClient: createClient
|
|
91
|
+
};
|
|
92
|
+
var simulation = ["ClickHouseClient"];
|
|
93
|
+
|
|
94
|
+
// src/examples/step.ts
|
|
95
|
+
var step_exports = {};
|
|
96
|
+
__export(step_exports, {
|
|
97
|
+
init: () => init,
|
|
98
|
+
initPassthrough: () => initPassthrough,
|
|
99
|
+
pageView: () => pageView,
|
|
100
|
+
purchase: () => purchase
|
|
101
|
+
});
|
|
102
|
+
var import_core = require("@walkeros/core");
|
|
103
|
+
|
|
104
|
+
// src/eventToRow.ts
|
|
105
|
+
function pad(value, length) {
|
|
106
|
+
return String(value).padStart(length, "0");
|
|
107
|
+
}
|
|
108
|
+
function toDateTime(timestamp) {
|
|
109
|
+
const date = new Date(timestamp);
|
|
110
|
+
const day = [
|
|
111
|
+
pad(date.getUTCFullYear(), 4),
|
|
112
|
+
pad(date.getUTCMonth() + 1, 2),
|
|
113
|
+
pad(date.getUTCDate(), 2)
|
|
114
|
+
].join("-");
|
|
115
|
+
const time = [
|
|
116
|
+
pad(date.getUTCHours(), 2),
|
|
117
|
+
pad(date.getUTCMinutes(), 2),
|
|
118
|
+
pad(date.getUTCSeconds(), 2)
|
|
119
|
+
].join(":");
|
|
120
|
+
return `${day} ${time}.${pad(date.getUTCMilliseconds(), 3)}`;
|
|
121
|
+
}
|
|
122
|
+
function jsonOrEmpty(value) {
|
|
123
|
+
if (value === void 0 || value === null) return "";
|
|
124
|
+
if (typeof value === "object") {
|
|
125
|
+
if (Array.isArray(value)) {
|
|
126
|
+
if (value.length === 0) return "";
|
|
127
|
+
} else if (Object.keys(value).length === 0) return "";
|
|
128
|
+
}
|
|
129
|
+
return JSON.stringify(value);
|
|
130
|
+
}
|
|
131
|
+
function eventToRow(event) {
|
|
132
|
+
return {
|
|
133
|
+
name: event.name,
|
|
134
|
+
data: jsonOrEmpty(event.data),
|
|
135
|
+
context: jsonOrEmpty(event.context),
|
|
136
|
+
globals: jsonOrEmpty(event.globals),
|
|
137
|
+
custom: jsonOrEmpty(event.custom),
|
|
138
|
+
user: jsonOrEmpty(event.user),
|
|
139
|
+
nested: jsonOrEmpty(event.nested),
|
|
140
|
+
consent: jsonOrEmpty(event.consent),
|
|
141
|
+
id: event.id,
|
|
142
|
+
trigger: event.trigger,
|
|
143
|
+
entity: event.entity,
|
|
144
|
+
action: event.action,
|
|
145
|
+
timestamp: toDateTime(event.timestamp),
|
|
146
|
+
timing: event.timing,
|
|
147
|
+
source: jsonOrEmpty(event.source)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// src/insert.ts
|
|
152
|
+
var import_node_crypto = require("crypto");
|
|
153
|
+
|
|
154
|
+
// src/config.ts
|
|
155
|
+
var import_client3 = require("@clickhouse/client");
|
|
156
|
+
|
|
157
|
+
// src/insert.ts
|
|
158
|
+
function deduplicationToken(ids) {
|
|
159
|
+
return (0, import_node_crypto.createHash)("sha256").update(JSON.stringify(ids)).digest("hex");
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/examples/step.ts
|
|
163
|
+
var settings = {
|
|
164
|
+
url: "https://clickhouse.example.com:8443",
|
|
165
|
+
database: "analytics",
|
|
166
|
+
table: "events"
|
|
167
|
+
};
|
|
168
|
+
var init = {
|
|
169
|
+
title: "Initialization",
|
|
170
|
+
description: "Init creates a single ClickHouse client for the configured endpoint, database and credentials. The client is held on the resolved config and reused by every insert. Its request timeout is derived from the collector timeout so a retried insert cannot outlive the delivery it belongs to, and request compression is enabled.",
|
|
171
|
+
in: {
|
|
172
|
+
settings,
|
|
173
|
+
credentials: {
|
|
174
|
+
username: "walkeros_writer",
|
|
175
|
+
password: "$secret.CLICKHOUSE_PASSWORD"
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
out: [
|
|
179
|
+
[
|
|
180
|
+
"createClient",
|
|
181
|
+
{
|
|
182
|
+
url: "https://clickhouse.example.com:8443",
|
|
183
|
+
database: "analytics",
|
|
184
|
+
username: "walkeros_writer",
|
|
185
|
+
password: "$secret.CLICKHOUSE_PASSWORD",
|
|
186
|
+
request_timeout: 4812,
|
|
187
|
+
compression: { request: true }
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
]
|
|
191
|
+
};
|
|
192
|
+
var initPassthrough = {
|
|
193
|
+
title: "Client option passthrough",
|
|
194
|
+
description: "The raw settings.clickhouse options reach the client underneath the destination's own settings: url, database and the credentials slot win over them, an explicit request_timeout or compression wins over the derived default, and any other option travels through untouched.",
|
|
195
|
+
public: false,
|
|
196
|
+
in: {
|
|
197
|
+
settings: {
|
|
198
|
+
url: "https://clickhouse.example.com:8443",
|
|
199
|
+
database: "analytics",
|
|
200
|
+
clickhouse: {
|
|
201
|
+
url: "https://ignored.example.com:8443",
|
|
202
|
+
database: "ignored",
|
|
203
|
+
username: "ignored_user",
|
|
204
|
+
request_timeout: 6e4,
|
|
205
|
+
max_open_connections: 25,
|
|
206
|
+
application: "walkeros"
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
credentials: {
|
|
210
|
+
username: "walkeros_writer",
|
|
211
|
+
password: "$secret.CLICKHOUSE_PASSWORD"
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
out: [
|
|
215
|
+
[
|
|
216
|
+
"createClient",
|
|
217
|
+
{
|
|
218
|
+
url: "https://clickhouse.example.com:8443",
|
|
219
|
+
database: "analytics",
|
|
220
|
+
username: "walkeros_writer",
|
|
221
|
+
password: "$secret.CLICKHOUSE_PASSWORD",
|
|
222
|
+
request_timeout: 6e4,
|
|
223
|
+
max_open_connections: 25,
|
|
224
|
+
application: "walkeros",
|
|
225
|
+
compression: { request: true }
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
]
|
|
229
|
+
};
|
|
230
|
+
function expectedInsert(event) {
|
|
231
|
+
return [
|
|
232
|
+
[
|
|
233
|
+
"insert",
|
|
234
|
+
{
|
|
235
|
+
table: settings.table,
|
|
236
|
+
values: [eventToRow(event)],
|
|
237
|
+
format: "JSONEachRow",
|
|
238
|
+
clickhouse_settings: {
|
|
239
|
+
async_insert: 0,
|
|
240
|
+
input_format_skip_unknown_fields: 0,
|
|
241
|
+
input_format_null_as_default: 0,
|
|
242
|
+
insert_deduplication_token: deduplicationToken([event.id])
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
]
|
|
246
|
+
];
|
|
247
|
+
}
|
|
248
|
+
var pageViewEvent = (0, import_core.getEvent)("page view", { timestamp: 1700000000123 });
|
|
249
|
+
var pageView = {
|
|
250
|
+
title: "Page view",
|
|
251
|
+
description: "A page view is inserted as a single JSONEachRow row. The payload columns (data, context, globals, custom, user, nested, consent, source) are JSON-encoded strings and the timestamp is a UTC datetime literal, both produced by eventToRow.",
|
|
252
|
+
in: pageViewEvent,
|
|
253
|
+
mapping: void 0,
|
|
254
|
+
out: expectedInsert(pageViewEvent)
|
|
255
|
+
};
|
|
256
|
+
var purchaseEvent = (0, import_core.getEvent)("order complete", {
|
|
257
|
+
timestamp: 1700000000456,
|
|
258
|
+
data: {
|
|
259
|
+
id: "ORD-500",
|
|
260
|
+
currency: "EUR",
|
|
261
|
+
total: 199.99,
|
|
262
|
+
items: [
|
|
263
|
+
{ sku: "SKU-1", quantity: 2 },
|
|
264
|
+
{ sku: "SKU-2", quantity: 1 }
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
var purchase = {
|
|
269
|
+
title: "Purchase",
|
|
270
|
+
description: "An order event is inserted as one row. The nested items array is JSON-encoded into the data column, so a richer payload needs no table change. Promoting a hot key to its own column is a MATERIALIZED expression in the table DDL, not a destination setting.",
|
|
271
|
+
in: purchaseEvent,
|
|
272
|
+
mapping: void 0,
|
|
273
|
+
out: expectedInsert(purchaseEvent)
|
|
274
|
+
};
|
|
275
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
276
|
+
0 && (module.exports = {
|
|
277
|
+
env,
|
|
278
|
+
step
|
|
279
|
+
});
|