Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/prashaantt/tiny-orm
A super tiny ORM for TypeScript.
https://github.com/prashaantt/tiny-orm
joi typescript validation
Last synced: 10 days ago
JSON representation
A super tiny ORM for TypeScript.
- Host: GitHub
- URL: https://github.com/prashaantt/tiny-orm
- Owner: prashaantt
- License: mit
- Created: 2016-12-27T16:04:33.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2017-01-01T20:35:07.000Z (about 8 years ago)
- Last Synced: 2024-04-26T20:21:27.576Z (10 months ago)
- Topics: joi, typescript, validation
- Language: TypeScript
- Homepage:
- Size: 59.6 KB
- Stars: 2
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# tiny-orm
> A super tiny ORM for TypeScript.`tiny-orm` lets you
- auto-validate TypeScript classes using [Joi](https://github.com/hapijs/joi).
- access snake_cased DB objects through camelCased JavaScript objects.
- compose simple classes together to model more complex structures.# Installation
```bash
$ npm install tiny-orm
```# Usage
## Basic
At its simplest, any class properties can be decorated with a Joi schema like so:
```ts
class User extends TinyORM<{}> {
@prop(Joi.number().min(1)) // prop decorator for valid id
id: number;@prop(Joi.string().email()) // prop decorator for valid email
email: string;@prop() // no runtime validation specified, only static string validation will apply
name: string;constructor(id: number, email: string, name: string) {
super();this.id = id;
this.email = email;
this.name = name;
}
}const user = new User(1, '[email protected]', 'John Doe');
user.validate(); // okuser.id = 0;
user.validate(); // throws `User.id must be larger than or equal to 1`
```The same example can be enhanced to auto-validate upon each mutation:
```ts
@strict // validate() will be automatically called
class User extends TinyORM<{}> {
@prop(Joi.string().email())
email: string;constructor(email: string) {
super();
this.email = email;
}
}const user = new User('[email protected]'); // validates without errors
user.email = 'abc' ; // throws `User.email must be a valid email`
```## Advanced
### Better static typing
Get stronger static typing by supplying an interface:
```ts
interface IUser {
id: number;
email: string;
}@strict
class User extends TinyORM implements IUser {
@prop(Joi.number().min(1))
id: number;@prop(Joi.string().email())
email: string;// constructor no longer necessary
}// props to constructor are available through the IUser interface for auto-completion
const user = new User({
id: 1,
email: '[email protected]'
});
```### `getInstance`
Normalise data from an arbitrary_source (such as a database) to an interface with camelCased properties:
```ts
interface IUser {
userId: number;
userEmail: string;
}@strict
class User extends TinyORM implements IUser {
@prop(Joi.number().min(1))
userId: number;@prop(Joi.string().email())
userEmail: string;
}const pgData = {
user_id: 1,
user_email: '[email protected]'
}const user = User.getInstance(pgData) as User; // init object by calling the static getInstance method
user.userId === pgData.user_id;
user.userEmail === pgData.user_email;
```### `toObject`, `toDbObject` and `toString`
Get a validated object structure just with all the `@prop`s:
```ts
interface IUser {
userId: number;
userEmail: string;
}@strict
class User extends TinyORM implements IUser {
@prop(Joi.number().min(1))
userId: number;@prop(Joi.string().email())
userEmail: string;someUtilityFunction() {
return this.userId + ': ' + this.userEmail;
}
}const user = new User({
userId: 1,
userEmail: '[email protected]'
});user.someUtilityFunction(); // 1: [email protected]
user.toObject(); // { userId: 1, userEmail: '[email protected]' }
user.toDbObject(); // { user_id: 1, user_email: '[email protected]' }
user.toString(); // overridden method to get JSON representation of .toObject()
```# Composition
This is left to your imagination. Please note, however, that it's not possible to validate nested objects if they are not directly created using `TinyORM`. This applies especially to nested objects created via the `getInstance` method.
```ts
// Define interfacesinterface IPost {
id: string;
title: string;
createdAt: string;
comments?: IComment[];
}interface IComment {
id: string;
body: string;
children?: IComment[];
}// Declare classes with validation code
@strict
class Post extends TinyORM implements IPost {
@prop(Joi.string().guid())
id: string;@prop()
title: string;@prop(Joi.date().iso())
createdAt: string;@prop(Joi.array())
comments?: IComment[];
}@strict
class Comment extends TinyORM implements IComment {
@prop(Joi.string().guid())
id: string;@prop(Joi.string().min(5))
body: string;@prop(Joi.array())
children?: IComment[];
}// Create an object using the Post and Comment constructors. These will be fully validated.
let post = new Post({
id: '3ed44ac2-4dd8-4a2a-9aaa-879e4a44148f',
title: 'The blog post',
createdAt: new Date().toISOString(),
comments: [
new Comment({
id: '3ed44ac2-4dd8-4a2a-9aaa-879e4a44148b',
body: 'First!',
children: [
new Comment({
id: '3ed44ac2-4dd8-4a2a-9aaa-879e4a44148d',
body: 'Second!'
})
]
})
]
});// Or create the object using statically typed object notation.
// Anything below Post will not be validated by default.post = new Post({
id: '3ed44ac2-4dd8-4a2a-9aaa-879e4a44148f',
title: 'The blog post',
createdAt: new Date().toISOString(),
comments: [
{
id: '3ed44ac2-4dd8-4a2a-9aaa-879e4a44148b',
body: 'First!',
children: [
{
id: '3ed44ac2-4dd8-4a2a-9aaa-879e4a44148d',
body: 'Second!'
}
]
}
]
});// Or use getInstance. Only Post will be validated.
post = Post.getInstance({
id: '3ed44ac2-4dd8-4a2a-9aaa-879e4a44148f',
title: 'The blog post',
created_at: new Date().toISOString(),
comments: [
{
id: '3ed44ac2-4dd8-4a2a-9aaa-879e4a44148b',
body: 'First!',
children: [
{
id: '3ed44ac2-4dd8-4a2a-9aaa-879e4a44148d',
body: 'Second!'
}
]
}
]
}) as Post;// In all these cases (assuming strictNullChecks is temporarily disabled :)):
post.toObject().comments[0].children[0].body === 'Second!';
```