Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@travetto/model

Package Overview
Dependencies
Maintainers
1
Versions
371
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@travetto/model - npm Package Compare versions

Comparing version 3.3.3 to 3.3.4

8

package.json
{
"name": "@travetto/model",
"version": "3.3.3",
"version": "3.3.4",
"description": "Datastore abstraction for core operations.",

@@ -29,9 +29,9 @@ "keywords": [

"dependencies": {
"@travetto/config": "^3.3.3",
"@travetto/config": "^3.3.4",
"@travetto/di": "^3.3.3",
"@travetto/registry": "^3.3.3",
"@travetto/schema": "^3.3.3"
"@travetto/schema": "^3.3.4"
},
"peerDependencies": {
"@travetto/cli": "^3.3.4",
"@travetto/cli": "^3.3.5",
"@travetto/test": "^3.3.4"

@@ -38,0 +38,0 @@ },

@@ -219,14 +219,6 @@ <!-- This file was generated by @travetto/doc and should not be modified directly -->

id: string;
/**
* Run before saving
*/
prePersist?(): void | Promise<void>;
/**
* Run after loading
*/
postLoad?(): void | Promise<void>;
}
```
All fields are optional, but the `id` and `type` are important as those field types are unable to be changed. This may make using existing data models impossible if types other than strings are required. Additionally, the type field, is intended to record the base model type and cannot be remapped. This is important to support polymorphism, not only in [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations."), but also in [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.").
The `id` is the only required field for a model, as this is a hard requirement on naming and type. This may make using existing data models impossible if types other than strings are required. Additionally, the `type` field, is intended to record the base model type, but can be remapped. This is important to support polymorphism, not only in [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations."), but also in [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.").

@@ -233,0 +225,0 @@ ## Implementations

@@ -11,2 +11,3 @@ import crypto from 'crypto';

import { SubTypeNotSupportedError } from '../../error/invalid-sub-type';
import { DataHandler } from '../../registry/types';

@@ -66,6 +67,3 @@ export type ModelCrudProvider = {

if (result.postLoad) {
await result.postLoad();
}
return result;
return this.postLoad(cls, result);
}

@@ -95,5 +93,3 @@

if (item.prePersist) {
await item.prePersist();
}
item = await this.prePersist(cls, item);

@@ -147,5 +143,3 @@ let errors: ValidationError[] = [];

if (item.prePersist) {
await item.prePersist();
}
item = await this.prePersist(cls, item);

@@ -164,2 +158,32 @@ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions

}
/**
* Pre persist behavior
*/
static async prePersist<T>(cls: Class<T>, item: T): Promise<T> {
const config = ModelRegistry.get(cls);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
for (const handler of (config.prePersist ?? []) as unknown as DataHandler<T>[]) {
item = await handler(item) ?? item;
}
if (typeof item === 'object' && item && 'prePersist' in item && typeof item['prePersist'] === 'function') {
item = await item.prePersist() ?? item;
}
return item;
}
/**
* Post load behavior
*/
static async postLoad<T>(cls: Class<T>, item: T): Promise<T> {
const config = ModelRegistry.get(cls);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
for (const handler of (config.postLoad ?? []) as unknown as DataHandler<T>[]) {
item = await handler(item) ?? item;
}
if (typeof item === 'object' && item && 'postLoad' in item && typeof item['postLoad'] === 'function') {
item = await item.postLoad() ?? item;
}
return item;
}
}

@@ -6,3 +6,3 @@ import { Class } from '@travetto/base';

import { ModelRegistry } from './model';
import { IndexConfig, ModelOptions } from './types';
import { DataHandler, IndexConfig, ModelOptions } from './types';

@@ -44,2 +44,41 @@ /**

};
}
/**
* Model class decorator for pre-persist behavior
*/
export function PrePersist<T>(handler: DataHandler<T>) {
return function (tgt: Class<T>): void {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
ModelRegistry.registerDataHandlers(tgt, { prePersist: [handler as DataHandler] });
};
}
/**
* Model field decorator for pre-persist value setting
*/
export function PersistValue<T>(handler: (curr: T | undefined) => T) {
return function <K extends string, C extends Partial<Record<K, T>>>(tgt: C, prop: K): void {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
ModelRegistry.registerDataHandlers(tgt.constructor as Class<C>, {
prePersist: [
(inst): void => {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const cInst = (inst as unknown as Record<K, T>);
cInst[prop] = handler(cInst[prop]);
}
]
});
};
}
/**
* Model class decorator for post-load behavior
*/
export function PostLoad<T>(handler: DataHandler<T>) {
return function (tgt: Class<T>): void {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
ModelRegistry.registerDataHandlers(tgt, { postLoad: [handler as DataHandler] });
};
}

@@ -55,5 +55,14 @@ import { RootIndex } from '@travetto/manifest';

createPending(cls: Class): Partial<ModelOptions<ModelType>> {
return { class: cls, indices: [], autoCreate: true, baseType: RootIndex.getFunctionMetadata(cls)?.abstract };
return { class: cls, indices: [], autoCreate: true, baseType: RootIndex.getFunctionMetadata(cls)?.abstract, postLoad: [], prePersist: [] };
}
registerDataHandlers(cls: Class, pConfig?: Partial<ModelOptions<ModelType>>): void {
const cfg = this.getOrCreatePending(cls);
this.register(cls, {
...cfg,
prePersist: [...cfg.prePersist ?? [], ...pConfig?.prePersist ?? []],
postLoad: [...cfg.postLoad ?? [], ...pConfig?.postLoad ?? []],
});
}
onInstallFinalize(cls: Class): ModelOptions<ModelType> {

@@ -70,2 +79,12 @@ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions

delete view[schema.subTypeField].required; // Allow type to be optional
let parent = this.getParentClass(cls);
let from = cls;
// Merge inherited prepersist/postload
while (parent && from !== parent) {
const pCfg = this.get(parent);
config.prePersist = [...pCfg.prePersist ?? [], ...config.prePersist ?? []];
config.postLoad = [...pCfg.postLoad ?? [], ...config.postLoad ?? []];
from = parent;
parent = this.getParentClass(from);
}
}

@@ -72,0 +91,0 @@ return config;

@@ -24,2 +24,4 @@ import { Primitive, Class } from '@travetto/base';

export type DataHandler<T = unknown> = (inst: T) => (Promise<T | void> | T | void);
/**

@@ -61,2 +63,10 @@ * Model options

autoCreate: boolean;
/**
* Pre-persist handlers
*/
prePersist?: DataHandler<unknown>[];
/**
* Post-load handlers
*/
postLoad?: DataHandler<unknown>[];
}

@@ -63,0 +73,0 @@

@@ -16,12 +16,4 @@ /**

id: string;
/**
* Run before saving
*/
prePersist?(): void | Promise<void>;
/**
* Run after loading
*/
postLoad?(): void | Promise<void>;
}
export type OptionalId<T extends { id: string }> = Omit<T, 'id'> & { id?: string };

@@ -49,2 +49,6 @@ import assert from 'assert';

name: string;
prePersist() {
this.name = `${this.name}-suff`;
}
}

@@ -179,2 +183,3 @@

assert(o.address === undefined);
assert(o.name === 'bob-suff');

@@ -181,0 +186,0 @@ await service.updatePartial(User2, User2.from({

@@ -51,9 +51,5 @@ import assert from 'assert';

id: string;
createdDate?: Date;
createdDate?: Date = new Date();
color: string;
child: Child;
prePersist?() {
this.createdDate ??= new Date();
}
}

@@ -161,3 +157,3 @@

const arr = await this.toArray(service.listByIndex(User4, 'nameCreated', User4.from({ child: { name: 'bob' } })));
const arr = await this.toArray(service.listByIndex(User4, 'nameCreated', { child: { name: 'bob' } }));

@@ -164,0 +160,0 @@ assert(arr[0].color === 'green' && arr[0].child.name === 'bob' && arr[0].child.age === 50);

@@ -5,6 +5,6 @@ import assert from 'assert';

import { Suite, Test } from '@travetto/test';
import { Text, TypeMismatchError } from '@travetto/schema';
import { SubTypeField, Text, TypeMismatchError } from '@travetto/schema';
import {
ModelIndexedSupport, Index, ModelCrudSupport, Model,
NotFoundError, SubTypeNotSupportedError
NotFoundError, SubTypeNotSupportedError, PersistValue
} from '@travetto/model';

@@ -20,11 +20,10 @@

id: string;
type: string;
@SubTypeField()
_type: string;
@Text()
name: string;
age?: number;
@PersistValue(() => new Date())
updatedDate?: Date;
prePersist() {
this.updatedDate = new Date();
}
}

@@ -31,0 +30,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc