Skip to content

Commit 2be31b0

Browse files
authored
add index support (#573)
* feat: add doc store * feat: add index * test: add index test case
1 parent 8c41779 commit 2be31b0

13 files changed

+282
-78
lines changed

sdk/src/account/db3_account.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { toHEX } from '../crypto/crypto_utils'
3636
* const account = createFromPrivateKey("0x........")
3737
* ```
3838
* @param privatekey - a hex format private key string
39-
* @returns the instance of {@link DB3ACCOUNT}
39+
* @returns the instance of {@link DB3Account}
4040
*
4141
**/
4242
export function createFromPrivateKey(privateKey: Hex) {
@@ -60,7 +60,7 @@ export function createFromPrivateKey(privateKey: Hex) {
6060
* ```ts
6161
* const account = createRandomAccount()
6262
* ```
63-
* @returns the instance of {@link DB3ACCOUNT}
63+
* @returns the instance of {@link DB3Account}
6464
*
6565
**/
6666
export function createRandomAccount() {
@@ -75,7 +75,7 @@ export function createRandomAccount() {
7575
* ```ts
7676
* const account = createFromExternal()
7777
* ```
78-
* @returns the instance of {@link DB3ACCOUNT}
78+
* @returns the instance of {@link DB3Account}
7979
*
8080
**/
8181
export async function createFromExternal(chain?: Chain) {

sdk/src/index.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,25 @@
1414
* limitations under the License.
1515
*/
1616

17+
export type { DB3Account } from './account/types'
1718
export {
1819
createFromPrivateKey,
1920
createRandomAccount,
2021
signTypedData,
2122
createFromExternal,
2223
} from './account/db3_account'
23-
export type { DB3Account } from './account/types'
2424
export type { Client, ReadClient } from './client/types'
25-
export type { Database, Collection } from './store/types'
25+
export type {
26+
Database,
27+
Collection,
28+
CreateDBResult,
29+
CreateCollectionResult,
30+
MutationResult,
31+
QueryResult,
32+
} from './store/types'
2633
export { addDoc, updateDoc, deleteDoc, queryDoc } from './store/document_v2'
2734

28-
export { SystemConfig, SystemStatus } from './proto/db3_base'
35+
export { SystemConfig, SystemStatus, Version } from './proto/db3_base'
2936
export {
3037
createClient,
3138
createReadonlyClient,
@@ -50,6 +57,7 @@ export {
5057
showCollection,
5158
getDatabase,
5259
getCollection,
60+
addIndex,
5361
} from './store/database_v2'
5462

5563
export { Index, IndexType } from './proto/db3_database_v2'

sdk/src/provider/storage_provider_v2.ts

-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ export class StorageProviderV2 {
131131
blockId: block,
132132
orderId: order,
133133
}
134-
135134
try {
136135
const { response } = await this.client.getMutationHeader(request)
137136
return response

sdk/src/store/database_v2.ts

+81-8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
Mutation_BodyWrapper,
3333
DocumentDatabaseMutation,
3434
EventDatabaseMutation,
35+
AddIndexMutation,
3536
} from '../proto/db3_mutation_v2'
3637

3738
import { Client, ReadClient } from '../client/types'
@@ -43,10 +44,22 @@ import { Index } from '../proto/db3_database_v2'
4344
* Create an event database to store contract events
4445
*
4546
* ```ts
46-
* const {db, result} = await createEventDatabase(client, "my_db")
47+
* const {db, result} = await createEventDatabase(client,
48+
* "my contract event db",
49+
* "0x...",
50+
* ["DepositEvent"],
51+
* "{...}",
52+
* "wss://xxxxx",
53+
* "100000"
54+
* )
4755
* ```
48-
* @param client - the db3 client instance
49-
* @param desc - the description for the database
56+
* @param client - the client instance
57+
* @param desc - the description for the event database
58+
* @param contractAddress - the contract address
59+
* @param tables - the contract event list
60+
* @param abi - the json abi of contract
61+
* @param evmNodeUrl - the websocket url of evm node
62+
* @param startBlock - the start block to subscribe, 0 start from the latest block
5063
* @returns the {@link CreateDBResult}
5164
*
5265
**/
@@ -111,6 +124,65 @@ export async function createEventDatabase(
111124
throw new Error('fail to create database')
112125
}
113126
}
127+
/**
128+
*
129+
* Add index the existing Collection
130+
*
131+
* ```ts
132+
*
133+
* const index:Index = {
134+
* path:'/city', // a top level field name 'city' and the path will be '/city'
135+
* indexType: IndexType.StringKey
136+
* }
137+
* const result = await addIndex(collection, [index])
138+
* ```
139+
* @param client - the db3 client instance
140+
* @param indexes - the index list of {@link Index}
141+
* @returns the {@link MutationResult}
142+
*
143+
**/
144+
export async function addIndex(collection: Collection, indexes: Index[]) {
145+
if (indexes.filter((item) => !item.path.startsWith('/')).length > 0) {
146+
throw new Error('the index path must start with /')
147+
}
148+
const addIndexMutation: AddIndexMutation = {
149+
collectionName: collection.name,
150+
indexFields: indexes,
151+
}
152+
153+
const body: Mutation_BodyWrapper = {
154+
body: { oneofKind: 'addIndexMutation', addIndexMutation },
155+
dbAddress: fromHEX(collection.db.addr),
156+
}
157+
158+
const dm: Mutation = {
159+
action: MutationAction.AddIndex,
160+
bodies: [body],
161+
}
162+
const payload = Mutation.toBinary(dm)
163+
try {
164+
const response = await collection.db.client.provider.sendMutation(
165+
payload,
166+
collection.db.client.nonce.toString()
167+
)
168+
if (response.code == 0) {
169+
return {
170+
result: {
171+
id: response.id,
172+
block: response.block,
173+
order: response.order,
174+
} as MutationResult,
175+
}
176+
} else {
177+
throw new Error('fail to add index with err ' + response.msg)
178+
}
179+
} catch (e) {
180+
throw e
181+
} finally {
182+
collection.db.client.nonce += 1
183+
}
184+
}
185+
114186
/**
115187
*
116188
* Create a document database to group the collections
@@ -163,12 +235,12 @@ export async function createDocumentDatabase(client: Client, desc: string) {
163235
* Get the collection by an db address and collection name
164236
*
165237
* ```ts
166-
* const database = await getCollection("0x....", "col1", client)
238+
* const collection = await getCollection("0x....", "col1", client)
167239
* ```
168-
* @param addr - a hex format string address
240+
* @param addr - a hex format string database address
169241
* @param name - the name of collection
170-
* @param client- the db3 client instance
171-
* @returns the {@link Database}[]
242+
* @param client- the client instance
243+
* @returns the {@link Collection}
172244
*
173245
**/
174246
export async function getCollection(
@@ -187,6 +259,7 @@ export async function getCollection(
187259
)
188260
}
189261
}
262+
190263
/**
191264
*
192265
* Get the database by an address
@@ -271,7 +344,7 @@ export async function showDatabase(owner: string, client: Client | ReadClient) {
271344
*
272345
* @param db - the instance of database
273346
* @param name - the name of collection
274-
* @param indexFields - the fields for index
347+
* @param indexFields - the fields for {@link Index}
275348
* @returns the {@link CreateCollectionResult}
276349
*
277350
**/

sdk/src/store/document_v2.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ async function runQueryInternal<T>(col: Collection, query: Query) {
9292
* @param col - the instance of collection
9393
* @param queryStr - a document query string
9494
* @param parameters - an optional query parameters
95-
* @returns the {@link Queryresult}
95+
* @returns the {@link QueryResult}
9696
*
9797
**/
9898
export async function queryDoc<T = DocumentData>(

sdk/tests/client_v2.test.ts

+69
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
createCollection,
4949
getDatabase,
5050
getCollection,
51+
addIndex,
5152
} from '../src/store/database_v2'
5253
import { Index, IndexType } from '../src/proto/db3_database_v2'
5354
import { SystemConfig } from '../src/proto/db3_base'
@@ -271,6 +272,74 @@ describe('test db3.js client module', () => {
271272
expect(1).toBe(0)
272273
}
273274
})
275+
276+
test('test add index', async () => {
277+
const client = await createTestClient()
278+
try {
279+
const { db } = await createDocumentDatabase(
280+
client,
281+
'db_for_add index'
282+
)
283+
expect(db).toBeDefined()
284+
const index: Index = {
285+
path: '/city',
286+
indexType: IndexType.StringKey,
287+
}
288+
const { collection } = await createCollection(db, 'col', [index])
289+
expect(collection).toBeDefined()
290+
try {
291+
await addIndex(collection, [index])
292+
} catch (e) {
293+
expect(
294+
'invalid key path for error the index paths ["/city"] exist'
295+
).toBe(e.message)
296+
}
297+
const index2: Index = {
298+
path: '/name',
299+
indexType: IndexType.StringKey,
300+
}
301+
try {
302+
const result = await addIndex(collection, [index2])
303+
expect(result).toBeDefined()
304+
} catch (e) {
305+
expect(1).toBe(2)
306+
}
307+
const badIndex: Index = {
308+
path: 'name',
309+
indexType: IndexType.StringKey,
310+
}
311+
try {
312+
const result = await addIndex(collection, [badIndex])
313+
expect(1).toBe(2)
314+
} catch (e) {
315+
expect('the index path must start with /').toBe(e.message)
316+
}
317+
318+
const client2 = await createTestClient()
319+
const collection2 = await getCollection(db.addr, 'col', client2)
320+
expect(collection2).toBeDefined()
321+
try {
322+
const result = await addIndex(collection2, [index2])
323+
expect(1).toBe(2)
324+
} catch (e) {
325+
expect('You have no permission to modify the collection').toBe(
326+
e.message
327+
)
328+
}
329+
expect(collection2.indexFields.length).toBe(2)
330+
expect(collection2.indexFields[0].path).toBe('/city')
331+
expect(collection2.indexFields[0].indexType).toBe(
332+
IndexType.StringKey
333+
)
334+
expect(collection2.indexFields[1].path).toBe('/name')
335+
expect(collection2.indexFields[1].indexType).toBe(
336+
IndexType.StringKey
337+
)
338+
} catch (e) {
339+
console.log(e)
340+
expect(1).toBe(2)
341+
}
342+
})
274343
test('test create/update/delete document', async () => {
275344
const client = await createTestClient()
276345
try {

sdk/yarn.lock

+4-9
Original file line numberDiff line numberDiff line change
@@ -3213,15 +3213,10 @@ caniuse-api@^3.0.0:
32133213
lodash.memoize "^4.1.2"
32143214
lodash.uniq "^4.5.0"
32153215

3216-
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001426:
3217-
version "1.0.30001443"
3218-
resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001443.tgz#8fc85f912d5471c9821acacf9e715c421ca0dd1f"
3219-
integrity sha512-jUo8svymO8+Mkj3qbUbVjR8zv8LUGpGkUM/jKvc9SO2BvjCI980dp9fQbf/dyLs6RascPzgR4nhAKFA4OHeSaA==
3220-
3221-
caniuse-lite@^1.0.30001400:
3222-
version "1.0.30001434"
3223-
resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz#ec1ec1cfb0a93a34a0600d37903853030520a4e5"
3224-
integrity sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==
3216+
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426:
3217+
version "1.0.30001517"
3218+
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz"
3219+
integrity sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==
32253220

32263221
capture-exit@^2.0.0:
32273222
version "2.0.0"

src/error/src/lib.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,7 @@ pub enum DB3Error {
6969
QuerySessionVerifyError(String),
7070
#[error("fail to query database {0}")]
7171
QueryDatabaseError(String),
72-
#[error("database with addr {0} was not found")]
73-
DatabaseNotFound(String),
74-
#[error("collection with name {0} was not found in db {1}")]
75-
CollectionNotFound(String, String),
76-
#[error("collection {0} already exist in db {1}")]
77-
CollectionAlreadyExist(String, String),
72+
7873
#[error("the address does not match the public key")]
7974
InvalidSigner,
8075
#[error("fail to generate key for {0}")]
@@ -139,6 +134,16 @@ pub enum DB3Error {
139134
InvalidArUrlError(String),
140135
#[error("invalid database desc for error {0}")]
141136
InvalidDescError(String),
137+
138+
#[error("database with addr {0} was not found")]
139+
DatabaseNotFound(String),
140+
141+
#[error("collection with name {0} was not found in db {1}")]
142+
CollectionNotFound(String, String),
143+
#[error("collection {0} already exist in db {1}")]
144+
CollectionAlreadyExist(String, String),
145+
#[error("You have no permission to modify the collection")]
146+
CollectionPermssionDenied(),
142147
}
143148

144149
pub type Result<T> = std::result::Result<T, DB3Error>;

src/node/src/storage_node_light_impl.rs

-1
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,6 @@ impl StorageNode for StorageNodeV2Impl {
611611
})?;
612612
let action = MutationAction::from_i32(dm.action)
613613
.ok_or(Status::invalid_argument("bad mutation action".to_string()))?;
614-
// TODO validate the database mutation
615614
match self.state_store.incr_nonce(&address, nonce) {
616615
Ok(_) => {
617616
// mutation id

src/proto/proto/db3_database_v2.proto

-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ message EventTable {
7575
}
7676

7777
message Collection {
78-
bytes id = 1;
7978
string name = 2;
8079
repeated Index index_fields = 3;
8180
bytes sender = 4;

src/proto/proto/db3_mutation_v2.proto

+7
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ message MintDocumentDatabaseMutation {
4747
string sender = 6;
4848
}
4949

50+
message AddIndexMutation {
51+
string collection_name = 1;
52+
repeated db3_database_v2_proto.Index index_fields = 2;
53+
}
54+
5055
message DocumentMutation {
5156
string collection_name = 1;
5257
repeated bytes documents = 2;
@@ -102,6 +107,7 @@ enum MutationAction {
102107
CreateEventDB = 5;
103108
MintDocumentDB = 6;
104109
MintCollection = 7;
110+
AddIndex = 8;
105111
}
106112

107113
enum MutationRollupStatus {
@@ -121,6 +127,7 @@ message Mutation {
121127
DocumentDatabaseMutation doc_database_mutation = 5;
122128
MintDocumentDatabaseMutation mint_doc_database_mutation = 6;
123129
MintCollectionMutation mint_collection_mutation = 7;
130+
AddIndexMutation add_index_mutation = 8;
124131
}
125132
}
126133
repeated BodyWrapper bodies = 3;

0 commit comments

Comments
 (0)