Adding and searching simple records

Adding and searching simple records
Overview

In this guide, you are going to write a dapp that provides a few basic functions to add and retrieve simple profile records that consist of a name, description, and an array of keywords.

在本指南中,您将编写一个 dapp,它提供一些基本功能来添加和检索由名称、描述和关键字数组组成的简单个人资料记录。

This program supports the following functions:

  • The update function enables you to add a profile that consists of a name, a description, and keywords.  更新功能使您能够添加由名称、描述和关键字组成的配置文件。

  • The getSelf function returns the profile for the principal associated with the function caller.  getSelf 函数返回与函数调用方关联的主体的配置文件。

  • The get function performs a simple query to return the profile matching the name value passed to it. For this function, the name specified must match the name field exactly to return the record.  get 函数执行一个简单的查询,以返回与传递给它的名称值匹配的配置文件。 对于此函数,指定的名称必须与名称字段完全匹配才能返回记录。

  • The search function performs a more complex query to return the profile matching all or part of the text specified in any profile field. For example, the search function can return a profile containing a specific keyword or that matches only part of a name or description.  搜索功能执行更复杂的查询,以返回与任何个人资料字段中指定的全部或部分文本匹配的个人资料。 例如,搜索功能可以返回包含特定关键字或仅匹配部分名称或说明的配置文件

This guide provides a simple example of how you can use the Rust CDK interfaces and macros to simplify writing dapps in Rust for the Internet Computer blockchain.

This guide demonstrates:

  • How to represent slightly more complex data—in the form of a profile as a record and an array of keywords—using the Candid interface description language.
  • How to write a simple search function with partial string matching.
  • How profiles are associated with a specific principal.
Prerequisites

Before getting started, assure you have set up your developer environment according to the instructions in the developer environment guide.

在开始之前,请确保您已按照开发者环境指南中的说明设置开发者环境。

Creating a new project

Open a terminal window on your local computer, if you don’t already have one open. Then, create a new project by running the following command:

dfx new --type=rust rust_profile
cd rust_profile

Now that you have the files in place for your Rust dapp, we can replace the template lib.rs dapp with the Rust dapp we want to deploy on the Internet Computer blockchain.

现在您已经为 Rust dapp 准备好了文件,我们可以将模板 https://lib.rs/ dapp 替换为我们想要在互联网计算机区块链上部署的 Rust dapp。

To replace the default program, open the src/rust_profile_backend/Cargo.toml file in a text editor and add serde to dependencies.

[dependencies]
candid = "0.8.2"
ic-cdk = "0.6.0"
serde = "1.0"

Then, open the template src/rust_profile_backend/src/lib.rs file in a text editor and delete the existing content.

The next step is to add a Rust program that implements the getSelf, update, get, and search functions. To do this, copy and paste this code into the src/rust_profile_backend/src/lib.rs file.

下一步是添加一个实现 getSelf、更新、获取和搜索功能的 Rust 程序。 为此,请将此代码复制并粘贴到 src/rust_profile_backend/src/https://lib.rs/ 文件中。

use ic_cdk::{
export::{
candid::{CandidType, Deserialize},
Principal,
},
query, update,
};
use std::cell::RefCell;
use std::collections::BTreeMap;

type IdStore = BTreeMap<String, Principal>;
type ProfileStore = BTreeMap<Principal, Profile>;

#[derive(Clone, Debug, Default, CandidType, Deserialize)]
struct Profile {
pub name: String,
pub description: String,
pub keywords: Vec<String>,
}

thread_local! {
static PROFILE_STORE: RefCell<ProfileStore> = RefCell::default();
static ID_STORE: RefCell<IdStore> = RefCell::default();
}

#[query(name = "getSelf")]
fn get_self() -> Profile {
let id = ic_cdk::api::caller();
PROFILE_STORE.with(|profile_store| {
profile_store
.borrow()
.get(&id)
.cloned().unwrap_or_default()
})
}

#[query]
fn get(name: String) -> Profile {
ID_STORE.with(|id_store| {
PROFILE_STORE.with(|profile_store| {
id_store
.borrow()
.get(&name)
.and_then(|id| profile_store.borrow().get(id).cloned()).unwrap_or_default()
})
})
}

#[update]
fn update(profile: Profile) {
let principal_id = ic_cdk::api::caller();
ID_STORE.with(|id_store| {
id_store
.borrow_mut()
.insert(profile.name.clone(), principal_id);
});
PROFILE_STORE.with(|profile_store| {
profile_store.borrow_mut().insert(principal_id, profile);
});
}

Save your changes and close the file to continue.

Update the interface description file

Candid is an interface description language (IDL) for interacting with canisters running on the Internet Computer. Candid files provide a language-independent description of a canister’s interfaces including the names, parameters, and result formats and data types for each function a canister defines.

Candid 是一种接口描述语言 (IDL),用于与 Internet 计算机上运行的容器进行交互。 Candid 文件提供容器接口的独立于语言的描述,包括容器定义的每个函数的名称、参数以及结果格式和数据类型。

By adding Candid files to your project, you can ensure that data is properly converted from its definition in Rust to run safely on the Internet Computer blockchain.

