Flutter图数据库操作插件dgraph的使用

发布于 1周前 作者 h691938207 来自 Flutter

Flutter图数据库操作插件dgraph的使用

dgraph

Dgraph Dart客户端通过gRPC与服务器通信。

在使用此客户端之前,我们强烈建议您访问游dgraph.io文档dgraph.io以了解如何运行和使用Dgraph。

目录

支持的版本

根据您连接的Dgraph版本,您将需要使用不同的客户端版本。

Dgraph版本 dgraph客户端版本
dgraph 1.0.X dgraph客户端 0.5.0
dgraph 1.1.X dgraph客户端 1.1.X

注意:从dgraph客户端v0.5.0到v1.1.X最重要的API更改在于函数Txn.Mutate。该函数在v0.5.0返回一个api.Assigned值,但在v1.1.X返回一个api.Response值。

使用客户端

创建客户端

dgraphClient对象可以通过传递一个或多个api.DgraphApi客户端作为变参来初始化。连接到同一集群中的多个Dgraph服务器可以更好地分配工作负载。

以下代码片段仅展示了一个连接:

DgraphRpcClient rpcClient =
    DgraphRpcClient("localhost", 9080, const ChannelCredentials.insecure());
Dgraph dgraphClient = dgraph.NewDgraphClient(api.DgraphApi(rpcClient));

修改数据库

要设置模式,创建一个api.Operation实例并使用Alter端点。

api.Operation operation = api.Operation();
operation.schema = """
name: string @index(exact) .
""";
await dgraphClient.Alter(clientContext, operation);

Operation包含其他字段,包括dropAttrdropAlldropAll如果您希望丢弃所有数据,并从一个干净的起点开始,而不关闭实例,这很有用。dropAttr用于删除与谓词相关的所有数据。

创建事务

要创建事务,调用dgraphClient.NewTxn(),这会返回一个Txn对象。此操作不会产生网络开销。

最好在初始化后在finally块中调用txn.Discard()。在调用txn.Commit()之后调用txn.Discard()是一个空操作,您可以多次调用txn.Discard()而不会产生额外的副作用。

Txn txn;
ClientContext clientContext = ClientContext();
try {
  txn = dgraphClient.NewTxn();
  // 执行一些查询和变异。
  // 提交事务。
} finally {
  txn.Discard(clientContext);
}

只读事务可以通过调用dgraphClient.NewReadOnlyTxn()创建。只读事务有助于提高读取速度,因为它们可以绕过通常的共识协议。只读事务不能包含变异,并且尝试调用txn.Commit()将导致错误。调用txn.Discard()将是一个空操作。

运行变异

txn.Mutate(clientContext, mutation)运行变异。它接受一个ClientContext和一个api.Mutation对象。您可以使用JSON或RDF N-Quad格式设置数据。

为了使用JSON,使用setJson和deleteJson字段,它们接受一个表示要添加或删除的节点的编码字符串(要么是JSON映射,要么是列表)。为了使用RDF,使用setNquads和delNquads字段,它们接受一个表示有效RDF三元组(每行一个)的字符串,用于添加或删除。

定义一个Map来表示一个人,并将其转换为与Mutation对象一起使用。

Map<String, dynamic> p = {
  "uid": "_:alice",
  "name": "Alice",
};
List<int> pb = utf8.encode(json.encode(p));
api.Mutation mutation = api.Mutation();
mutation.setJson = pb;
api.Request request = api.Request();
request.mutations.add(mutation);
api.Response response = await txn.Mutate(clientContext, request);
print("Response: ${response.uids}");
// {alice: 0x5}

有时,您只想提交变异,而不进行进一步的查询。在这种情况下,您可以使用mutation.commitNow = true来指示必须立即提交变异。

运行查询

您可以调用txn.Query(clientContext, query)来运行查询。您需要传递一个GraphQL±查询字符串。如果您想传递任何变量,可以在查询中设置,可以调用txn.QueryWithVars(clientContext, query, vars),第三个参数为变量映射。

让我们运行以下带有变量$a的查询:

