@travetto/model
Advanced tools
Comparing version 4.1.3 to 5.0.0-rc.0
{ | ||
"name": "@travetto/model", | ||
"version": "4.1.3", | ||
"version": "5.0.0-rc.0", | ||
"description": "Datastore abstraction for core operations.", | ||
@@ -29,10 +29,10 @@ "keywords": [ | ||
"dependencies": { | ||
"@travetto/config": "^4.1.1", | ||
"@travetto/di": "^4.1.1", | ||
"@travetto/registry": "^4.1.1", | ||
"@travetto/schema": "^4.1.1" | ||
"@travetto/config": "^5.0.0-rc.0", | ||
"@travetto/di": "^5.0.0-rc.0", | ||
"@travetto/registry": "^5.0.0-rc.0", | ||
"@travetto/schema": "^5.0.0-rc.0" | ||
}, | ||
"peerDependencies": { | ||
"@travetto/cli": "^4.1.1", | ||
"@travetto/test": "^4.1.1" | ||
"@travetto/cli": "^5.0.0-rc.0", | ||
"@travetto/test": "^5.0.0-rc.0" | ||
}, | ||
@@ -39,0 +39,0 @@ "peerDependenciesMeta": { |
@@ -175,11 +175,5 @@ <!-- This file was generated by @travetto/doc and should not be modified directly --> | ||
*/ | ||
getStream(location: string): Promise<Readable>; | ||
getStream(location: string, range?: StreamRange): Promise<Readable>; | ||
/** | ||
* Get partial stream from asset store given a starting byte and an optional ending byte | ||
* @param location The location of the stream | ||
*/ | ||
getStreamPartial(location: string, start: number, end?: number): Promise<PartialStream>; | ||
/** | ||
* Get metadata for stream | ||
@@ -235,3 +229,3 @@ * @param location The location of the stream | ||
|[SQL Model Service](https://github.com/travetto/travetto/tree/main/module/model-sql#readme "SQL backing for the travetto model module, with real-time modeling support for SQL schemas.")|X|X|X|X| |X| | ||
|[MemoryModelService](https://github.com/travetto/travetto/tree/main/module/model/src/provider/memory.ts#L53)|X|X|X|X|X|X| | ||
|[MemoryModelService](https://github.com/travetto/travetto/tree/main/module/model/src/provider/memory.ts#L54)|X|X|X|X|X|X| | ||
|[FileModelService](https://github.com/travetto/travetto/tree/main/module/model/src/provider/file.ts#L50)|X|X| |X|X|X| | ||
@@ -245,3 +239,4 @@ | ||
import { Readable } from 'node:stream'; | ||
import { StreamUtil, Class, TimeSpan } from '@travetto/base'; | ||
import { buffer as toBuffer } from 'node:stream/consumers'; | ||
import { Class, TimeSpan } from '@travetto/base'; | ||
import { DeepPartial } from '@travetto/schema'; | ||
@@ -251,3 +246,3 @@ import { Injectable } from '@travetto/di'; | ||
import { ModelCrudSupport } from '../service/crud'; | ||
import { ModelStreamSupport, PartialStream, StreamMeta } from '../service/stream'; | ||
import { ModelStreamSupport, StreamMeta, StreamRange } from '../service/stream'; | ||
import { ModelType, OptionalId } from '../types/model'; | ||
@@ -264,3 +259,3 @@ import { ModelExpirySupport } from '../service/expiry'; | ||
import { ModelStorageUtil } from '../internal/service/storage'; | ||
import { ModelStreamUtil, StreamModel, STREAMS } from '../internal/service/stream'; | ||
import { enforceRange, StreamModel, STREAMS } from '../internal/service/stream'; | ||
import { IndexConfig } from '../registry/types'; | ||
@@ -271,3 +266,3 @@ const STREAM_META = `${STREAMS}_meta`; | ||
export class MemoryModelConfig { | ||
autoCreate?: boolean; | ||
autoCreate?: boolean = true; | ||
namespace?: string; | ||
@@ -310,4 +305,3 @@ cullRate?: number | TimeSpan; | ||
async upsertStream(location: string, input: Readable, meta: StreamMeta): Promise<void>; | ||
async getStream(location: string): Promise<Readable>; | ||
async getStreamPartial(location: string, start: number, end?: number): Promise<PartialStream>; | ||
async getStream(location: string, range?: StreamRange): Promise<Readable>; | ||
async describeStream(location: string): Promise<StreamMeta>; | ||
@@ -314,0 +308,0 @@ async deleteStream(location: string): Promise<void>; |
import crypto from 'node:crypto'; | ||
import { Class, ObjectUtil, Util } from '@travetto/base'; | ||
import { SchemaRegistry, SchemaValidator, ValidationError, ValidationResultError } from '@travetto/schema'; | ||
import { Class, Util } from '@travetto/base'; | ||
import { DataUtil, SchemaRegistry, SchemaValidator, ValidationError, ValidationResultError } from '@travetto/schema'; | ||
@@ -80,3 +80,3 @@ import { ModelRegistry } from '../../registry/model'; | ||
if (ObjectUtil.isPlainObject(item)) { | ||
if (DataUtil.isPlainObject(item)) { | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions | ||
@@ -122,3 +122,3 @@ item = cls.from(item as object); | ||
static async naivePartialUpdate<T extends ModelType>(cls: Class<T>, item: Partial<T>, view: undefined | string, getExisting: () => Promise<T>): Promise<T> { | ||
if (ObjectUtil.isPlainObject(item)) { | ||
if (DataUtil.isPlainObject(item)) { | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions | ||
@@ -125,0 +125,0 @@ item = cls.from(item as object); |
@@ -37,3 +37,3 @@ import { ShutdownManager, Class, TimeSpan, TimeUtil, Util } from '@travetto/base'; | ||
const running = new AbortController(); | ||
const cullInterval = TimeUtil.timeToMs(svc.config?.cullRate ?? '10m'); | ||
const cullInterval = TimeUtil.asMillis(svc.config?.cullRate ?? '10m'); | ||
@@ -40,0 +40,0 @@ ShutdownManager.onGracefulShutdown(async () => running.abort(), this); |
@@ -1,6 +0,22 @@ | ||
import { Class } from '@travetto/base'; | ||
import { AppError, Class } from '@travetto/base'; | ||
import { ModelType } from '../../types/model'; | ||
import { StreamRange } from '../../service/stream'; | ||
class Cls { id: string; } | ||
export const StreamModel: Class<ModelType> = Cls; | ||
export const STREAMS = '_streams'; | ||
export const STREAMS = '_streams'; | ||
/** | ||
* Enforce byte range for stream stream/file of a certain size | ||
*/ | ||
export function enforceRange({ start, end }: StreamRange, size: number): Required<StreamRange> { | ||
end = Math.min(end ?? size - 1, size - 1); | ||
if (Number.isNaN(start) || Number.isNaN(end) || !Number.isFinite(start) || start >= size || start < 0 || start > end) { | ||
throw new AppError('Invalid position, out of range', 'data'); | ||
} | ||
return { start, end }; | ||
} |
import fs from 'node:fs/promises'; | ||
import { createReadStream } from 'node:fs'; | ||
import { createReadStream, createWriteStream } from 'node:fs'; | ||
import os from 'node:os'; | ||
import { Readable } from 'node:stream'; | ||
import { pipeline } from 'node:stream/promises'; | ||
import path from 'node:path'; | ||
import { path, RuntimeContext } from '@travetto/manifest'; | ||
import { StreamUtil, Class, TimeSpan } from '@travetto/base'; | ||
import { RuntimeContext } from '@travetto/manifest'; | ||
import { Class, TimeSpan } from '@travetto/base'; | ||
import { Injectable } from '@travetto/di'; | ||
@@ -15,3 +15,3 @@ import { Config } from '@travetto/config'; | ||
import { ModelCrudSupport } from '../service/crud'; | ||
import { ModelStreamSupport, PartialStream, StreamMeta } from '../service/stream'; | ||
import { ModelStreamSupport, StreamMeta, StreamRange } from '../service/stream'; | ||
import { ModelType, OptionalId } from '../types/model'; | ||
@@ -25,3 +25,3 @@ import { ModelExpirySupport } from '../service/expiry'; | ||
import { ExistsError } from '../error/exists'; | ||
import { StreamModel, STREAMS } from '../internal/service/stream'; | ||
import { enforceRange, StreamModel, STREAMS } from '../internal/service/stream'; | ||
@@ -117,3 +117,3 @@ type Suffix = '.bin' | '.meta' | '.json' | '.expires'; | ||
if (await exists(file)) { | ||
const content = await StreamUtil.streamToBuffer(createReadStream(file)); | ||
const content = await fs.readFile(file); | ||
return this.checkExpiry(cls, await ModelCrudUtil.load(cls, content)); | ||
@@ -186,3 +186,3 @@ } | ||
await Promise.all([ | ||
StreamUtil.writeToFile(input, file), | ||
await pipeline(input, createWriteStream(file)), | ||
fs.writeFile(file.replace(BIN, META), JSON.stringify(meta), 'utf8') | ||
@@ -192,20 +192,14 @@ ]); | ||
async getStream(location: string): Promise<Readable> { | ||
async getStream(location: string, range?: StreamRange): Promise<Readable> { | ||
const file = await this.#find(STREAMS, BIN, location); | ||
return createReadStream(file); | ||
if (range) { | ||
const meta = await this.describeStream(location); | ||
range = enforceRange(range, meta.size); | ||
} | ||
return createReadStream(file, range); | ||
} | ||
async getStreamPartial(location: string, start: number, end?: number): Promise<PartialStream> { | ||
const file = await this.#find(STREAMS, BIN, location); | ||
const meta = await this.describeStream(location); | ||
[start, end] = StreamUtil.enforceRange(start, end, meta.size); | ||
const stream = createReadStream(file, { start, end }); | ||
return { stream, range: [start, end] }; | ||
} | ||
async describeStream(location: string): Promise<StreamMeta> { | ||
const file = await this.#find(STREAMS, META, location); | ||
const content = await StreamUtil.streamToBuffer(createReadStream(file)); | ||
const content = await fs.readFile(file); | ||
const text: StreamMeta = JSON.parse(content.toString('utf8')); | ||
@@ -212,0 +206,0 @@ return text; |
import { Readable } from 'node:stream'; | ||
import { buffer as toBuffer } from 'node:stream/consumers'; | ||
import { StreamUtil, Class, TimeSpan } from '@travetto/base'; | ||
import { Class, TimeSpan } from '@travetto/base'; | ||
import { DeepPartial } from '@travetto/schema'; | ||
@@ -9,3 +10,3 @@ import { Injectable } from '@travetto/di'; | ||
import { ModelCrudSupport } from '../service/crud'; | ||
import { ModelStreamSupport, PartialStream, StreamMeta } from '../service/stream'; | ||
import { ModelStreamSupport, StreamMeta, StreamRange } from '../service/stream'; | ||
import { ModelType, OptionalId } from '../types/model'; | ||
@@ -22,3 +23,3 @@ import { ModelExpirySupport } from '../service/expiry'; | ||
import { ModelStorageUtil } from '../internal/service/storage'; | ||
import { StreamModel, STREAMS } from '../internal/service/stream'; | ||
import { enforceRange, StreamModel, STREAMS } from '../internal/service/stream'; | ||
import { IndexConfig } from '../registry/types'; | ||
@@ -249,20 +250,15 @@ | ||
metaContent.set(location, Buffer.from(JSON.stringify(meta))); | ||
streams.set(location, await StreamUtil.streamToBuffer(input)); | ||
streams.set(location, await toBuffer(input)); | ||
} | ||
async getStream(location: string): Promise<Readable> { | ||
async getStream(location: string, range?: StreamRange): Promise<Readable> { | ||
const streams = this.#find(STREAMS, location, 'notfound'); | ||
return StreamUtil.bufferToStream(streams.get(location)!); | ||
let buffer = streams.get(location)!; | ||
if (range) { | ||
range = enforceRange(range, buffer.length); | ||
buffer = buffer.subarray(range.start, range.end! + 1); | ||
} | ||
return Readable.from(buffer); | ||
} | ||
async getStreamPartial(location: string, start: number, end?: number): Promise<PartialStream> { | ||
const streams = this.#find(STREAMS, location, 'notfound'); | ||
const buffer = streams.get(location)!; | ||
[start, end] = StreamUtil.enforceRange(start, end, buffer.length); | ||
const stream = await StreamUtil.bufferToStream(buffer.subarray(start, end + 1)); | ||
return { stream, range: [start, end] }; | ||
} | ||
async describeStream(location: string): Promise<StreamMeta> { | ||
@@ -269,0 +265,0 @@ const metaContent = this.#find(STREAM_META, location, 'notfound'); |
@@ -1,2 +0,3 @@ | ||
import { Primitive, Class } from '@travetto/base'; | ||
import { Class } from '@travetto/base'; | ||
import { Primitive } from '@travetto/schema'; | ||
@@ -3,0 +4,0 @@ import { ModelType } from '../types/model'; |
@@ -47,3 +47,3 @@ import { Class, AppError } from '@travetto/base'; | ||
errors: errors.map(x => { | ||
const { message, type, errors: subErrors, details } = x.error; | ||
const { message, type, details: { errors: subErrors } = {}, details } = x.error; | ||
return { message, type, errors: subErrors ?? details, idx: x.idx }; | ||
@@ -50,0 +50,0 @@ }) |
@@ -38,6 +38,3 @@ import { Readable } from 'node:stream'; | ||
export interface PartialStream { | ||
stream: Readable; | ||
range: [number, number]; | ||
} | ||
export type StreamRange = { start: number, end?: number }; | ||
@@ -63,11 +60,5 @@ /** | ||
*/ | ||
getStream(location: string): Promise<Readable>; | ||
getStream(location: string, range?: StreamRange): Promise<Readable>; | ||
/** | ||
* Get partial stream from asset store given a starting byte and an optional ending byte | ||
* @param location The location of the stream | ||
*/ | ||
getStreamPartial(location: string, start: number, end?: number): Promise<PartialStream>; | ||
/** | ||
* Get metadata for stream | ||
@@ -74,0 +65,0 @@ * @param location The location of the stream |
@@ -26,7 +26,7 @@ import assert from 'node:assert'; | ||
async wait(n: number | TimeSpan) { | ||
await timers.setTimeout(TimeUtil.timeToMs(n) * this.delayFactor); | ||
await timers.setTimeout(TimeUtil.asMillis(n) * this.delayFactor); | ||
} | ||
timeFromNow(v: number | TimeSpan, unit?: TimeUnit) { | ||
return new Date(Date.now() + TimeUtil.timeToMs(v, unit) * this.delayFactor); | ||
return TimeUtil.fromNow(TimeUtil.asMillis(v, unit) * this.delayFactor); | ||
} | ||
@@ -33,0 +33,0 @@ |
@@ -152,5 +152,5 @@ import assert from 'node:assert'; | ||
await service.create(User4, User4.from({ child: { name: 'bob', age: 40 }, createdDate: TimeUtil.timeFromNow('3d'), color: 'blue' })); | ||
await service.create(User4, User4.from({ child: { name: 'bob', age: 30 }, createdDate: TimeUtil.timeFromNow('2d'), color: 'red' })); | ||
await service.create(User4, User4.from({ child: { name: 'bob', age: 50 }, createdDate: TimeUtil.timeFromNow('-1d'), color: 'green' })); | ||
await service.create(User4, User4.from({ child: { name: 'bob', age: 40 }, createdDate: TimeUtil.fromNow('3d'), color: 'blue' })); | ||
await service.create(User4, User4.from({ child: { name: 'bob', age: 30 }, createdDate: TimeUtil.fromNow('2d'), color: 'red' })); | ||
await service.create(User4, User4.from({ child: { name: 'bob', age: 50 }, createdDate: TimeUtil.fromNow('-1d'), color: 'green' })); | ||
@@ -157,0 +157,0 @@ const arr = await this.toArray(service.listByIndex(User4, 'nameCreated', { child: { name: 'bob' } })); |
@@ -6,8 +6,9 @@ import fs from 'node:fs/promises'; | ||
import { pipeline } from 'node:stream/promises'; | ||
import { buffer as toBuffer } from 'node:stream/consumers'; | ||
import { Suite, Test, TestFixtures } from '@travetto/test'; | ||
import { StreamUtil } from '@travetto/base'; | ||
import { BaseModelSuite } from './base'; | ||
import { ModelStreamSupport } from '../../src/service/stream'; | ||
import { enforceRange } from '../../src/internal/service/stream'; | ||
@@ -80,30 +81,32 @@ @Suite() | ||
const retrieved = await service.getStream(meta.hash); | ||
const content = (await StreamUtil.toBuffer(retrieved)).toString('utf8'); | ||
const content = (await toBuffer(retrieved)).toString('utf8'); | ||
assert(content.startsWith('abc')); | ||
assert(content.endsWith('xyz')); | ||
const partial = await service.getStreamPartial(meta.hash, 10, 20); | ||
const subContent = (await StreamUtil.toBuffer(partial.stream)).toString('utf8'); | ||
assert(subContent.length === (partial.range[1] - partial.range[0]) + 1); | ||
const partial = await service.getStream(meta.hash, { start: 10, end: 20 }); | ||
const subContent = (await toBuffer(partial)).toString('utf8'); | ||
const range = await enforceRange({ start: 10, end: 20 }, meta.size); | ||
assert(subContent.length === (range.end - range.start) + 1); | ||
assert(subContent === 'klmnopqrstu'); | ||
const partialUnbounded = await service.getStreamPartial(meta.hash, 10); | ||
const subContent2 = (await StreamUtil.toBuffer(partialUnbounded.stream)).toString('utf8'); | ||
assert(subContent2.length === (partialUnbounded.range[1] - partialUnbounded.range[0]) + 1); | ||
const partialUnbounded = await service.getStream(meta.hash, { start: 10 }); | ||
const subContent2 = (await toBuffer(partialUnbounded)).toString('utf8'); | ||
const range2 = await enforceRange({ start: 10 }, meta.size); | ||
assert(subContent2.length === (range2.end - range2.start) + 1); | ||
assert(subContent2.startsWith('klm')); | ||
assert(subContent2.endsWith('xyz')); | ||
const partialSingle = await service.getStreamPartial(meta.hash, 10, 10); | ||
const subContent3 = (await StreamUtil.toBuffer(partialSingle.stream)).toString('utf8'); | ||
const partialSingle = await service.getStream(meta.hash, { start: 10, end: 10 }); | ||
const subContent3 = (await toBuffer(partialSingle)).toString('utf8'); | ||
assert(subContent3.length === 1); | ||
assert(subContent3 === 'k'); | ||
const partialOverbounded = await service.getStreamPartial(meta.hash, 20, 40); | ||
const subContent4 = (await StreamUtil.toBuffer(partialOverbounded.stream)).toString('utf8'); | ||
const partialOverbounded = await service.getStream(meta.hash, { start: 20, end: 40 }); | ||
const subContent4 = (await toBuffer(partialOverbounded)).toString('utf8'); | ||
assert(subContent4.length === 6); | ||
assert(subContent4.endsWith('xyz')); | ||
await assert.rejects(() => service.getStreamPartial(meta.hash, -10, 10)); | ||
await assert.rejects(() => service.getStreamPartial(meta.hash, 30, 37)); | ||
await assert.rejects(() => service.getStream(meta.hash, { start: -10, end: 10 })); | ||
await assert.rejects(() => service.getStream(meta.hash, { start: 30, end: 37 })); | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2999
161304
1
414
+ Added@travetto/cli@5.0.16(transitive)
+ Added@travetto/config@5.0.13(transitive)
+ Added@travetto/di@5.0.13(transitive)
+ Added@travetto/manifest@5.0.9(transitive)
+ Added@travetto/registry@5.0.13(transitive)
+ Added@travetto/runtime@5.0.13(transitive)
+ Added@travetto/schema@5.0.13(transitive)
+ Added@travetto/terminal@5.0.15(transitive)
+ Added@travetto/test@5.0.15(transitive)
+ Added@travetto/worker@5.0.15(transitive)
+ Added@types/node@22.10.1(transitive)
+ Addedundici-types@6.20.0(transitive)
+ Addedyaml@2.6.1(transitive)
- Removed@travetto/base@4.1.2(transitive)
- Removed@travetto/cli@4.1.2(transitive)
- Removed@travetto/config@4.1.2(transitive)
- Removed@travetto/di@4.1.1(transitive)
- Removed@travetto/manifest@4.1.0(transitive)
- Removed@travetto/registry@4.1.2(transitive)
- Removed@travetto/schema@4.1.1(transitive)
- Removed@travetto/terminal@4.1.1(transitive)
- Removed@travetto/test@4.1.1(transitive)
- Removed@travetto/worker@4.1.1(transitive)
- Removed@travetto/yaml@4.1.1(transitive)
- Removed@types/node@20.17.9(transitive)
- Removedundici-types@6.19.8(transitive)
Updated@travetto/config@^5.0.0-rc.0
Updated@travetto/di@^5.0.0-rc.0
Updated@travetto/schema@^5.0.0-rc.0