Skip to content

Commit

Permalink
add implementation and tests for pagination for items and keys
Browse files Browse the repository at this point in the history
  • Loading branch information
lastmjs committed Dec 9, 2023
1 parent 9850532 commit 5f22298
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ service: () -> {
insertLargeRecord: (nat32) -> ();
insertMediumRecord: (nat32) -> ();
insertSmallRecord: (nat32) -> ();
itemsLargeRecord: (nat32) -> (vec record {text; record {id:text; age:nat; signature:vec nat8; internetIdentity:principal; username:text; mediumRecord:record {id:text; age:nat; internetIdentity:principal; username:text}; friends:vec text}}) query;
itemsMediumRecord: (nat32) -> (vec record {text; record {id:text; age:nat; internetIdentity:principal; username:text}}) query;
itemsSmallRecord: (nat32) -> (vec record {text; record {id:principal}}) query;
keysLargeRecord: (nat32) -> (vec text) query;
keysMediumRecord: (nat32) -> (vec text) query;
keysSmallRecord: (nat32) -> (vec text) query;
valuesLargeRecord: (nat32) -> (vec record {id:text; age:nat; signature:vec nat8; internetIdentity:principal; username:text; mediumRecord:record {id:text; age:nat; internetIdentity:principal; username:text}; friends:vec text}) query;
valuesMediumRecord: (nat32) -> (vec record {id:text; age:nat; internetIdentity:principal; username:text}) query;
valuesSmallRecord: (nat32) -> (vec record {id:principal}) query;
Expand Down
33 changes: 32 additions & 1 deletion examples/stable_b_tree_map_instruction_threshold/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Record,
StableBTreeMap,
text,
Tuple,
update,
Vec,
Void
Expand Down Expand Up @@ -54,9 +55,19 @@ export default Canister({
});
}
}),
keysSmallRecord: query([nat32], Vec(text), (numToReturn) => {
return smallRecordMap.keys(0, numToReturn);
}),
valuesSmallRecord: query([nat32], Vec(SmallRecord), (numToReturn) => {
return smallRecordMap.values(0, numToReturn);
}),
itemsSmallRecord: query(
[nat32],
Vec(Tuple(text, SmallRecord)),
(numToReturn) => {
return smallRecordMap.items(0, numToReturn);
}
),
insertMediumRecord: update([nat32], Void, (numToInsert) => {
for (let i = 0; i < numToInsert; i++) {
const id = v4();
Expand All @@ -69,9 +80,19 @@ export default Canister({
});
}
}),
keysMediumRecord: query([nat32], Vec(text), (numToReturn) => {
return mediumRecordMap.keys(0, numToReturn);
}),
valuesMediumRecord: query([nat32], Vec(MediumRecord), (numToReturn) => {
return mediumRecordMap.values(0, numToReturn);
}),
itemsMediumRecord: query(
[nat32],
Vec(Tuple(text, MediumRecord)),
(numToReturn) => {
return mediumRecordMap.items(0, numToReturn);
}
),
insertLargeRecord: update([nat32], Void, (numToInsert) => {
for (let i = 0; i < numToInsert; i++) {
const id = v4();
Expand All @@ -92,7 +113,17 @@ export default Canister({
});
}
}),
keysLargeRecord: query([nat32], Vec(text), (numToReturn) => {
return largeRecordMap.keys(0, numToReturn);
}),
valuesLargeRecord: query([nat32], Vec(LargeRecord), (numToReturn) => {
return largeRecordMap.values(0, numToReturn);
})
}),
itemsLargeRecord: query(
[nat32],
Vec(Tuple(text, LargeRecord)),
(numToReturn) => {
return largeRecordMap.items(0, numToReturn);
}
)
});
51 changes: 45 additions & 6 deletions examples/stable_b_tree_map_instruction_threshold/test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,26 @@ export function getTests(
10_000
);

const result =
const keysResult =
await stableBTreeMapInstructionThresholdCanister.keysSmallRecord(
5_000
);

const valuesResult =
await stableBTreeMapInstructionThresholdCanister.valuesSmallRecord(
6_000
);

const itemsResult =
await stableBTreeMapInstructionThresholdCanister.itemsSmallRecord(
2_000
);

return {
Ok: result.length === 6_000
Ok:
keysResult.length === 5_000 &&
valuesResult.length === 6_000 &&
itemsResult.length === 2_000
};
}
},
Expand All @@ -30,13 +43,26 @@ export function getTests(
5_000
);

const result =
const keysResult =
await stableBTreeMapInstructionThresholdCanister.keysMediumRecord(
1_000
);

const valuesResult =
await stableBTreeMapInstructionThresholdCanister.valuesMediumRecord(
1_000
);

const itemsResult =
await stableBTreeMapInstructionThresholdCanister.itemsMediumRecord(
1_000
);

return {
Ok: result.length === 1_000
Ok:
keysResult.length === 1_000 &&
valuesResult.length === 1_000 &&
itemsResult.length === 1_000
};
}
},
Expand All @@ -47,13 +73,26 @@ export function getTests(
2_000
);

const result =
const keysResult =
await stableBTreeMapInstructionThresholdCanister.keysLargeRecord(
500
);

const valuesResult =
await stableBTreeMapInstructionThresholdCanister.valuesLargeRecord(
500
);

const itemsResult =
await stableBTreeMapInstructionThresholdCanister.itemsLargeRecord(
400
);