String query = """
query all(\$a: string) {
  all(func: eq(name, \$a)) {
    name
  }
}
""";
api.Response response =
    await txn.QueryWithVars(clientContext, query, {"\$a": "Alice"});
print("Response: ${utf8.decode(response.json)}");
// {"all":[{"name":"Alice"}]}

您也可以使用txn.Do函数来运行查询。

request = api.Request();
request.query = query;
request.vars.addAll({"\$a": "Alice"});
response = await txn.Do(clientContext, request);
print("Response: ${utf8.decode(response.json)}");
// {"all":[{"name":"Alice"}]}

当运行针对谓词name的模式查询时,模式响应在api.Responsejson字段中找到,如下所示:

String query = """
schema(pred: [name]) {
  type
  index
  reverse
  tokenizer
  list
  count
  upsert
  lang
}
""";
api.Response response = await txn.Query(clientContext, query);
print("Response: ${utf8.decode(response.json)}");
// {"schema":[{"predicate":"name","type":"string","index":true,"tokenizer":["exact"]}]}

提交事务

事务可以通过txn.Commit(clientContext)方法提交。如果您的事务仅由对txn.Querytxn.QueryWithVars的调用组成,并且没有对txn.Mutate的调用,则没有必要调用txn.Commit

如果其他并发运行的事务修改了此事务中修改的数据,则将返回错误。用户必须重试失败的事务。

Txn txn;
ClientContext clientContext = ClientContext();
try {
  txn = dgraphClient.NewTxn();
  // 执行一些查询和变异。
  await txn.Commit(clientContext);
} catch (e) {
  // 重试或处理错误
}

开发

运行测试

确保您安装了dgraph后再运行测试。此脚本将运行单元测试。

pub run test --concurrency=1

更新protobuf

要更新protobuf,请执行以下命令:

bash lib/protos/api/regenerate-proto.sh

示例代码

import 'package:dgraph/api.dart';
import 'package:dgraph/dgraph.dart';
import 'package:dgraph/protos/api/api.pb.dart' as api;
import 'package:dgraph/txn.dart';
import 'package:grpc/grpc.dart';
import 'package:protobuf/protobuf.dart';
import 'dart:convert';

void main(List<String> arguments) async {
  // 创建客户端
  DgraphRpcClient rpcClient =
      DgraphRpcClient("localhost", 9080, const ChannelCredentials.insecure());
  Dgraph dgraphClient = dgraph.NewDgraphClient(api.DgraphApi(rpcClient));

  Txn? txn;
  ClientContext clientContext = ClientContext();
  try {
    // 修改数据库
    api.Operation operation = api.Operation();
    operation.schema = """
    name: string @index(exact) .
    """;
    await dgraphClient.Alter(clientContext, operation);

    txn = dgraphClient.NewTxn();
    String query = """
    schema(pred: [name]) {
      type
      index
      reverse
      tokenizer
      list
      count
      upsert
      lang
    }
    """;
    api.Response response = await txn.Query(clientContext, query);
    print("Response: ${utf8.decode(response.json)}");
    txn.Discard(clientContext);

    // 创建事务
    txn = dgraphClient.NewTxn();

    // 运行变异
    Map<String, dynamic> p = {
      "uid": "_:alice",
      "name": "Alice",
      "age": 18,
    };
    List<int> pb = utf8.encode(json.encode(p));
    api.Mutation mutation = api.Mutation();
    mutation.setJson = pb;
    api.Request request = api.Request();
    request.mutations.add(mutation);
    response =
        await (txn.Mutate(clientContext, request) as Future<api.Response>);
    print("Response: ${response.uids}");

    // 运行查询
    query = """
    query all(\$a: string) {
      all(func: eq(name, \$a)) {
        name
        age
      }
    }
    """;
    response = await txn.QueryWithVars(clientContext, query, {"\$a": "Alice"});
    print("Response: ${utf8.decode(response.json)}");

    // 提交事务
    await txn.Commit(clientContext);

    // 修改数据库
    operation = api.Operation();
    operation.dropAttr = "age";
    await dgraphClient.Alter(clientContext, operation);

    // 创建另一个事务
    txn = dgraphClient.NewReadOnlyTxn();

    // 再次运行相同的查询
    response = await txn.QueryWithVars(clientContext, query, {"\$a": "Alice"});
    print("Response: ${utf8.decode(response.json)}");

    // 再次运行相同的查询,但现在使用txn.Do
    request = api.Request();
    request.query = query;
    request.vars.addAll({"\$a": "Alice"});
    response = await (txn.Do(clientContext, request) as Future<api.Response>);
    print("Response: ${utf8.decode(response.json)}");

    // 结束事务但不提交
    await txn.Discard(clientContext);

    // 修改数据库
    operation = api.Operation();
    operation.dropAll = true;
    await dgraphClient.Alter(clientContext, operation);
  } catch (e) {
    print("Error: $e");
  } finally {
    if (txn != null) {
      await txn.Discard(clientContext);
    }
  }
}

