Object
Introduction
Object represents DynamoDB's Map data type (marshalled as "M").
Define an Object
- DynamoQL
- produced type
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
info: Object, // shorthand
adress: {
// longhand
type: Object,
allowUndeclared: true,
fields: {}
}
} as const);
interface IUserSchema {
id: string,
info: Record<string, any>,
adress?: Record<string, any>
}
When Object type is defined with a JS object, fields must be defined.
Nested Object
To define nested object properties, fill fields with desired keys and types
- DynamoQL
- produced type
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
adress: {
type: Object,
fields: {
country: String,
city: String,
street: String,
zip: {
type: Number,
min: 01,
max: 999999
}
}
}
} as const);
interface IUserSchema {
id: string,
adress?: {
country: string;
city: string;
street: string;
zip?: number
}
}
Options
- required
boolean which makes attribute as required or optionnal, default is false when type is defined with a JS object.
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
adress: {
type: Object,
required: true,
fields: {
country: String,
city: String
}
}
} as const);
- default
To set a default value for an attribute use default option.
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
adress: {
type: Object,
fields: {
country: String,
city: String
},
default: {
country: "France",
city: "Paris"
},
}
} as const);
With this configuration when you put an Item into your table, your Item will contain adress attribute with {country: "France", city: "Paris"} as value.
default's type must match fields type.
Otherwise it will throw an error during dev time and runtime.
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
adress: {
type: Object,
fields: {
country: String,
city: String
},
default: { // DynamoQLInvalidTypeException: "adress.country" expected to be "S" received "N".
country: 87,
city: "Some-city"
}
}
} as const);
default can also be a (async) function which accepts one argument (put Item value) and must return an object which type's must match fields type.
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
adress: {
type: Object,
fields: {
country: String,
city: String
},
default: async (item: Record<string, any>) => {
const userInfo = await getUserAdress(item.id)
return userInfo.adress
}
}
} as const);
- allow undeclared
allowUndeclared option allows you to define an object with unknown properties.
Default is false.
when false all undeclared fields are removed from object before putting or updating an item.
- DynamoQL
- produced type
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
adress: {
type: Object,
allowUndeclared: true,
fields: {}
}
} as const);
interface IUserSchema {
id: string,
adress?: Record<string, any>
}
It is possible to combine fields with allowUndeclared:
- DynamoQL
- produced type
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
adress: {
type: Object,
allowUndeclared: true,
fields: {
country: String,
city: {
type: String,
required: false
}
},
}
} as const);
interface IUserSchema {
id: string,
adress?: { country: string; city?:string } & Record<string, any>
}
Reduce usage of allowUndeclared when possible.
Prefer union types and required declarations in fields instead.
- DynamoQL
- produced type
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
adress: {
type: Object,
required: true
fields: {
country: [
{ type: String },
{
type: Number,
set: (self:number)=> {
return getCountryLabelFromCountryCode(self)
}
}
],
city: { type: String },
zip: [
{ type: Number },
{
type: String,
set: (self:string)=> {
return Number(self)
}
}
],
},
}
} as const);
interface IUserSchema {
id: string,
adress: {
country?: string | number;
city?: string;
zip?: string | number;
}
}
- set
To modify a value before storing it use set option.
set (async) function accepts 3 arguments:
selfprovided value.itementier put Item object.setterInfoan optionnal value provided inside in put, batchPut, batchWrite, transactWrite command's options.
set will not be called if attribute doesn't exists in put Item object.
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
moderator: Boolean,
adress: {
type: Object,
fields: {
country: String,
city: String
},
set: (self: Record<string, any>, item: Record<string, any>, setterInfo?: any)=> {
if(item.moderator && setterInfo?.someCondition) {
return {
country: "UK",
city: "London"
}
}
return self
}
}
} as const);
- get
When reteving an Item we can transform field's value with get option.
get (async) function accepts 3 arguments:
selfretrieved value.itementier retrieved Item object.getterInfoan optionnal value provided inside get, batchGet, transactGet, query, scan command's options.
get can return anything.
get will not be called if attribute doesn't exists in stored Item.
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
moderator: Boolean,
adress: {
type: Object,
fields: {
country: String,
city: String
},
get: (self: Record<string, any>, item: Record<string, any>, getterInfo?: any)=> {
if(getterInfo?.someCondition) {
return `${self.city}, ${self.country}`
}
return self
}
}
} as const);
- validate
validate option allows you to manually validate provided value in put and update commands.
To return an error you should return a string which explains value invalidity. Any other returned value is considered as valid.
import { Schema } from "dynamoql";
import { randomUUID } from "crypto";
const userSchema = new Schema({
id: {
type: String,
primaryIndex: true,
default: randomUUID
},
moderator: Boolean,
adress: {
type: Object,
fields: {
country: String,
city: String
},
validate: (self: number)=> {
if(checkForsomeCondition(self)) {
return "some error message."
}
}
}
} as const);
- description
add any information to the Schema for your personal usage.
Condition expression
Condition expression are not part of Schema but they are based on your defined Schema.
They are used in various DynamoDB operations to check for some condition(s).
DynamoQL supports all DynamoDB Condition expression.
- equals
{
adress: {
$eq: {
country: "France",
city: "Paris"
}
}
}
Unlike other DynamoQL types there is not a shorthand version of $eq for Object type.
'shorthand' version will apply Condition expression on nested object keys individually which may lead to unexpected behaviour.
- not equals
{
adress: {
$neq: {
country: "France",
city: "Paris"
}
}
}
- attribute exists
$exists can be true or false.
{
adress: {
$exists: true
}
}
- attribute type
Checks for stored attribute type.
{
adress: {
$type: Object
}
}
$type can be String, Number, Boolean, Null, Buffer, Object, Array, or {type: Set, items: String | Number | Buffer }
- object keys length
Checks for stored object keys length.
{
adress: {
$size: 1
}
}
$size can also be any valid numeric comparison operator.
{
adress: {
$size: {
$gt: 0
}
}
}
Possible operators are $eq, $neq, $gt, $gte, $lt, $lte, $in, $between.
- nested object conditions
Sometimes we need to verify a condition on a specific property of an object.
Accessing a property is possible with 2 styles.
DynamoDB style
{
"adress.city": "Paris"
}
DynamoQL style
{
adress: {
city: "Paris"
}
}
Please refer to your defined Object fields attribute type for more condition.
In our example it will be String
- AND
Checks for multiple conditions. Condition is valid if ALL specified conditions are satisfied.
{
adress: {
$and: [
{
$size: 2
},
{
city: "Paris"
}
]
}
}
shorthand style
{
adress: {
$size: 2,
city: "Paris"
}
}
- OR
Checks for multiple conditions. Condition is valid if at least one of specified conditions is satisfied.
{
adress: {
$or: [
{
$size: 3
},
{
city: "Paris"
}
]
}
}
- NOT
Condition is valid if specified condition is NOT satisfied.
{
adress: {
$not: {
city: "Lyon"
}
}
}
$not accepts any Condition expression.
When multiple conditions are provided inside $not: {} they are considered as $and condition.
{
adress: {
$not: {
$size: 2,
city: "Paris"
}
}
}
longhand equivalent is:
{
adress: {
$not: {
$and: [
{
$size: 2
},
{
city: "Paris"
}
]
}
}
}
Update expressions
Like Condition expression, Update expressions are not part of Schema, but they are based on defined Schema.
Update expressions are used in update, transactUpdate and transactWrite operations.
DynamoQL supports all DynamoDB update operations.
- set
$set replaces stored object by provided object.
{
adress: {
$set: {
country: "France",
city: "Paris"
}
}
}
Unlike other DynamoQL types there is not a shorthand version of $set for Object type.
'shorthand' version will apply update operations on nested object keys individually which will lead to a partial update of stored object.
- if not exists
$ifNotExists sets provided object if attribute do not exists in stored item.
$ifNotExists dont affects Condition expression and is attribute specific.
If attribute exists, stored value stays unchanged.
{
adress: {
$ifNotExists: {
country: "France",
city: "Paris"
}
}
}
- remove
remove removes an attribute from stored object.
{
adress: {
$remove: "city"
}
}
It is possible to remove multiple attributes by passing an array of attributes.
{
adress: {
$remove: ["city", "country"]
}
}
You can only remove optionnal attributes.
- update nested object
Using JS dot notation.
{
"adress.city": "Lyon"
}
Using DynamoQL syntax.
{
adress: {
city: "Lyon"
}
}
Please refer to your defined Object fields attribute type for more update operations.
In our example it will be String