diff --git a/knowledge base/cloud computing/aws/README.md b/knowledge base/cloud computing/aws/README.md
index c417972..89905b4 100644
--- a/knowledge base/cloud computing/aws/README.md
+++ b/knowledge base/cloud computing/aws/README.md
@@ -636,6 +636,52 @@ Such roles need to allow being assumed by the `states.amazonaws.com` Principal.
If wanting to send logs to CloudWatch, the execution role must be able to access the log group.
+
+ Example: get an RDS DB instance's information and pass it as a specific attribute
+
+```json
+{
+ "Comment": "Get an RDS DB instance's information and pass it as a specific attribute",
+ "StartAt": "Get RDS DB Instance information",
+ "States": {
+ "Get RDS DB Instance information": {
+ "Type": "Task",
+ "Arguments": {
+ "DbInstanceIdentifier": "some-rds-db-instance-identifier"
+ },
+ "Resource": "arn:aws:states:::aws-sdk:rds:describeDBInstances",
+ "End": true,
+ "Output": {
+ "RdsDbInstanceInformation": "{% $states.result.DbInstances[0] %}"
+ }
+ }
+ },
+ "QueryLanguage": "JSONata"
+}
+```
+
+
+
+Unless one knows exactly what one is doing, prefer setting arguments from the service's Console to have _some_ level of
+suggestions.
+
+
+ FIXME - using variables in DescribeDBSnapshots
+
+```json
+{
+ "DbInstanceIdentifier": "{% $states.input.ProdDBInstanceInfo.DbInstanceIdentifier %}"
+}
+```
+
+```json
+{
+ "AvailableDBSnapshots": "{% $states.result.DbSnapshots[Status='available'] %}"
+}
+```
+
+
+
## Resource constraints
| Data type | Component | Summary | Description | Type | Length | Pattern | Required |
diff --git a/knowledge base/jsonata.md b/knowledge base/jsonata.md
new file mode 100644
index 0000000..fd3f4be
--- /dev/null
+++ b/knowledge base/jsonata.md
@@ -0,0 +1,92 @@
+# JSONata
+
+> TODO
+
+JSON query and transformation language.
+
+
+
+1. [TL;DR](#tldr)
+1. [Further readings](#further-readings)
+ 1. [Sources](#sources)
+
+## TL;DR
+
+```plaintext
+# Concatenate strings
+someAttribute & 'someSuffix'
+'somePrefix' & someAttribute
+'somePrefix' & someAttribute & 'someSuffix'
+
+# Join strings
+$join(['somePrefix', someAttribute, 'someSuffix'], '-')
+
+# Filter array of objects by attribute's value
+users[role = "admin"]
+users[role = "admin" and name = "Alice"].name
+
+# Filter events with timestamp value in the last week
+events[$toMillis(timestamp) >= $toMillis($now()) - (60 * 60 * 7 * 24 * 1000)]
+
+# Get a random value between 0 included and 1 excluded (0<=X<1)
+$random()
+
+# Get a random object from a list
+# Lists are 0-indexed
+users[$floor($random()*$count($users))]
+```
+
+
+
+
+
+
+
+## Further readings
+
+- [Website]
+- [Codebase]
+
+### Sources
+
+- [Documentation]
+
+
+
+
+
+
+
+[Codebase]: https://github.com/jsonata-js/jsonata
+[Documentation]: https://docs.jsonata.org/
+[Website]: https://jsonata.org/
+
+
diff --git a/snippets/pulumi/aws/step function to create clones of an rds instance.ts b/snippets/pulumi/aws/step function to create clones of an rds instance.ts
new file mode 100644
index 0000000..4985a73
--- /dev/null
+++ b/snippets/pulumi/aws/step function to create clones of an rds instance.ts
@@ -0,0 +1,219 @@
+import * as pulumi from "@pulumi/pulumi";
+import * as aws from "@pulumi/aws";
+
+const iamRole: pulumi.Output = aws.iam.getRoleOutput({
+ name: 'SomeServiceRole',
+});
+
+// -----------------
+
+/**
+ * Base type for Step Function states.
+ *
+ * States are elements in a state machine.\
+ * A state is referred to by its name, which can be any string, but which must be unique within the scope of the entire
+ * state machine.
+ *
+ * States take input from their own invocation or a previous state.\
+ * States can filter their input and manipulate the output that is sent to the next state.
+ *
+ * Refer .
+ */
+type StateMachineBaseState = {
+ Type: string;
+ Comment?: string;
+ Next?: string;
+ End?: boolean;
+};
+
+/**
+ * Choice state.\
+ * Enables conditional branching.
+ */
+interface StateMachineChoiceState extends StateMachineBaseState {
+ Type: "Choice";
+ Choices: Record[];
+ Default: string;
+};
+
+/**
+ * Branch type for Parallel states.\
+ * Itself a smaller state machine.
+ */
+type StateMachineParallelBranch = {
+ StartAt: string;
+ States: Record;
+}
+/**
+ * Parallel state.\
+ * Runs other step states in parallel.
+ */
+interface StateMachineParallelState extends StateMachineBaseState {
+ Type: "Parallel";
+ Branches: StateMachineParallelBranch[];
+};
+
+/**
+ * Task state.\
+ * Runs a service integration or Lambda function.
+ */
+interface StateMachineTaskState extends StateMachineBaseState {
+ Type: "Task";
+ Resource: string;
+ Arguments?: Record;
+ Output?: Record;
+};
+
+/**
+ * Wait state.\
+ * Pauses execution for a fixed duration or until a specified time or date.
+ */
+interface StateMachineWaitState extends StateMachineBaseState {
+ Type: "Wait";
+ Seconds?: number;
+ Timestamp?: string;
+};
+
+/**
+ * Union type for Step Function states.
+ */
+type StateMachineStepState =
+ | StateMachineChoiceState
+ | StateMachineParallelState
+ | StateMachineTaskState
+ | StateMachineWaitState;
+
+/**
+ * Generic State Machine definition.
+ */
+interface StateMachineDefinition {
+ Comment?: string;
+ QueryLanguage?: string;
+ StartAt: string;
+ States: Record;
+};
+
+// -----------------
+
+const changeClonedDbInstancePassword: StateMachineTaskState = {
+ Type: "Task",
+ Resource: "arn:aws:states:::aws-sdk:rds:modifyDBInstance",
+ Arguments: {
+ DbInstanceIdentifier: "{% $states.input.ClonedDBInstance.DbInstanceIdentifier %}",
+ MasterUserPassword: "some-Secur3-Password",
+ ApplyImmediately: true,
+ },
+ End: true,
+};
+
+const checkClonedDbInstanceIsAvailable: StateMachineChoiceState = {
+ Type: "Choice",
+ Choices: [
+ {
+ Condition: "{% $states.input.ClonedDBInstance.DBInstanceStatus in ['available'] %}",
+ Next: "ChangeClonedDBInstancePassword",
+ },
+ ],
+ Default: "WaitForClonedDBInstanceNextCheck",
+};
+
+const createClonedDbInstance: StateMachineTaskState = {
+ Type: "Task",
+ Resource: "arn:aws:states:::aws-sdk:rds:restoreDBInstanceToPointInTime",
+ Arguments: {
+ SourceDBInstanceIdentifier: "{% $states.input.ExistingDBInstanceInfo.DbInstanceIdentifier %}",
+ UseLatestRestorableTime: true,
+ TargetDBInstanceIdentifier: "{% $join([$states.input.ExistingDBInstanceInfo.DbInstanceIdentifier, 'clone'], '-') %}",
+ Engine: "postgres",
+ MultiAZ: false,
+ AvailabilityZone: "eu-west-1a",
+ DbSubnetGroupName: "default",
+ PubliclyAccessible: false,
+ VpcSecurityGroupIds: [],
+ DbParameterGroupName: "{% $states.input.ExistingDBInstanceInfo.DbParameterGroups[0].DbParameterGroupName %}",
+ OptionGroupName: "{% $states.input.ExistingDBInstanceInfo.OptionGroupMemberships[0].OptionGroupName %}",
+ StorageType: "gp3",
+ DedicatedLogVolume: false,
+ DbInstanceClass: "db.t4g.medium",
+ DeletionProtection: false,
+ AutoMinorVersionUpgrade: false,
+ },
+ Output: {
+ ClonedDBInstance: "{% $states.result.DbInstance %}",
+ },
+ Next: "GetClonedDBInstanceState",
+};
+
+const getClonedDbInstanceState: StateMachineTaskState = {
+ Type: "Task",
+ Resource: "arn:aws:states:::aws-sdk:rds:describeDBInstances",
+ Arguments: {
+ DbInstanceIdentifier: "{% $states.input.ClonedDBInstance.DbInstanceIdentifier %}",
+ },
+ Output: {
+ ClonedDBInstance: "{% $states.result.DbInstances[0] %}",
+ },
+ Next: "CheckClonedDBInstanceIsAvailable",
+};
+
+const getExistingDbInstanceInfo: StateMachineTaskState = {
+ Type: "Task",
+ Resource: "arn:aws:states:::aws-sdk:rds:describeDBInstances",
+ Arguments: {
+ DbInstanceIdentifier: "some-existing-rds-instance",
+ },
+ Output: {
+ ExistingDBInstanceInfo: "{% $states.result.DbInstances[0] %}",
+ },
+ Next: "ParallelZone",
+};
+
+const waitForClonedDbInstanceNextCheck: StateMachineWaitState = {
+ Type: "Wait",
+ Seconds: 60,
+ Next: "GetClonedDBInstanceState",
+};
+
+const parallelZone: StateMachineParallelState = {
+ Type: "Parallel",
+ Branches: [
+ {
+ StartAt: "CreateClonedDBInstance",
+ States: {
+ CreateClonedDBInstance: createClonedDbInstance,
+ GetClonedDBInstanceState: getClonedDbInstanceState,
+ CheckClonedDBInstanceIsAvailable: checkClonedDbInstanceIsAvailable,
+ WaitForClonedDBInstanceNextCheck: waitForClonedDbInstanceNextCheck,
+ ChangeClonedDBInstancePassword: changeClonedDbInstancePassword,
+ },
+ },
+ // FIXME: another branch here
+ ],
+ End: true,
+};
+
+const stateMachineDefinition: StateMachineDefinition = {
+ QueryLanguage: "JSONata",
+ States: {
+ GetExistingDBInstanceInfo: getExistingDbInstanceInfo,
+ ParallelZone: parallelZone,
+ },
+ StartAt: "GetExistingDBInstanceInfo",
+};
+// pulumi.jsonStringify(stateMachineDefinition).apply(s => console.log(s))
+
+const dbCloner_stateMachine: aws.sfn.StateMachine = new aws.sfn.StateMachine(
+ 'dbCloner',
+ {
+ name: 'DBCloner',
+ roleArn: iamRole.arn,
+ loggingConfiguration: {
+ level: "OFF",
+ },
+ encryptionConfiguration: {
+ type: "AWS_OWNED_KEY",
+ },
+ publish: false,
+ definition: pulumi.jsonStringify(stateMachineDefinition),
+ },
+);