更多关于Flutter图数据库操作插件dgraph的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter图数据库操作插件dgraph的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用Dgraph图数据库操作插件的一个基本示例。由于Flutter本身没有直接的Dgraph插件,我们通常需要通过HTTP请求与Dgraph的GraphQL API进行交互。因此,我们会使用Dart的HTTP客户端库如httpdio来发送请求。

在这个示例中,我们将使用dio库,因为它提供了更丰富的功能和更好的错误处理。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加dio依赖:

dependencies:
  flutter:
    sdk: flutter
  dio: ^4.0.0  # 请检查最新版本号

然后运行flutter pub get来安装依赖。

2. 创建Dgraph服务类

接下来,我们创建一个服务类来处理与Dgraph的交互。

import 'package:dio/dio.dart';

class DgraphService {
  final Dio dio;

  DgraphService(String baseUrl) {
    dio = Dio(
      BaseOptions(
        baseUrl: baseUrl,
        connectTimeout: 5000,
        receiveTimeout: 3000,
      )
    );
  }

  // 发送GraphQL查询
  Future<Map<String, dynamic>> query(String query) async {
    try {
      Response response = await dio.post(
        "/query",
        data: {'query': query},
      );
      return response.data;
    } catch (e) {
      print("Error: $e");
      rethrow;
    }
  }

  // 发送GraphQL变更(mutation)
  Future<Map<String, dynamic>> mutate(String mutation) async {
    try {
      Response response = await dio.post(
        "/mutate",
        data: {'mutations': mutation.split('\n').map((e) => '{"set": $e}').toList()},
        options: Options(
          contentType: Headers.formUrlEncodedContentType,
        ),
      );
      return response.data;
    } catch (e) {
      print("Error: $e");
      rethrow;
    }
  }
}

3. 使用Dgraph服务类

现在,我们可以在Flutter应用中使用这个服务类来与Dgraph交互。

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:your_app/dgraph_service.dart';  // 假设你的文件名为dgraph_service.dart

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final DgraphService dgraphService = DgraphService("http://localhost:8080");  // Dgraph服务器地址
  String responseData = "";

  @override
  void initState() {
    super.initState();
    _executeQuery();
  }

  Future<void> _executeQuery() async {
    String query = """
      {
        all(func: eq(name, "Alice")) {
          uid
          name
        }
      }
    """;

    try {
      Map<String, dynamic> result = await dgraphService.query(query);
      setState(() {
        responseData = result.toString();
      });
    } catch (e) {
      print("Failed to execute query: $e");
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Dgraph Example'),
        ),
        body: Center(
          child: Text(responseData),
        ),
      ),
    );
  }
}

4. 运行应用

确保你的Dgraph服务器正在运行,并且可以通过http://localhost:8080访问。然后运行你的Flutter应用,你应该能够看到从Dgraph获取的数据。

注意

  1. 安全性:在实际应用中,不要在生产环境中硬编码敏感信息(如服务器地址和凭证)。使用环境变量或安全存储机制。
  2. 错误处理:上面的示例中简单地打印了错误。在实际应用中,你可能需要更详细的错误处理和用户反馈。
  3. 性能:对于大型数据集,可能需要优化查询和变更操作。

这个示例提供了一个基本的框架,你可以根据需要进行扩展和修改。

回到顶部