Skip to content

Commit

Permalink
StorageMeta Type Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
arietrouw committed Jan 2, 2025
1 parent 56fec3f commit 902dec2
Show file tree
Hide file tree
Showing 14 changed files with 163 additions and 137 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import { PayloadDivinerQuerySchema } from '@xyo-network/diviner-payload-model'
import { MemoryNode } from '@xyo-network/node-memory'
import { PayloadBuilder } from '@xyo-network/payload-builder'
import {
isSequenceMeta, type Payload,
isSequenceStorageMeta, type Payload,
SequenceConstants,
type WithSequenceMeta,
type WithSequenceStorageMeta,
type WithStorageMeta,
} from '@xyo-network/payload-model'
import {
Expand Down Expand Up @@ -102,8 +102,8 @@ describe('MemoryPayloadDiviner', () => {
.build()
const results = await sut.divine([query])
expect(results.length).toBeGreaterThan(0)
expect(results.every(isSequenceMeta)).toBeTruthy()
expect((results.filter(isSequenceMeta) as WithSequenceMeta[]).every(result => result._sequence > cursor)).toBe(true)
expect(results.every(isSequenceStorageMeta)).toBeTruthy()
expect((results.filter(isSequenceStorageMeta) as WithSequenceStorageMeta[]).every(result => result._sequence > cursor)).toBe(true)
})
it.skip('returns payloads equal to the supplied sequence (not a thing with _sequence)', async () => {
const cursor = insertedPayloads.sort()[1]._sequence
Expand All @@ -112,8 +112,8 @@ describe('MemoryPayloadDiviner', () => {
.build()
const results = await sut.divine([query])
expect(results.length).toBeGreaterThan(0)
expect(results.every(isSequenceMeta)).toBeTruthy()
expect((results.filter(isSequenceMeta) as WithSequenceMeta[]).every(result => result._sequence !== cursor)).toBe(true)
expect(results.every(isSequenceStorageMeta)).toBeTruthy()
expect((results.filter(isSequenceStorageMeta) as WithSequenceStorageMeta[]).every(result => result._sequence !== cursor)).toBe(true)
})
})
describe('desc', () => {
Expand All @@ -125,8 +125,8 @@ describe('MemoryPayloadDiviner', () => {
.build()
const results = await sut.divine([query])
expect(results.length).toBeGreaterThan(0)
expect(results.every(isSequenceMeta)).toBeTruthy()
expect((results.filter(isSequenceMeta) as WithSequenceMeta[]).every(result => result._sequence < cursor)).toBe(true)
expect(results.every(isSequenceStorageMeta)).toBeTruthy()
expect((results.filter(isSequenceStorageMeta) as WithSequenceStorageMeta[]).every(result => result._sequence < cursor)).toBe(true)
})
it.skip('returns payloads equal to the supplied sequence (not a thing with _sequence)', async () => {
const cursor = insertedPayloads.sort()[0]._sequence
Expand All @@ -135,8 +135,8 @@ describe('MemoryPayloadDiviner', () => {
.build()
const results = await sut.divine([query])
expect(results.length).toBeGreaterThan(0)
expect(results.every(isSequenceMeta)).toBe(true)
expect((results.filter(isSequenceMeta) as WithSequenceMeta[]).every(result => result._sequence !== cursor)).toBe(true)
expect(results.every(isSequenceStorageMeta)).toBe(true)
expect((results.filter(isSequenceStorageMeta) as WithSequenceStorageMeta[]).every(result => result._sequence !== cursor)).toBe(true)
})
})
})
Expand All @@ -147,8 +147,8 @@ describe('MemoryPayloadDiviner', () => {
const query = new PayloadBuilder<PayloadDivinerQueryPayload>({ schema: PayloadDivinerQuerySchema }).fields({ cursor }).build()
const results = await sut.divine([query])
expect(results.length).toBeGreaterThan(0)
expect(results.every(isSequenceMeta)).toBe(true)
expect((results.filter(isSequenceMeta) as WithSequenceMeta[]).every(result => result._sequence !== cursor)).toBe(true)
expect(results.every(isSequenceStorageMeta)).toBe(true)
expect((results.filter(isSequenceStorageMeta) as WithSequenceStorageMeta[]).every(result => result._sequence !== cursor)).toBe(true)
}
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
type Sequence,
SequenceComparer,
SequenceParser,
type WithHashMeta,
type WithHashStorageMeta,
type WithOnlyClientMeta,
type WithOptionalSchema,
type WithoutClientMeta,
Expand Down Expand Up @@ -224,9 +224,9 @@ export class PayloadBuilder<T extends Payload = Payload<AnyObject>, R = T> {
return result
}

private static async addHashMeta<T extends Payload>(payload: T): Promise<WithHashMeta<T>>
private static async addHashMeta<T extends Payload>(payloads: T[]): Promise<WithHashMeta<T>[]>
private static async addHashMeta<T extends Payload>(payloads: T | T[]): Promise<WithHashMeta<T>[] | WithHashMeta<T>> {
private static async addHashMeta<T extends Payload>(payload: T): Promise<WithHashStorageMeta<T>>
private static async addHashMeta<T extends Payload>(payloads: T[]): Promise<WithHashStorageMeta<T>[]>
private static async addHashMeta<T extends Payload>(payloads: T | T[]): Promise<WithHashStorageMeta<T>[] | WithHashStorageMeta<T>> {
if (Array.isArray(payloads)) {
return await Promise.all(
payloads.map(async (payload) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { type Hash, isHash } from '@xylabs/hex'
import { AsObjectFactory } from '@xylabs/object'

import type { Payload } from '../Payload.ts'

export interface DataHashStorageMeta {
_dataHash: Hash
}

export type WithDataHashStorageMeta<T extends Payload = Payload> = T & DataHashStorageMeta
export type WithPartialDataHashStorageMeta<T extends Payload = Payload> = Partial<WithDataHashStorageMeta<T>>

export const isDataHashStorageMeta = (value: unknown): value is DataHashStorageMeta => {
return isHash((value as WithDataHashStorageMeta)?._dataHash)
}

export const asDataHashStorageMeta = AsObjectFactory.create<DataHashStorageMeta>(isDataHashStorageMeta)
export const asOptionalDataHashStorageMeta = AsObjectFactory.createOptional<DataHashStorageMeta>(isDataHashStorageMeta)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { type Hash, isHash } from '@xylabs/hex'
import { AsObjectFactory } from '@xylabs/object'

import type { Payload } from '../Payload.ts'
import { type DataHashStorageMeta, isDataHashStorageMeta } from './DataHash.ts'

export interface HashStorageMeta extends DataHashStorageMeta {
_hash: Hash
}

export type WithHashStorageMeta<T extends Payload = Payload> = T & HashStorageMeta
export type WithPartialHashStorageMeta<T extends Payload = Payload> = Partial<WithHashStorageMeta<T>>

export const isHashStorageMeta = (value: unknown): value is HashStorageMeta => {
return isDataHashStorageMeta(value) && isHash((value as WithHashStorageMeta)?._hash)
}

export const asHashStorageMeta = AsObjectFactory.create<HashStorageMeta>(isHashStorageMeta)
export const asOptionalHashStorageMeta = AsObjectFactory.createOptional<HashStorageMeta>(isHashStorageMeta)
Original file line number Diff line number Diff line change
@@ -1,78 +1,18 @@
import type { Address, Hex } from '@xylabs/hex'
import { isHex } from '@xylabs/hex'
import { AsObjectFactory } from '@xylabs/object'

// we use Exclude to intentionally make the type not equal to string
export type LocalSequence = Hex & Exclude<string, 'reserved-local-sequence-value'>
export type QualifiedSequence = Hex & Exclude<string, 'reserved-qualified-sequence-value'>
export type Sequence = LocalSequence | QualifiedSequence
import type { Payload } from '../Payload.ts'
import type { Sequence } from './sequence/index.ts'

export type Epoch = Hex & Exclude<string, 'reserved-epoch-sequence-value'>

export const isEpoch = (value: unknown): value is Epoch => {
return isHex(value) && (value as string).length === SequenceConstants.epochBytes * 2
}

export type Nonce = Hex & Exclude<string, 'reserved-nonce-sequence-value'>

export const isNonce = (value: unknown): value is Epoch => {
return isHex(value) && (value as string).length === SequenceConstants.nonceBytes * 2
}

export const isLocalSequence = (value: unknown): value is Sequence => {
return isHex(value) && (value as string).length === SequenceConstants.localSequenceBytes * 2
}

export const isQualifiedSequence = (value: unknown): value is Sequence => {
return isHex(value) && (value as string).length === SequenceConstants.qualifiedSequenceBytes * 2
}

export const isSequence = (value: unknown): value is Sequence => {
return isLocalSequence(value) || isQualifiedSequence(value)
export interface SequenceStorageMeta {
_sequence: Sequence
}

export const SequenceNonceComponentLengths = {
nonceIndexBytes: 4,
nonceHashBytes: 4,
}

export const SequenceComponentLengths = {
...SequenceNonceComponentLengths,
epochBytes: 8,
nonceBytes: SequenceNonceComponentLengths.nonceIndexBytes + SequenceNonceComponentLengths.nonceHashBytes,
addressBytes: 20,
}

export const SequenceComponentMinMax = {
minEpoch: '0'.repeat(SequenceComponentLengths.epochBytes * 2) as Epoch,
maxEpoch: 'f'.repeat(SequenceComponentLengths.epochBytes * 2) as Epoch,
minNonce: '0'.repeat(SequenceComponentLengths.nonceBytes * 2) as Nonce,
maxNonce: 'f'.repeat(SequenceComponentLengths.nonceBytes * 2) as Nonce,
minAddress: '0'.repeat(SequenceComponentLengths.addressBytes * 2) as Address,
maxAddress: 'f'.repeat(SequenceComponentLengths.addressBytes * 2) as Address,
}
export type WithSequenceStorageMeta<T extends Payload = Payload> = T & SequenceStorageMeta
export type WithPartialSequenceStorageMeta<T extends Payload = Payload> = Partial<WithSequenceStorageMeta<T>>

export const LocalSequenceConstants = {
...SequenceComponentLengths,
...SequenceComponentMinMax,
localSequenceBytes: SequenceComponentLengths.epochBytes + SequenceComponentLengths.nonceBytes,
minLocalSequence: SequenceComponentMinMax.minEpoch + SequenceComponentMinMax.minNonce as LocalSequence,
maxLocalSequence: SequenceComponentMinMax.maxEpoch + SequenceComponentMinMax.maxNonce as LocalSequence,
export const isSequenceStorageMeta = (value: unknown): value is SequenceStorageMeta => {
return (value as WithSequenceStorageMeta)?._sequence !== undefined
}

export const QualifiedSequenceConstants = {
qualifiedSequenceBytes: LocalSequenceConstants.localSequenceBytes + SequenceComponentLengths.addressBytes,
minQualifiedSequence: LocalSequenceConstants.minLocalSequence + SequenceComponentMinMax.minAddress as QualifiedSequence,
maxQualifiedSequence: LocalSequenceConstants.maxLocalSequence + SequenceComponentMinMax.maxAddress as QualifiedSequence,
}

export const SequenceConstants = {
...LocalSequenceConstants,
...QualifiedSequenceConstants,
}

// "11111111111111112222222222222222" is and example of a local sequence string

// "111111111111111122222222222222223333333333333333333333333333333333333333" is and example of a local sequence string
// epoch = "1111111111111111"
// nonce = "2222222222222222"
// address = "3333333333333333333333333333333333333333"
export const asSequenceStorageMeta = AsObjectFactory.create(isSequenceStorageMeta)
export const asOptionalSequenceStorageMeta = AsObjectFactory.createOptional(isSequenceStorageMeta)
Original file line number Diff line number Diff line change
@@ -1,49 +1,17 @@
import { type Hash, isHash } from '@xylabs/hex'
import { AsObjectFactory } from '@xylabs/object'

import type { Payload } from '../Payload.ts'
import type { Sequence } from './Sequence.ts'
import { type HashStorageMeta, isHashStorageMeta } from './Hash.ts'
import { isSequenceStorageMeta, type SequenceStorageMeta } from './Sequence.ts'

export interface SequenceMeta {
_sequence: Sequence
}

export type WithPartialSequenceMeta<T extends Payload = Payload> = Partial<WithSequenceMeta<T>>

export type WithSequenceMeta<T extends Payload = Payload> = T & SequenceMeta

export interface HashMeta {
_dataHash: Hash
_hash: Hash
}

export type WithPartialHashMeta<T extends Payload = Payload> = Partial<WithHashMeta<T>>

export type WithHashMeta<T extends Payload = Payload> = T & HashMeta

export interface StorageMeta extends SequenceMeta, HashMeta {}

export type WithPartialStorageMeta<T extends Payload = Payload> = Partial<WithStorageMeta<T>>
export interface StorageMeta extends SequenceStorageMeta, HashStorageMeta {}

export type WithStorageMeta<T extends Payload = Payload> = T & StorageMeta

export const isSequenceMeta = (value: unknown): value is SequenceMeta => {
return (value as WithSequenceMeta)?._sequence !== undefined
}

export const isHashMeta = (value: unknown): value is HashMeta => {
return isHash((value as WithHashMeta)?._hash) && isHash((value as WithHashMeta)?._dataHash)
}
export type WithPartialStorageMeta<T extends Payload = Payload> = Partial<WithStorageMeta<T>>

export const isStorageMeta = (value: unknown): value is StorageMeta => {
return isSequenceMeta(value) && isHashMeta(value)
return isSequenceStorageMeta(value) && isHashStorageMeta(value)
}
export const asStorageMeta = AsObjectFactory.create(isStorageMeta)
export const asOptionalStorageMeta = AsObjectFactory.createOptional(isStorageMeta)

// "00005a7f354762f3ac1bc5ddc6cfd08d14" is and example of a local sequence string

// "00005a7f354762f3ac1bc5ddc6cfd08d14a123456789abcdef0123" is and example of a local sequence string
// epoch = "00005a7f354762f3ac"
// nonce = "1bc5ddc6cfd08d14"
// address = "a123456789abcdef0123"
export const asStorageStorageMeta = AsObjectFactory.create(isStorageMeta)
export const asOptionalStorageMeta = AsObjectFactory.createOptional(isStorageMeta)
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './DataHash.ts'
export * from './Hash.ts'
export * from './Sequence.ts'
export * from './SequenceComparer.ts'
export * from './SequenceParser.ts'
export * from './sequence/index.ts'
export * from './StorageMeta.ts'
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Compare } from '@xylabs/object'

import { SequenceParser } from './Parser.ts'
import type { Sequence } from './Sequence.ts'
import { SequenceParser } from './SequenceParser.ts'

const local: Compare<Sequence> = (a, b) => {
const aa = SequenceParser.from(a)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type { Address, Hex } from '@xylabs/hex'
import { isHex } from '@xylabs/hex'

// we use Exclude to intentionally make the type not equal to string
export type LocalSequence = Hex & Exclude<string, 'reserved-local-sequence-value'>
export type QualifiedSequence = Hex & Exclude<string, 'reserved-qualified-sequence-value'>
export type Sequence = LocalSequence | QualifiedSequence

export type Epoch = Hex & Exclude<string, 'reserved-epoch-sequence-value'>

export const isEpoch = (value: unknown): value is Epoch => {
return isHex(value) && (value as string).length === SequenceConstants.epochBytes * 2
}

export type Nonce = Hex & Exclude<string, 'reserved-nonce-sequence-value'>

export const isNonce = (value: unknown): value is Epoch => {
return isHex(value) && (value as string).length === SequenceConstants.nonceBytes * 2
}

export const isLocalSequence = (value: unknown): value is Sequence => {
return isHex(value) && (value as string).length === SequenceConstants.localSequenceBytes * 2
}

export const isQualifiedSequence = (value: unknown): value is Sequence => {
return isHex(value) && (value as string).length === SequenceConstants.qualifiedSequenceBytes * 2
}

export const isSequence = (value: unknown): value is Sequence => {
return isLocalSequence(value) || isQualifiedSequence(value)
}

export const SequenceNonceComponentLengths = {
nonceIndexBytes: 4,
nonceHashBytes: 4,
}

export const SequenceComponentLengths = {
...SequenceNonceComponentLengths,
epochBytes: 8,
nonceBytes: SequenceNonceComponentLengths.nonceIndexBytes + SequenceNonceComponentLengths.nonceHashBytes,
addressBytes: 20,
}

export const SequenceComponentMinMax = {
minEpoch: '0'.repeat(SequenceComponentLengths.epochBytes * 2) as Epoch,
maxEpoch: 'f'.repeat(SequenceComponentLengths.epochBytes * 2) as Epoch,
minNonce: '0'.repeat(SequenceComponentLengths.nonceBytes * 2) as Nonce,
maxNonce: 'f'.repeat(SequenceComponentLengths.nonceBytes * 2) as Nonce,
minAddress: '0'.repeat(SequenceComponentLengths.addressBytes * 2) as Address,
maxAddress: 'f'.repeat(SequenceComponentLengths.addressBytes * 2) as Address,
}

export const LocalSequenceConstants = {
...SequenceComponentLengths,
...SequenceComponentMinMax,
localSequenceBytes: SequenceComponentLengths.epochBytes + SequenceComponentLengths.nonceBytes,
minLocalSequence: SequenceComponentMinMax.minEpoch + SequenceComponentMinMax.minNonce as LocalSequence,
maxLocalSequence: SequenceComponentMinMax.maxEpoch + SequenceComponentMinMax.maxNonce as LocalSequence,
}

export const QualifiedSequenceConstants = {
qualifiedSequenceBytes: LocalSequenceConstants.localSequenceBytes + SequenceComponentLengths.addressBytes,
minQualifiedSequence: LocalSequenceConstants.minLocalSequence + SequenceComponentMinMax.minAddress as QualifiedSequence,
maxQualifiedSequence: LocalSequenceConstants.maxLocalSequence + SequenceComponentMinMax.maxAddress as QualifiedSequence,
}

export const SequenceConstants = {
...LocalSequenceConstants,
...QualifiedSequenceConstants,
}

// "11111111111111112222222222222222" is and example of a local sequence string

// "111111111111111122222222222222223333333333333333333333333333333333333333" is and example of a local sequence string
// epoch = "1111111111111111"
// nonce = "2222222222222222"
// address = "3333333333333333333333333333333333333333"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './Comparer.ts'
export * from './Parser.ts'
export * from './Sequence.ts'
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {
describe, expect, it,
} from 'vitest'

import type {
Epoch, Nonce, Sequence,
} from '../Sequence.ts'
import { SequenceComparer } from '../SequenceComparer.ts'
import { SequenceParser } from '../SequenceParser.ts'
import {
type Epoch, type Nonce, type Sequence,
SequenceComparer,
SequenceParser,
} from '../sequence/index.ts'

describe('SequenceComparer', () => {
describe('local', () => {
Expand Down
Loading

0 comments on commit 902dec2

Please sign in to comment.