serverless-cloud-data-utils
v0.3.6
Published
Utilities for working with serverless cloud data APIs.
Downloads
43
Readme
Utilities for Serverless Data
Utilities for working with serverless cloud data APIs. By default, accessing and modifying data via @serverless/cloud
API revolves around namespaces and key expressions, tracking which can be a headache (imagine a typo in a namespace or a key expression). With serverless-cloud-data-utils
, you can define your models and their indexes (access paths) programmatically, and then access and modify your data in a consistent and type-safe manner.
How to Install
Install via NPM. Note that this library is a wrapper on top of serverless cloud, so it would only work in an environment
where @serverless/cloud
package is installed (and is not a mock), i.e. on serverless cloud apps and instances.
npm i serverless-cloud-data-utils
How to Use
📐 First you need to define your model and its indexes:
// order.model.ts
import { Model, buildIndex, indexBy, timekey } from 'serverless-cloud-data-utils'
//
// Indexes are ways you want to be able to access
// your records.
//
//
// 👉 this is for accessing orders by their id
//
export const OrderId = buildIndex({ namespace: 'orders' })
//
// 👉 this is for accessing orders by their time.
// this is a secondary index, so it needs an explicit label
// (which can be label1-label5)
//
export const OrderTime = buildIndex({
namespace: 'orders',
label: 'label1',
converter: timekey, // --> timestamp strings are illegal by default, this converter takes care of that.
})
//
// 👉 this parametric index allows accessing
// orders of a specific user.
//
export const OrderOwner = owner => buildIndex({
namespace: `orders_${owner.id}`,
label: 'label2',
converter: timekey,
})
export class Order extends Model<Order> {
id: string
owner: User
amount: number
date: string
//
// 👉 this method indicates the indexes of each record
// and how they are mapped to its properties.
// note that you should have only one primary index,
// and the secondary indexes should have distinct
// labels.
//
keys() {
return [
indexBy(OrderTime).exact(this.date),
indexBy(OrderId).exact(this.id),
indexBy(OrderOwner(this.owner)).exact(this.date),
]
}
}
✨ Now you can create and store new objects:
import { Order } from './order.model'
const newOrder = new Order()
newOrder.amount = 42
newOrder.user = someUser
newOrder.date = new Date().toISOString()
newOrder.id = uuid.v4()
await newOrder.save()
✏️ Modify objects:
myOrder.amount += 10
await myOrder.save()
🗑️ Delete objects:
await someOrder.delete()
🎯 Get a specific object:
import { indexBy } from 'serverless-cloud-data-utils'
import { Order, OrderId } from './order.model'
const order = await indexBy(OrderId).exact('some_id').get(Order)
🔍 Or query objects with specific indexes:
import { indexBy } from 'serverless-cloud-data-utils'
import { Order, OrderTime } from './order.model'
//
// fetch last 10 orders
//
const latestOrders = await indexBy(OrderTime)
.limit(10)
.reverse()
.get(Order)
import { indexBy } from 'serverless-cloud-data-utils'
import { Order, OrderOwner } from './order.model'
//
// get orders of a user
// which where issued last month
//
const lastMonth = new Date()
lastMonth.setMonth(lastMonth.getMonth() - 1)
const userOrders = await indexBy(OrderOwner(someUser))
.after(lastMonth)
.reverse()
.get(Order)
📦 Use .clean()
method for sending model data over network:
import { api } from '@serverless/cloud'
import { indexBy } from 'serverless-cloud-data-utils'
import { Order, OrderId } from './order.model'
api.get('/:id', async (req, res) => {
const order = await indexBy(OrderId).exact(req.params.id).get(Order)
if (order) {
res.send(order.clean())
} else {
res.status(404).send()
}
})
🧹 You can also use .clean()
to exclude some fields you don't want to
send to the client:
order.clean(['id', 'owner'])
Formatting
Fields of your models MUST always be camel case, since any data retreived from the database
will be converted into camel case. Conversely, when you call .clean()
, the data is also converted to snake case for transfer over the network.
These rules also apply to nested objects.
Contribution
Feedback and pull requests are more than welcome! Currently the main pressing issues are:
- [ ] Full API documentation
- [ ] Support for metadata
Here are some useful commands for contributing:
npm test # runs all the tests
npm run cov:view # checks the coverage status, try to avoid coverage regression!