Connections
motherduck
Commentary
added in 1.10.0
Connects to a Motherduck database.
You can connect by either supplying a MotherDuck token and database name 1 or a JDBC url 2.
The MotherDuck connection writes data asynchronously. A new transaction will be executed every 1000 ms or 10000 rows, whichever happens first. You can override row size/write timing with batchConfigs. 3
Automatic table creation
By default for convenience, any tables ShadowTraffic writes to will be automatically created. This makes it easier to iterate on your generators without flipping back and forth between ShadowTraffic and MotherDuck.
ShadowTraffic does this by scanning the structure of your generators and creating a suitable DDL, then executing it on your behalf.
If ShadowTraffic doesn't create the table exactly as you'd want it, you can override each column using the sqlHint function modifier. 4
If the table already exists but you'd like to clear out any existing data, set tablePolicy to dropAndCreate. 5
Manual table control
If you don't ShadowTraffic to control your tables, you can turn this behavior off by setting tablePolicy to manual in the connection map. It'll then be up to you to make sure your tables exist before trying to write to them. 6
Generating updates and deletes
By default, ShadowTraffic only issues INSERT statements to your tables. But sometimes, it might be useful to issue UPDATE and DELETE statements too.
You can control the statement type by setting the op key on your generator. op must be one of insert, update, or delete.
For the latter two, you must also include a where key on your generator, which contains a map of column name to value. You need this because when you issue an update or a delete, you need to tell MotherDuck what rows you want to change. The where map is used to check equality and select rows that match. 7
Generating reader traffic
In addition to mutating events (inserts, updates, and deletes), this connection also has the ability to issue read traffic. In other words, it's able to send arbitrary SQL to MotherDuck with the intent of running ordinary SELECT queries. Query results are realized in memory and discard. 8
Examples
Connecting with a token
You can authenticate with MotherDuck in two different ways. The first, shown here, is to supply a token and db. ShadowTraffic will figure out the right connection endpoint based on these two parameters. You can read about how to obtain a token from MotherDuck's docs.
It's advisable to keep your token in an environment variable (shown here) to avoid hardcoding it in your ShadowTraffic file.
You can also optionally supply of a map of queryParams, which will be tacked onto the end of the URL ShadowTraffic uses to connect to MotherDuck. This is useful if you want to set arbitrary connection parameters like attach_mode and dbinstance_inactivity_ttl. Note that one query parameter you can't set set is session_hint, because it's controlled by ShadowTraffic to multiplex connections under the hood.
{
"connections": {
"md": {
"kind": "motherduck",
"connectionConfigs": {
"token": {
"_gen": "env",
"var": "MOTHERDUCK_TOKEN"
},
"db": "mydb",
"queryParams": {
"attach_mode": "single",
"dbinstance_inactivity_ttl": "600"
}
}
}
}
}
Connecting with a JDBC URL
The second way you can authenticate is to directly pass a JDBC url. This is useful if you want to control the entire connection string, or perhaps transparently redirect the data to DuckDB.
{
"connections": {
"md": {
"kind": "motherduck",
"connectionConfigs": {
"jdbcUrl": "jdbc:duckdb:md:my_db?motherduck_token"
}
}
}
}
Setting batch parameters
Set batchConfigs to control how frequently transactions are written. In this example, a transaction is executed whenever 500 milliseconds pass or 5000 rows are accumulated—whichever comes first.
{
"connections": {
"md": {
"kind": "motherduck",
"connectionConfigs": {
"token": {
"_gen": "env",
"var": "MOTHERDUCK_TOKEN"
},
"db": "mydb"
},
"batchConfigs": {
"lingerMs": 500,
"batchRows": 5000
}
}
}
}
Automatic table creation
By default, table sandbox doesn't need to be defined. ShadowTraffic will automatically create it for you.
{
"generators": [
{
"table": "sandbox",
"row": {
"id": {
"_gen": "uuid"
},
"level": {
"_gen": "uniformDistribution",
"bounds": [
1,
10
]
},
"active": {
"_gen": "boolean"
}
}
}
],
"connections": {
"md": {
"kind": "motherduck",
"connectionConfigs": {
"token": {
"_gen": "env",
"var": "MOTHERDUCK_TOKEN"
},
"db": "mydb"
}
}
}
}
In this case, sandbox will be created like so:
┌─────────────┬──── ─────────┬──────┬─────┬─────────┬───────┐
│ column_name ┆ column_type ┆ null ┆ key ┆ default ┆ extra │
╞═════════════╪═════════════╪══════╪═════╪═════════╪═══════╡
│ id ┆ VARCHAR ┆ YES ┆ ┆ ┆ │
│ level ┆ DOUBLE ┆ YES ┆ ┆ ┆ │
│ active ┆ BOOLEAN ┆ YES ┆ ┆ ┆ │
└─────────────┴─────────────┴──────┴─────┴─────────┴───────┘
Automatic table truncation
Use dropAndCreate to automatically clear out any rows in an existing target table. This will executing a cascading drop, deleting any dependent objects too.
{
"kind": "motherduck",
"tablePolicy": "dropAndCreate",
"connectionConfigs": {
"token": {
"_gen": "env",
"var": "MOTHERDUCK_TOKEN"
},
"db": "mydb"
}
}
Overriding column types
Use the optional sqlHint function modifier on any generator to override how its column is defined.
{
"table": "sandbox",
"row": {
"id": {
"_gen": "uuid",
"sqlHint": "TEXT NOT NULL"
},
"level": {
"_gen": "uniformDistribution",
"bounds": [
1,
10
],
"sqlHint": "INTEGER"
},
"active": {
"_gen": "boolean"
}
}
}
Now, sandbox will like this:
┌─────────────┬─────────────┬──────┬─────┬─────────┬───────┐
│ column_name ┆ column_type ┆ null ┆ key ┆ default ┆ extra │
╞═════════════╪═════════════╪══════╪═════╪═════════╪══ ═════╡
│ id ┆ VARCHAR ┆ NO ┆ ┆ ┆ │
│ level ┆ INTEGER ┆ YES ┆ ┆ ┆ │
│ active ┆ BOOLEAN ┆ YES ┆ ┆ ┆ │
└─────────────┴─────────────┴──────┴─────┴─────────┴───────┘
Manual table creation
Use manual to prevent ShadowTraffic from automatically creating tables for you. When you do this, your tables must already exist before ShadowTraffic tries to write to them.
{
"kind": "motherduck",
"tablePolicy": "manual",
"connectionConfigs": {
"token": {
"_gen": "env",
"var": "MOTHERDUCK_TOKEN"
},
"db": "mydb"
}
}
Upserts and deletes
Use op and where to issue upserts and deletes. It's up to you to make sure that you don't try to update or delete rows that don't exist.
This example uses fork and stateMachine to generate many simultaneous rows being inserted, updated, and deleted.
In the first state, insertIt, a random value of about 50 is generated. In the second state, updateIt, the value gets updated to one of 1, 5, or 10. Finally, in deleteIt, the entire row is deleted.
id is generated once as a fork key and used as the basis for equality to perform updates and deletes.
{
"table": "sandbox",
"fork": {
"key": {
"_gen": "uuid"
}
},
"row": {
"id": {
"_gen": "var",
"var": "forkKey"
}
},
"stateMachine": {
"_gen": "stateMachine",
"initial": "insertIt",
"transitions": {
"insertIt": "updateIt",
"updateIt": "deleteIt"
},
"states": {
"insertIt": {
"row": {
"value": {
"_gen": "normalDistribution",
"mean": 50,
"sd": 15
}
}
},
"updateIt": {
"op": "update",
"where": {
"id": {
"_gen": "var",
"var": "forkKey"
}
},
"row": {
"value": {
"_gen": "oneOf",
"choices": [
1,
5,
10
]
}
}
},
"deleteIt": {
"op": "delete",
"where": {
"id": {
"_gen": "var",
"var": "forkKey"
}
}
}
}
}
}
A random snapshot of the table might look like:
duckdb> select * from sandbox limit 10;
┌───────────────────────────────────────┬───────┐
│ id ┆ value │
╞═══════════════════════════════════════╪═══════╡
│ 07f217c6-1c82-e1cb-6dd8-fc614ff1a6e3 ┆ 49 │
│ 83d35207-ac3f-b8a7-fd7e-c82e1bdc3b05 ┆ 10 │
│ 184a0e26-237f-915b-4d97-5dc1808d91df ┆ 37 │
└───────────────────────────────────────┴───────┘
Timestamp types
If your schema uses a timestamp type (timestamp, timestamp with time zone and friends), use serialize around your timestamp (Unix ms) to write it with a compatible type. This works because MotherDuck is wire-compatible with Postgres.
The specific format of the timestamp will defer to the schema set in MotherDuck.
{
"table": "sandbox",
"row": {
"createdAt": {
"_gen": "now",
"serialize": {
"type": "postgresTimestamp"
}
}
}
}
Generating reads
To generate read events, mark the top-level generator with kind set to reader (generator kind is default set to writer, but it is explicitly shown here). Then set query to the SQL query you want to execute.
In this example, there are two generators.
- The first writes data to the table
foo. - The second looks up data previously written to
fooand uses to run targetedSELECTqueries against that same table. It usesinterpolateto build the SQL strings.
These two generators interleave, issuing a mix of read and write traffic to MotherDuck.
{
"generators": [
{
"kind": "writer",
"table": "foo",
"row": {
"bar": {
"_gen": "uuid"
}
}
},
{
"kind": "reader",
"query": {
"_gen": "interpolate",
"template": "SELECT * FROM foo WHERE bar=':id';",
"params": {
"id": {
"_gen": "lookup",
"table": "foo",
"path": [
"row",
"bar"
]
}
}
}
}
],
"connections": {
"md": {
"kind": "motherduck",
"connectionConfigs": {
"token": {
"_gen": "env",
"var": "MOTHERDUCK_TOKEN"
},
"db": "mydb"
}
}
}
}
Connection pooling
By default, each MotherDuck connection instance establishes one network connection to the database. You can increase this by setting poolSize, which will establish n unique connections (and sessions). ShadowTraffic will then emit events evenly across each connection in the pool. This is useful if you want stripe traffic across many nodes in a MotherDuck cluster from a single ShadowTraffic generator.
Note that ShadowTraffic makes no gaurantees about which events will sent on which connection. If your workload requires atomicity, you probably don't want to enable this.
{
"connections": {
"md": {
"kind": "motherduck",
"poolSize": 3,
"connectionConfigs": {
"token": {
"_gen": "env",
"var": "MOTHERDUCK_TOKEN"
},
"db": "mydb"
}
}
}
}
Object comments
When ShadowTraffic is responsible for creating your tables, you can optionally supply comments at both the table and column-level. Set comments to a map of table and/or columns with your respective text.
Note that ShadowTraffic won't register comments for pre-existing tables.
{
"table": "time_series_data",
"row": {
"id": {
"_gen": "uuid"
},
"timestamp": {
"gen": "now"
}
},
"comments": {
"table": "data captured from registered devices",
"columns": {
"id": "uuid v4 from legacy devices",
"timestamp": "the timestamp on the device itself"
}
}
}
Follow the DuckDB docs to query comments on the respective objects.
Writing to multiple tables
If you need to generate data to multiple tables per generator iteration, use tables instead of table and row.
tables is a map of table name to attributes, where the attributes generally minor what is otherwse specified at the top level (e.g. row, comments, op, and so on).
In this example, each iteration of the generator writes one row to t1 and one row to t2. What's nice about being able to express your tables this way is that both t1 and t2 share the same variables space, so it's easy to generate linked data without reaching for more advanced functionality like fork.
Three additional notes about writing to multiple tables:
- The rows for each table are committed independently. In other words, in this example
t1andt2do not commit atomically. This is because writes are executed using DuckDB's Appender API, which don't support multi-table operations. - The configured batch settings for your connection apply to each table. For example, if this connection were configured to commit after 1,000 rows have been created, then
t1andt2would commit their writes whenever either has achieved 1,000 rows. - Connection pooling is applied at the per table level. For instance, if this connection were opened with a pool size of 3, ShadowTraffic would open 6 total connections to MotherDuck.
{
"tables": {
"t1": {
"row": {
"foo": {
"_gen": "boolean"
}
}
},
"t2": {
"row": {
"bar": {
"_gen": "uuid"
}
},
"comments": {
"table": "t2 is a good table",
"columns": {
"foo": "foo is just an okay column"
}
}
}
}
}
Moreover, if you want to lookup data on a table that writes to multiple table, you must give that generator a name to look it up by (since there is no single table target to look up by)
[
{
"name": "compositeTables",
"tables": {
"t1": {
"row": {
"id": {
"_gen": "uuid"
}
}
},
"t2": {
"row": {
"state": {
"_gen": "boolean"
}
}
}
}
},
{
"table": "dependentTable",
"vars": {
"target": {
"_gen": "lookup",
"name": "compositeTables"
}
},
"row": {
"foreignId": {
"_gen": "var",
"var": "target",
"path": [
"t1",
"row",
"id"
]
},
"foreignState": {
"_gen": "var",
"var": "target",
"path": [
"t2",
"row",
"state"
]
},
"id": {
"_gen": "uuid"
}
}
}
]
Writing multiple rows
By default, ShadowTraffic writes one row per table per iteration. If you want to write multiple rows, use rows instead of row. Rows must be either:
- An array literal of maps
- A function, like
repeatedlythat resolves to an array of maps.
rows is particular useful when used to generate multiple tables in one shot to create 1 to many relationships.
{
"table": "sandbox",
"rows": {
"_gen": "repeatedly",
"n": {
"_gen": "uniformDistribution",
"bounds": [
1,
5
],
"decimals": 0
},
"target": {
"id": {
"_gen": "uuid"
},
"level": {
"_gen": "uniformDistribution",
"bounds": [
1,
10
]
},
"active": {
"_gen": "boolean"
}
}
}
}
Specification
Connection JSON schema
{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "motherduck"
},
"connectionConfigs": {
"type": "object",
"properties": {
"jdbcUrl": {
"type": "string"
},
"token": {
"type": "string"
},
"queryParams": {
"type": "object"
},
"db ": {
"type": "string"
}
},
"oneOf": [
{
"required": [
"jdbcUrl"
]
},
{
"required": [
"token",
"db"
]
}
]
},
"batchConfigs": {
"type": "object",
"properties": {
"lingerMs": {
"type": "integer",
"minimum": 0
},
"batchRows": {
"type": "integer",
"minimum": 0
}
}
},
"poolSize": {
"type": "integer",
"minimum": 1
},
"tablePolicy": {
"type": "string",
"enum": [
"manual",
"create",
"dropAndCreate"
]
}
},
"required": [
"connectionConfigs"
]
}
Writer generator JSON schema
{
"oneOf": [
{
"type": "object",
"properties": {
"table": {
"type": "string"
},
"localConfigs": {
"type": "object",
"properties": {
"throttleMs": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"maxEvents": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"kafkaKeyProtobufHint": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
},
"jsonSchemaHint": {
"type": "object"
},
"maxBytes": {
"type": "integer",
"minimum": 1
},
"discard": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"retainHistory": {
"type": "boolean"
}
},
"required": [
"rate"
]
},
"repeat": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"times": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
},
"required": [
"rate",
"times"
]
},
"protobufSchemaHint": {
"type": "object",
"patternProperties": {
"^.*$": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
}
}
},
"schemaRegistrySubject": {
"type": "object"
},
"maxHistoryEvents": {
"type": "integer",
"minimum": 0
},
"maxMs": {
"type": "integer",
"minimum": 0
},
"time": {
"type": "integer"
},
"events": {
"type": "object",
"properties": {
"exactly": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
}
},
"delay": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"ms": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
},
"required": [
"rate",
"ms"
]
},
"history": {
"type": "object",
"properties": {
"events": {
"type": "object",
"properties": {
"max": {
"type": "integer",
"minimum": 0
}
}
}
}
},
"avroSchemaHint": {
"type": "object"
},
"throttle": {
"type": "object",
"properties": {
"ms": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
}
},
"throughput": {
"oneOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"timeMultiplier": {
"oneOf": [
{
"type": "number"
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"kafkaValueProtobufHint": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
}
}
},
"where": {
"type": "object"
},
"name": {
"type": "string"
},
"connection": {
"type": "string"
},
"row": {
"type": "object"
},
"comments": {
"type": "object",
"properties": {
"table": {
"type": "string"
},
"columns": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
},
"rows": {
"oneOf": [
{
"type": "array",
"items": {
"type": "object"
}
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"op": {
"type": "string",
"enum": [
"insert",
"update",
"delete"
]
}
},
"required": [
"table"
],
"oneOf": [
{
"required": [
"row"
]
},
{
"required": [
"rows"
]
}
],
"allOf": [
{
"if": {
"properties": {
"op": {
"const": "update"
}
}
},
"then": {
"required": [
"where"
]
}
},
{
"if": {
"properties": {
"op": {
"const": "delete"
}
}
},
"then": {
"required": [
"where"
]
}
}
]
},
{
"type": "object",
"properties": {
"connection": {
"type": "string"
},
"name": {
"type": "string"
},
"tables": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"row": {
"type": "object"
},
"rows": {
"oneOf": [
{
"type": "array",
"items": {
"type": "object"
}
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"op": {
"type": "string",
"enum": [
"insert",
"update",
"delete"
]
},
"where": {
"type": "object"
},
"comments": {
"type": "object",
"properties": {
"table": {
"type": "string"
},
"columns": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
},
"oneOf": [
{
"required": [
"row"
]
},
{
"required": [
"rows"
]
}
],
"allOf": [
{
"if": {
"properties": {
"op": {
"const": "update"
}
}
},
"then": {
"required": [
"where"
]
}
},
{
"if": {
"properties": {
"op": {
"const": "delete"
}
}
},
"then": {
"required": [
"where"
]
}
}
]
}
},
"localConfigs": {
"type": "object",
"properties": {
"throttleMs": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"maxEvents": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"kafkaKeyProtobufHint": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
},
"jsonSchemaHint": {
"type": "object"
},
"maxBytes": {
"type": "integer",
"minimum": 1
},
"discard": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"retainHistory": {
"type": "boolean"
}
},
"required": [
"rate"
]
},
"repeat": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"times": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
},
"required": [
"rate",
"times"
]
},
"protobufSchemaHint": {
"type": "object",
"patternProperties": {
"^.*$": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
}
}
},
"schemaRegistrySubject": {
"type": "object"
},
"maxHistoryEvents": {
"type": "integer",
"minimum": 0
},
"maxMs": {
"type": "integer",
"minimum": 0
},
"time": {
"type": "integer"
},
"events": {
"type": "object",
"properties": {
"exactly": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
}
},
"delay": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"ms": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
},
"required": [
"rate",
"ms"
]
},
"history": {
"type": "object",
"properties": {
"events": {
"type": "object",
"properties": {
"max": {
"type": "integer",
"minimum": 0
}
}
}
}
},
"avroSchemaHint": {
"type": "object"
},
"throttle": {
"type": "object",
"properties": {
"ms": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
}
},
"throughput": {
"oneOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"timeMultiplier": {
"oneOf": [
{
"type": "number"
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"kafkaValueProtobufHint": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
}
}
}
},
"required": [
"tables"
]
}
]
}
Reader generator JSON schema
{
"type": "object",
"properties": {
"connection": {
"type": "string"
},
"name": {
"type": "string"
},
"query": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"localConfigs": {
"type": "object",
"properties": {
"throttleMs": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"maxEvents": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"kafkaKeyProtobufHint": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
},
"jsonSchemaHint": {
"type": "object"
},
"maxBytes": {
"type": "integer",
"minimum": 1
},
"discard": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"retainHistory": {
"type": "boolean"
}
},
"required": [
"rate"
]
},
"repeat": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"times": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
},
"required": [
"rate",
"times"
]
},
"protobufSchemaHint": {
"type": "object",
"patternProperties": {
"^.*$": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
}
}
},
"schemaRegistrySubject": {
"type": "object"
},
"maxHistoryEvents": {
"type": "integer",
"minimum": 0
},
"maxMs": {
"type": "integer",
"minimum": 0
},
"time": {
"type": "integer"
},
"events": {
"type": "object",
"properties": {
"exactly": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
}
},
"delay": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"ms": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
},
"required": [
"rate",
"ms"
]
},
"history": {
"type": "object",
"properties": {
"events": {
"type": "object",
"properties": {
"max": {
"type": "integer",
"minimum": 0
}
}
}
}
},
"avroSchemaHint": {
"type": "object"
},
"throttle": {
"type": "object",
"properties": {
"ms": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
}
},
"throughput": {
"oneOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"timeMultiplier": {
"oneOf": [
{
"type": "number"
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"kafkaValueProtobufHint": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
}
}
}
},
"required": [
"query"
]
}