return {
Ok: result.length === 500
Ok:
keysResult.length === 500 &&
valuesResult.length === 500 &&
itemsResult.length === 400
};
}
}
Expand Down
4 changes: 2 additions & 2 deletions property_tests/tests/stable_b_tree_map/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ const StableBTreeMapTestArb = fc
);
}),
{
minLength: 20,
maxLength: 50
minLength: 10,
maxLength: 30
}
)
.map((canisterConfigs) => {
Expand Down
22 changes: 21 additions & 1 deletion src/compiler/rust/canister/src/ic/stable_b_tree_map_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,31 @@ pub fn native_function<'a>(
.try_into()?;
let memory_id: u8 = memory_id_string.parse()?;

let start_index_string: String = args
.get(1)
.expect("stable_b_tree_map_items argument 1 is undefined")
.to_js_value()?
.try_into()?;
let start_index: usize = start_index_string.parse()?;

let length_string: String = args
.get(2)
.expect("stable_b_tree_map_items argument 2 is undefined")
.to_js_value()?
.try_into()?;

let items: Vec<Vec<Vec<u8>>> = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| {
let stable_b_tree_maps = stable_b_tree_maps.borrow();
let stable_b_tree_map = &stable_b_tree_maps[&memory_id];

stable_b_tree_maps[&memory_id]
stable_b_tree_map
.iter()
.skip(start_index)
.take(if length_string == "NOT_SET" {
stable_b_tree_map.len().try_into().unwrap()
} else {
length_string.parse().unwrap()
})
.map(|(key, value)| vec![key.bytes, value.bytes])
.collect()
});
Expand Down
22 changes: 21 additions & 1 deletion src/compiler/rust/canister/src/ic/stable_b_tree_map_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,31 @@ pub fn native_function<'a>(
.try_into()?;
let memory_id: u8 = memory_id_string.parse()?;

let start_index_string: String = args
.get(1)
.expect("stable_b_tree_map_keys argument 1 is undefined")
.to_js_value()?
.try_into()?;
let start_index: usize = start_index_string.parse()?;

let length_string: String = args
.get(2)
.expect("stable_b_tree_map_keys argument 2 is undefined")
.to_js_value()?
.try_into()?;

let keys: Vec<Vec<u8>> = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| {
let stable_b_tree_maps = stable_b_tree_maps.borrow();
let stable_b_tree_map = &stable_b_tree_maps[&memory_id];

stable_b_tree_maps[&memory_id]
stable_b_tree_map
.iter()
.skip(start_index)
.take(if length_string == "NOT_SET" {
stable_b_tree_map.len().try_into().unwrap()
} else {
length_string.parse().unwrap()
})
.map(|(key, _)| key.bytes)
.collect()
});
Expand Down
12 changes: 10 additions & 2 deletions src/lib/ic/types/azle_ic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,16 @@ export type AzleIc = {
encodedValue: ArrayBufferLike
) => ArrayBuffer | undefined;
stableBTreeMapIsEmpty: (memoryId: string) => boolean;
stableBTreeMapItems: (memoryId: string) => [ArrayBuffer, ArrayBuffer][];
stableBTreeMapKeys: (memoryId: string) => ArrayBuffer[];
stableBTreeMapItems: (
memoryId: string,
startIndex: string,
length: string
) => [ArrayBuffer, ArrayBuffer][];
stableBTreeMapKeys: (
memoryId: string,
startIndex: string,
length: string
) => ArrayBuffer[];
stableBTreeMapLen: (memoryId: string) => ArrayBuffer;
stableBTreeMapRemove(
memoryId: string,
Expand Down
21 changes: 16 additions & 5 deletions src/lib/stable_structures/stable_b_tree_map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,20 @@ export function StableBTreeMap<Key = any, Value = any>(
},
/**
* Retrieves the items in the map in sorted order.
* @param startIndex the starting index to begin retrieval
* @param length the number of items to retrieve
* @returns tuples representing key/value pairs.
*/
items(): [Key, Value][] {
items(startIndex?: number, length?: number): [Key, Value][] {
if (globalThis._azleIc === undefined) {
return undefined as any;
}

const encodedItems =
globalThis._azleIc.stableBTreeMapItems(memoryId);
const encodedItems = globalThis._azleIc.stableBTreeMapItems(
memoryId,
startIndex?.toString() ?? '0',
length?.toString() ?? 'NOT_SET'
);

// TODO too much copying
return encodedItems.map(([encodedKey, encodedValue]) => {
Expand All @@ -127,14 +132,20 @@ export function StableBTreeMap<Key = any, Value = any>(
},
/**
* The keys for each element in the map in sorted order.
* @param startIndex the starting index to begin retrieval
* @param length the number of keys to retrieve
* @returns they keys in the map.
*/
keys(): Key[] {
keys(startIndex?: number, length?: number): Key[] {
if (globalThis._azleIc === undefined) {
return undefined as any;
}

const encodedKeys = globalThis._azleIc.stableBTreeMapKeys(memoryId);
const encodedKeys = globalThis._azleIc.stableBTreeMapKeys(
memoryId,
startIndex?.toString() ?? '0',
length?.toString() ?? 'NOT_SET'
);

// TODO too much copying
return encodedKeys.map((encodedKey) => {
Expand Down

0 comments on commit 5f22298

Please sign in to comment.