@sentio/sdk 2.39.4-rc.8 → 2.39.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/eth/builtin/internal/eacaggregatorproxy-processor.d.ts.map +1 -1
- package/lib/eth/builtin/internal/erc1155-processor.d.ts.map +1 -1
- package/lib/eth/builtin/internal/erc20-processor.d.ts.map +1 -1
- package/lib/eth/builtin/internal/erc20bytes-processor.d.ts.map +1 -1
- package/lib/eth/builtin/internal/erc721-processor.d.ts.map +1 -1
- package/lib/eth/builtin/internal/weth9-processor.d.ts.map +1 -1
- package/lib/fuel/context.d.ts.map +1 -1
- package/lib/solana/solana-processor.d.ts +0 -1
- package/lib/solana/solana-processor.d.ts.map +1 -1
- package/lib/store/codegen.js +3 -3
- package/lib/store/codegen.js.map +1 -1
- package/lib/store/decorators.d.ts +1 -1
- package/lib/store/decorators.d.ts.map +1 -1
- package/lib/store/decorators.js +61 -60
- package/lib/store/decorators.js.map +1 -1
- package/lib/store/schema.d.ts.map +1 -1
- package/lib/store/schema.js +38 -0
- package/lib/store/schema.js.map +1 -1
- package/lib/store/store.d.ts +3 -1
- package/lib/store/store.d.ts.map +1 -1
- package/lib/store/store.js +38 -13
- package/lib/store/store.js.map +1 -1
- package/lib/store/types.d.ts +2 -20
- package/lib/store/types.d.ts.map +1 -1
- package/lib/store/types.js +1 -14
- package/lib/store/types.js.map +1 -1
- package/lib/utils/price.d.ts +30 -30
- package/lib/utils/price.d.ts.map +1 -1
- package/lib/utils/price.js +5 -4
- package/lib/utils/price.js.map +1 -1
- package/package.json +4 -4
- package/src/store/codegen.ts +3 -3
- package/src/store/decorators.ts +66 -62
- package/src/store/schema.ts +40 -0
- package/src/store/store.ts +43 -15
- package/src/store/types.ts +2 -23
- package/src/utils/price.ts +6 -4
package/src/store/decorators.ts
CHANGED
@@ -15,8 +15,8 @@ import {
|
|
15
15
|
TypeConverters,
|
16
16
|
ValueConverter
|
17
17
|
} from './convert.js'
|
18
|
-
import { getStore } from './store.js'
|
19
18
|
import { RichStruct } from '@sentio/protos'
|
19
|
+
import { getStore } from './store.js'
|
20
20
|
|
21
21
|
type Constructor = { new (...args: any[]): any }
|
22
22
|
|
@@ -28,73 +28,77 @@ function handleError(entity: string, key: string, fn: () => any) {
|
|
28
28
|
}
|
29
29
|
}
|
30
30
|
|
31
|
-
export function Entity(
|
31
|
+
export function Entity(entityName: string) {
|
32
32
|
return function <T extends Constructor>(BaseClass: T) {
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
const meta: Record<string, ValueConverter<any>> = (BaseClass as any).meta || {}
|
34
|
+
const target = BaseClass.prototype
|
35
|
+
for (const [propertyKey, type] of Object.entries(meta)) {
|
36
|
+
if (type.isRelation && type.relationName) {
|
37
|
+
const relationName = type.relationName
|
38
|
+
const idGetter = function (this: any) {
|
39
|
+
return handleError(this.constructor.entityName, propertyKey, () => type!.to(this._data.fields[propertyKey]))
|
40
|
+
}
|
41
|
+
const idSetter = function (this: any, value: any) {
|
42
|
+
this._data.fields[propertyKey] = handleError(this.constructor.entityName, propertyKey, () =>
|
43
|
+
type!.from(value)
|
44
|
+
)
|
45
|
+
}
|
46
|
+
const idKey = type.isArray ? propertyKey + 'IDs' : propertyKey + 'ID'
|
36
47
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
const
|
44
|
-
|
45
|
-
return
|
48
|
+
Reflect.defineProperty(target, idKey, {
|
49
|
+
get: idGetter,
|
50
|
+
set: idSetter
|
51
|
+
})
|
52
|
+
Reflect.defineProperty(target, propertyKey, {
|
53
|
+
get: function () {
|
54
|
+
const ids = idGetter.call(this)
|
55
|
+
if (Array.isArray(ids)) {
|
56
|
+
return Promise.all(
|
57
|
+
ids.map((id) => {
|
58
|
+
return getStore()?.get(relationName, id)
|
59
|
+
})
|
60
|
+
)
|
61
|
+
} else {
|
62
|
+
return getStore()?.get(relationName, ids)
|
46
63
|
}
|
47
|
-
|
48
|
-
|
64
|
+
},
|
65
|
+
set: function (value) {
|
66
|
+
if (value instanceof Promise) {
|
67
|
+
value.then((v) => {
|
68
|
+
idSetter.call(this, v)
|
69
|
+
})
|
70
|
+
} else {
|
71
|
+
idSetter.call(this, value)
|
49
72
|
}
|
50
|
-
const idKey = converter.isArray ? propertyKey + 'IDs' : propertyKey + 'ID'
|
51
|
-
|
52
|
-
Object.defineProperty(this, idKey, {
|
53
|
-
get: idGetter,
|
54
|
-
set: idSetter
|
55
|
-
})
|
56
|
-
|
57
|
-
Object.defineProperty(this, propertyKey, {
|
58
|
-
get: () => {
|
59
|
-
const ids = idGetter()
|
60
|
-
if (Array.isArray(ids)) {
|
61
|
-
return Promise.all(
|
62
|
-
ids.map((id) => {
|
63
|
-
return getStore()?.get(relationName, id)
|
64
|
-
})
|
65
|
-
)
|
66
|
-
} else {
|
67
|
-
return getStore()?.get(relationName, ids)
|
68
|
-
}
|
69
|
-
},
|
70
|
-
set: (value) => {
|
71
|
-
if (value instanceof Promise) {
|
72
|
-
value.then((v) => {
|
73
|
-
idSetter(v)
|
74
|
-
})
|
75
|
-
} else {
|
76
|
-
idSetter(value)
|
77
|
-
}
|
78
|
-
}
|
79
|
-
})
|
80
|
-
} else {
|
81
|
-
Object.defineProperty(this, propertyKey, {
|
82
|
-
get: () => {
|
83
|
-
return handleError(name, propertyKey, () => converter.to(this._data.fields[propertyKey]))
|
84
|
-
},
|
85
|
-
set: (value) => {
|
86
|
-
this._data.fields[propertyKey] = handleError(name, propertyKey, () => converter.from(value))
|
87
|
-
}
|
88
|
-
})
|
89
73
|
}
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
74
|
+
})
|
75
|
+
} else {
|
76
|
+
Reflect.defineProperty(target, propertyKey, {
|
77
|
+
configurable: true,
|
78
|
+
get: function () {
|
79
|
+
return handleError(this.constructor.entityName, propertyKey, () => type!.to(this._data.fields[propertyKey]))
|
80
|
+
},
|
81
|
+
set: function (value) {
|
82
|
+
this._data.fields[propertyKey] = handleError(this.constructor.entityName, propertyKey, () =>
|
83
|
+
type!.from(value)
|
84
|
+
)
|
97
85
|
}
|
86
|
+
})
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
return class extends BaseClass {
|
91
|
+
readonly _data: RichStruct = { fields: {} }
|
92
|
+
static entityName = entityName
|
93
|
+
constructor(...args: any[]) {
|
94
|
+
super()
|
95
|
+
for (const key of Object.getOwnPropertyNames(this)) {
|
96
|
+
if (BaseClass.prototype.hasOwnProperty(key)) {
|
97
|
+
delete this[key]
|
98
|
+
}
|
99
|
+
}
|
100
|
+
if (args[0]) {
|
101
|
+
Object.assign(this, args[0])
|
98
102
|
}
|
99
103
|
}
|
100
104
|
}
|
package/src/store/schema.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import { buildASTSchema, DocumentNode, extendSchema, GraphQLSchema, parse, validateSchema } from 'graphql/index.js'
|
2
2
|
import * as fs from 'node:fs'
|
3
|
+
import { GraphQLObjectType, GraphQLOutputType, isListType, isNonNullType } from 'graphql'
|
3
4
|
|
4
5
|
const customScalars = ['BigInt', 'BigDecimal', 'Timestamp', 'JSON', 'Bytes', 'ID']
|
5
6
|
|
@@ -19,12 +20,51 @@ const baseSchema = buildASTSchema(
|
|
19
20
|
`)
|
20
21
|
)
|
21
22
|
|
23
|
+
function getElemType(type: GraphQLOutputType) {
|
24
|
+
if (isNonNullType(type)) {
|
25
|
+
return getElemType(type.ofType)
|
26
|
+
}
|
27
|
+
if (isListType(type)) {
|
28
|
+
return getElemType(type.ofType)
|
29
|
+
}
|
30
|
+
return type
|
31
|
+
}
|
32
|
+
|
33
|
+
function checkRelations(schema: GraphQLSchema) {
|
34
|
+
for (const t of Object.values(schema.getTypeMap())) {
|
35
|
+
if (t.name.startsWith('__')) {
|
36
|
+
continue
|
37
|
+
}
|
38
|
+
if (t instanceof GraphQLObjectType) {
|
39
|
+
for (const f of Object.values(t.getFields())) {
|
40
|
+
if (f.astNode) {
|
41
|
+
for (const d of f.astNode.directives ?? []) {
|
42
|
+
if (d.name.value === 'derivedFrom') {
|
43
|
+
const arg = (d.arguments ?? []).find((a) => a.name.value === 'field')
|
44
|
+
if (!arg || !arg.value || arg.value.kind !== 'StringValue') {
|
45
|
+
throw new Error(`@derivedFrom directive must have a 'field' argument`)
|
46
|
+
}
|
47
|
+
const fieldName = arg.value.value
|
48
|
+
const targetType = getElemType(f.type) as GraphQLObjectType
|
49
|
+
// Check if the target type has a field with the same name
|
50
|
+
if (!targetType.getFields()[fieldName]) {
|
51
|
+
throw new Error(`Field '${fieldName}' not found in type '${targetType.name}'`)
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
22
61
|
export function buildSchema(doc: DocumentNode): GraphQLSchema {
|
23
62
|
const schema = extendSchema(baseSchema, doc)
|
24
63
|
const errors = validateSchema(schema).filter((err) => !/query root/i.test(err.message))
|
25
64
|
if (errors.length > 0) {
|
26
65
|
throw errors[0]
|
27
66
|
}
|
67
|
+
checkRelations(schema)
|
28
68
|
return schema
|
29
69
|
}
|
30
70
|
|
package/src/store/store.ts
CHANGED
@@ -2,7 +2,7 @@ import { StoreContext } from './context.js'
|
|
2
2
|
import { DatabaseSchema } from '../core/index.js'
|
3
3
|
import { BigDecimal } from '@sentio/bigdecimal'
|
4
4
|
import { Bytes, Float, ID, Int, Timestamp } from './types.js'
|
5
|
-
import type {
|
5
|
+
import type { Entity as EntityStruct, RichValue } from '@sentio/protos'
|
6
6
|
import { DBRequest_DBOperator, DBResponse } from '@sentio/protos'
|
7
7
|
import { toBigInteger } from './convert.js'
|
8
8
|
import { PluginManager } from '@sentio/runtime'
|
@@ -17,20 +17,36 @@ export interface EntityClass<T> {
|
|
17
17
|
new (data: Partial<T>): T
|
18
18
|
}
|
19
19
|
|
20
|
+
function getEntityName<T>(entity: EntityClass<T> | T | string): string {
|
21
|
+
if (entity == null) {
|
22
|
+
throw new Error("can't figure out entityName from undefined")
|
23
|
+
}
|
24
|
+
if (typeof entity == 'string') {
|
25
|
+
return entity
|
26
|
+
}
|
27
|
+
if (typeof entity == 'function') {
|
28
|
+
return (entity as any).entityName
|
29
|
+
}
|
30
|
+
if (typeof entity == 'object') {
|
31
|
+
return (entity.constructor as any).entityName
|
32
|
+
}
|
33
|
+
throw new Error(`can't figure out entityName from ${typeof entity}`)
|
34
|
+
}
|
35
|
+
|
20
36
|
export class Store {
|
21
37
|
constructor(private readonly context: StoreContext) {}
|
22
38
|
|
23
39
|
async get<T extends Entity>(entity: EntityClass<T> | string, id: ID): Promise<T | undefined> {
|
24
40
|
const promise = this.context.sendRequest({
|
25
41
|
get: {
|
26
|
-
entity:
|
42
|
+
entity: getEntityName(entity),
|
27
43
|
id: id.toString()
|
28
44
|
}
|
29
45
|
})
|
30
46
|
|
31
47
|
const data = (await promise) as DBResponse
|
32
|
-
if (data.
|
33
|
-
const entityData = data.entities
|
48
|
+
if (data.entityList?.entities[0]) {
|
49
|
+
const entityData = data.entityList?.entities[0]
|
34
50
|
return this.newEntity(entity, entityData)
|
35
51
|
}
|
36
52
|
|
@@ -45,18 +61,17 @@ export class Store {
|
|
45
61
|
if (id) {
|
46
62
|
if (Array.isArray(id)) {
|
47
63
|
for (const i of id) {
|
48
|
-
|
49
|
-
request.entity.push(items)
|
64
|
+
request.entity.push(getEntityName(entity))
|
50
65
|
request.id.push(i.toString())
|
51
66
|
}
|
52
67
|
} else {
|
53
|
-
request.entity.push((entity
|
68
|
+
request.entity.push(getEntityName(entity))
|
54
69
|
request.id.push(id)
|
55
70
|
}
|
56
71
|
} else {
|
57
72
|
const entities = Array.isArray(entity) ? entity : [entity]
|
58
73
|
for (const e of entities) {
|
59
|
-
request.entity.push(
|
74
|
+
request.entity.push(getEntityName(entity))
|
60
75
|
request.id.push((e as Entity).id.toString())
|
61
76
|
}
|
62
77
|
}
|
@@ -70,7 +85,7 @@ export class Store {
|
|
70
85
|
const entities = Array.isArray(entity) ? entity : [entity]
|
71
86
|
const promise = this.context.sendRequest({
|
72
87
|
upsert: {
|
73
|
-
entity: entities.map((e) => e
|
88
|
+
entity: entities.map((e) => getEntityName(e)),
|
74
89
|
// data: entities.map((e) => serialize(e.data)),
|
75
90
|
id: entities.map((e) => e.id.toString()),
|
76
91
|
entityData: entities.map((e: any) => e._data)
|
@@ -80,13 +95,13 @@ export class Store {
|
|
80
95
|
await promise
|
81
96
|
}
|
82
97
|
|
83
|
-
async *
|
98
|
+
async *listIterator<T extends Entity>(entity: EntityClass<T>, filters?: ListFilter<T>[]) {
|
84
99
|
let cursor: string | undefined = undefined
|
85
100
|
|
86
101
|
while (true) {
|
87
102
|
const promise = this.context.sendRequest({
|
88
103
|
list: {
|
89
|
-
entity: entity
|
104
|
+
entity: getEntityName(entity),
|
90
105
|
cursor,
|
91
106
|
filters:
|
92
107
|
filters?.map((f) => ({
|
@@ -97,7 +112,7 @@ export class Store {
|
|
97
112
|
}
|
98
113
|
})
|
99
114
|
const response = (await promise) as DBResponse
|
100
|
-
for (const data of response.
|
115
|
+
for (const data of response.entityList?.entities || []) {
|
101
116
|
yield this.newEntity(entity, data)
|
102
117
|
}
|
103
118
|
if (!response.nextCursor) {
|
@@ -107,12 +122,25 @@ export class Store {
|
|
107
122
|
}
|
108
123
|
}
|
109
124
|
|
110
|
-
|
125
|
+
async list<T extends Entity>(entity: EntityClass<T>, filters?: ListFilter<T>[]) {
|
126
|
+
// TODO Array.fromAsync when upgrade to node 22
|
127
|
+
return this.fromAsync(this.listIterator(entity, filters))
|
128
|
+
}
|
129
|
+
|
130
|
+
private async fromAsync<T>(gen: AsyncIterable<T>): Promise<T[]> {
|
131
|
+
const out: T[] = []
|
132
|
+
for await (const x of gen) {
|
133
|
+
out.push(x)
|
134
|
+
}
|
135
|
+
return out
|
136
|
+
}
|
137
|
+
|
138
|
+
private newEntity<T extends Entity>(entity: EntityClass<T> | string, data: EntityStruct) {
|
111
139
|
if (typeof entity == 'string') {
|
112
140
|
let en = DatabaseSchema.findEntity(entity)
|
113
141
|
if (!en) {
|
114
142
|
// it is an interface
|
115
|
-
en = DatabaseSchema.findEntity(data.
|
143
|
+
en = DatabaseSchema.findEntity(data.entity)
|
116
144
|
if (!en) {
|
117
145
|
throw new Error(`Entity ${entity} not found`)
|
118
146
|
}
|
@@ -121,7 +149,7 @@ export class Store {
|
|
121
149
|
}
|
122
150
|
|
123
151
|
const res = new (entity as EntityClass<T>)({}) as T
|
124
|
-
;(res as any)._data = data
|
152
|
+
;(res as any)._data = data.data
|
125
153
|
return res
|
126
154
|
}
|
127
155
|
}
|
package/src/store/types.ts
CHANGED
@@ -1,29 +1,8 @@
|
|
1
|
-
export type ID =
|
1
|
+
export type ID = string | Uint8Array
|
2
2
|
export type String = string
|
3
|
-
export type Int = number
|
3
|
+
export type Int = number
|
4
4
|
export type Float = number
|
5
5
|
export type Boolean = boolean
|
6
6
|
export type Timestamp = Date
|
7
7
|
export type Bytes = Uint8Array
|
8
8
|
export type BigInt = bigint
|
9
|
-
|
10
|
-
export class Struct<T = unknown, S = unknown> {
|
11
|
-
readonly TYPE!: T
|
12
|
-
constructor(readonly schema: S) {}
|
13
|
-
}
|
14
|
-
export type Infer<T extends Struct<any>> = T['TYPE']
|
15
|
-
export type ObjectSchema = Record<string, Struct<any, any>>
|
16
|
-
|
17
|
-
export function object<S extends ObjectSchema>(schema: S): Struct<ObjectType<S>, S> {
|
18
|
-
return new Struct(schema ?? null)
|
19
|
-
}
|
20
|
-
|
21
|
-
export type Simplify<T> = T extends any[] | Date ? T : { [K in keyof T]: T[K] } & NonNullable<unknown>
|
22
|
-
|
23
|
-
export type ObjectType<S extends ObjectSchema> = Simplify<{ [K in keyof S]: Infer<S[K]> }>
|
24
|
-
|
25
|
-
const StringStruct = new Struct<string, null>(null)
|
26
|
-
|
27
|
-
const UU = object({
|
28
|
-
test: StringStruct
|
29
|
-
})
|
package/src/utils/price.ts
CHANGED
@@ -88,10 +88,12 @@ export async function getPriceByTypeOrSymbolInternal(
|
|
88
88
|
return res.price
|
89
89
|
})
|
90
90
|
.catch((e) => {
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
91
|
+
setTimeout(() => {
|
92
|
+
priceMap.delete(key)
|
93
|
+
}, 1000)
|
94
|
+
|
95
|
+
if (e.code === Status.NOT_FOUND || e.code === Status.UNKNOWN) {
|
96
|
+
console.error('price not found for ', JSON.stringify(coinId), ' at ', dateStr)
|
95
97
|
return undefined
|
96
98
|
}
|
97
99
|
// TODO maybe use small set of error
|