通过将 Candid 文件添加到您的项目中,您可以确保数据从 Rust 中的定义正确转换,以便在互联网计算机区块链上安全运行。

To see details about the Candid interface description language syntax, see the Candid Guide or the Candid crate documentation.

To update Candid file for this guide open the src/rust_profile_backend/rust_profile_backend.did file in a text editor.

Copy and paste the following Profile type declaration and service definition for the getSelf, update, get, and search functions.

type Profile = record {
"name": text;
"description": text;
"keywords": vec text;
};

service : {
"getSelf": () -> (Profile) query;
"get": (text) -> (Profile) query;
"update": (Profile) -> ();
"search": (text) -> (opt Profile) query;
}

Save your changes and close the file to continue.

Start the local execution environment

Before you can build the rust_profile project, you need to connect to the local execution environment running in your development environment or the decentralized Internet Computer blockchain mainnet.

在构建 rust_profile 项目之前,您需要连接到开发环境中运行的本地执行环境或去中心化互联网计算机区块链主网。

Start the local execution environment on your computer in the background by running the following command:

dfx start --background --clean

Depending on your platform and local security settings, you might see a warning displayed. If you are prompted to allow or deny incoming network connections, click Allow.

Register, build, and deploy your project

After you connect to the local execution environment running in your development environment, you can register, build, and deploy your project locally.

To do this, run the following command:

dfx deploy
Call functions on the deployed canister

After successfully deploying the canister, you can test the canister by calling the functions it provides.

For this guide:

  • Call the update function to add a profile.

  • Call the getSelf function to display the profile for the principal identity.

  • Call the search function to look up the profile using a keyword.

Updating records

Call the update function to create a profile record by running the following command:

dfx canister call rust_profile_backend update '(record {name = "Luxi"; description = "mountain dog"; keywords = vec {"scars"; "toast"}})'

In its current form, the dapp only stores and returns one profile. If you run the following command to add a second profile using the update function, the command replaces the Luxi profile with the Dupree profile:

dfx canister call rust_profile_backend update '(record {name = "Dupree"; description = "black dog"; keywords = vec {"funny tail"; "white nose"}})'

You can use the get, getSelf, and search functions, but they will only return results for the Dupree profile.

Retrieving records

Call the getSelf function to retrieve a profile record by running the following command:

dfx canister call rust_profile_backend getSelf

The command returns the profile you used the update function to add. For example:

(
record {
name = "Luxi";
description = "mountain dog";
keywords = vec { "scars"; "toast" };
},
)
Searching records

Run the following command to call the search function:

dfx canister call rust_profile_backend search '("black")'

This command finds the matching profile using the description and returns the profile:

(
opt record {
name = "Dupree";
description = "black dog";
keywords = vec { "funny tail"; "white nose" };
},
)
Adding profiles for new identities

In its current form, the dapp only stores one profile—the one associated with the principal invoking the commands. To test that the get, getSelf, and search functions do what we want them to, we need to add some new identities that can have different profiles.

在当前形式中,dapp 仅存储一个配置文件 - 与调用命令的主体关联的配置文件。 为了测试 get、getSelf 和搜索功能是否按照我们的要求执行,我们需要添加一些可以具有不同配置文件的新身份。

To add identities for testing, first create a new user identity by running the following command, enter a passphrase to secure the identity when prompted:

dfx identity new Miles

The following output will be returned:

Your seed phrase for identity 'Miles': recycle  ...
This can be used to reconstruct your key in case of emergency, so write it down in a safe place.
Created identity: "Miles".

Call the update function to add a profile for the new identity. Enter your passphrase when prompted.

dfx --identity Miles canister call rust_profile_backend update '(record {name = "Miles"; description = "Great Dane"; keywords = vec {"Boston"; "mantle"; "three-legged"}})'

Call the getSelf function to view the profile associated with the default user identity.

dfx canister call rust_profile_backend getSelf

The command displays the profile currently associated with the default identity, in this example, the Dupree profile:

(
record {
name = "Dupree";
description = "black dog";
keywords = vec { "funny tail"; "white nose" };
},
)

Call the getSelf function using the Miles user identity by running the following command:

dfx --identity Miles canister call rust_profile_backend getSelf

The command displays the profile currently associated with the Miles identity, in this example:

(
record {
name = "Miles";
description = "Great Dane";
keywords = vec { "Boston"; "mantle"; "three-legged" };
},
)

Call the search function using part of the description or a keyword to further test the whether the correct profile is returned.

For example, to verify the Miles profile is returned, you might run the following command:

dfx canister call rust_profile_backend search '("Great")'

The command returns the Miles profile:

(
opt record {
name = "Miles";
description = "Great Dane";
keywords = vec { "Boston"; "mantle"; "three-legged" };
},
)

Call the search function to further test the whether the correct profile is returned.

For example, to verify the Dupree profile is returned, you might run the following command:

dfx canister call rust_profile_backend search '("black")'

The command returns the Dupree profile:

(
opt record {
name = "Dupree";
description = "black dog";
keywords = vec { "funny tail"; "white nose" };
},
)

Adding and searching simple records
arkMeta Crypto Network Limited, arkSong October 9, 2023
Tags
Sign in to leave a comment

从 Rust 代理调用 IC
Calling IC from a Rust agent