Faunadb

2023-09-16 00:14:51

Faunadb和google spanner都属于云分布式数据库天然支持分片(无需做分表分库操作,一库搞定,当然价格另说),国内的也有比如TiDB  Oceanbase等

本文使用java语言,其他语言可以跳过;有想直接使用的可以参考(无法访问外网,可以搞个vpn吧!!!,有时会遇到网络问题):GitHub - fauna/faunadb-jvm: Scala and Java driver for FaunaDB v4

此文旨在想了解的小伙伴看看(免费使用30天)

本文演示使用的jdk版本为jdk21

目录

1.登录账号

2.了解一下FQL

3. 创建数据库,创建集合

4.点击搜索框中的dashbord进入到控制台然后到控制台创建集合

5. 生成数据库秘钥

6.springboot整合项目

7.实体

8.service及接口

9.属性文件配置属性

10.controller

11.启动后postman试试


1.登录账号

使用github账号或者注册一个

Welcome to Fauna docs - Fauna Documentation

2.了解一下FQL

建议按照图看下去

3. 创建数据库,创建集合

最好是跟着官网文档走

4.点击搜索框中的dashbord进入到控制台然后到控制台创建集合

(参考:使用 Spring Boot 使用 Fauna 和 Java 开始构建_rxjava_云O生-云原生

最新的不一样,使用下面语法

Collection.create({
  name: 'todos'
})

5. 生成数据库秘钥

记住不要到account哪里去申请

6.springboot整合项目

依赖

<dependency>
<groupId>com.faunadb</groupId>
<artifactId>faunadb-java</artifactId>
<version>4.4.0</version>
<scope>compile</scope>
</dependency>

实体\service\controller均参考博文:使用 Spring Boot 使用 Fauna 和 Java 开始构建_rxjava_云O生-云原生

7.实体

参考这个也行:GitHub - fauna/faunadb-jvm: Scala and Java driver for FaunaDB v4

import lombok.Data;

@Data
public abstract class Entity {
    protected  String id;
}
import java.util.List;
import java.util.Optional;

public class Page <T> {

    private List<T> data;
    private Optional<String> before;
    private Optional<String> after;


    public Page(List<T> data, Optional<String> before, Optional<String> after) {
        this.data = data;
        this.before = before;
        this.after = after;
    }

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    public Optional<String> getBefore() {
        return before;
    }

    public void setBefore(Optional<String> before) {
        this.before = before;
    }

    public Optional<String> getAfter() {
        return after;
    }

    public void setAfter(Optional<String> after) {
        this.after = after;
    }
}
package com.rulecheck.entity;

import java.util.Optional;

public class PaginationOptions {
    private Optional<Integer> size;
    private Optional<String> before;
    private Optional<String> after;


    public PaginationOptions(Optional<Integer> size, Optional<String> before, Optional<String> after) {
        this.size = size;
        this.before = before;
        this.after = after;
    }

    public Optional<Integer> getSize() {
        return size;
    }

    public void setSize(Optional<Integer> size) {
        this.size = size;
    }

    public Optional<String> getBefore() {
        return before;
    }

    public void setBefore(Optional<String> before) {
        this.before = before;
    }

    public Optional<String> getAfter() {
        return after;
    }

    public void setAfter(Optional<String> after) {
        this.after = after;
    }
}


import com.faunadb.client.types.FaunaConstructor;
import com.faunadb.client.types.FaunaField;

public class TodoEntity extends Entity {

    @FaunaField
    private String title;

    @FaunaField
    private String description;

    @FaunaConstructor
    public TodoEntity(@FaunaField("id") String id,
                      @FaunaField("title") String title,
                      @FaunaField("description") String description) {
        this.id = id;
        this.title = title;
        this.description = description;

    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
package com.rulecheck.entity;

public class CreateOrUpdateTodoData {

    private String title;
    private String description;

    public CreateOrUpdateTodoData(String title, String description) {
        this.title = title;
        this.description = description;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

8.service及接口

package com.rulecheck.service;

import com.faunadb.client.FaunaClient;
import com.faunadb.client.errors.NotFoundException;
import com.faunadb.client.query.Expr;
import com.faunadb.client.query.Pagination;
import com.faunadb.client.types.Value;
import com.rulecheck.entity.Entity;
import com.rulecheck.entity.Page;
import com.rulecheck.entity.PaginationOptions;
import jakarta.annotation.Resource;

import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.faunadb.client.query.Language.*;

import java.lang.Class;

public abstract class FaunaRepository<T extends Entity > implements Repository<T>, IdentityFactory {

    @Resource
    private FaunaClient faunaClient;

    protected final Class<T> entityType;
    protected final String collectionName;
    protected final String collectionIndexName;


    protected FaunaRepository(Class<T> entityType, String collectionName, String collectionIndexName) {
        this.entityType = entityType;
        this.collectionName = collectionName;
        this.collectionIndexName = collectionIndexName;
    }

    // This method returns a unique valid Id leveraging Fauna's NewId function.
    @Override
    public CompletableFuture<String> nextId() {

        CompletableFuture<String> result =
                faunaClient.query(
                        NewId()
                )
                        .thenApply(value -> value.to(String.class).get());

        return result;
    }

    // This method saves an entity to the database using the saveQuery method below. It also returns the result of the saved entity.
    @Override
    public CompletableFuture<T> save(T entity) {
        CompletableFuture<T> result =
                faunaClient.query(
                        saveQuery(Value(entity.getId()), Value(entity))
                )
                        .thenApply(this::toEntity);

        return result;
    }

    // This method deletes from the data an entity(document) with the specified Id. 
    @Override
    public CompletableFuture<Optional<T>> remove(String id) {
        CompletableFuture<T> result =
                faunaClient.query(
                        Select(
                                Value("data"),
                                Delete(Ref(Collection(collectionName), Value(id)))
                        )
                )
                        .thenApply(this::toEntity);

        CompletableFuture<Optional<T>> optionalResult = toOptionalResult(result);

        return optionalResult;
    }

    // This method finds an entity by its Id and returns the entity result.
    @Override
    public CompletableFuture<Optional<T>> find(String id) {
        CompletableFuture<T> result =
                faunaClient.query(
                        Select(
                                Value("data"),
                                Get(Ref(Collection(collectionName), Value(id)))
                        )
                )
                        .thenApply(this::toEntity);

        CompletableFuture<Optional<T>> optionalResult = toOptionalResult(result);

        return optionalResult;
    }

    // This method returns all entities(documents) in the database collection using the paginationOptions parameters.
    @Override
    public CompletableFuture<Page<T>> findAll(PaginationOptions po) {
        Pagination paginationQuery = Paginate(Match(Index(Value(collectionIndexName))));
        po.getSize().ifPresent(size -> paginationQuery.size(size));
        po.getAfter().ifPresent(after -> paginationQuery.after(Ref(Collection(collectionName), Value(after))));
        po.getBefore().ifPresent(before -> paginationQuery.before(Ref(Collection(collectionName), Value(before))));

        CompletableFuture<Page<T>> result =
                faunaClient.query(
                        Map(
                                paginationQuery,
                                Lambda(Value("nextRef"), Select(Value("data"), Get(Var("nextRef"))))
                        )
                ).thenApply(this::toPage);

        return result;
    }


    // This is the saveQuery expression method used by the save method to persist the database.
    protected Expr saveQuery(Expr id, Expr data) {
        Expr query =
                Select(
                        Value("data"),
                        If(
                                Exists(Ref(Collection(collectionName), id)),
                                Replace(Ref(Collection(collectionName), id), Obj("data", data)),
                                Create(Ref(Collection(collectionName), id), Obj("data", data))
                        )
                );

        return query;
    }

    // This method converts a FaunaDB Value into an Entity.
    protected T toEntity(Value value) {
        return value.to(entityType).get();
    }

    // This method returns an optionalResult from a CompletableFuture<T> result.
    protected CompletableFuture<Optional<T>> toOptionalResult(CompletableFuture<T> result) {
        CompletableFuture<Optional<T>> optionalResult =
                result.handle((v, t) -> {
                    CompletableFuture<Optional<T>> r = new CompletableFuture<>();
                    if(v != null) r.complete(Optional.of(v));
                    else if(t != null && t.getCause() instanceof NotFoundException) r.complete(Optional.empty());
                    else r.completeExceptionally(t);
                    return r;
                }).thenCompose(Function.identity());

        return optionalResult;
    }

    // This method converts a FaunaDB Value into a Page with the Entity type.
    protected Page<T> toPage(Value value) {

        Optional<String> after = value.at("after").asCollectionOf(Value.RefV.class).map(c -> c.iterator().next().getId()).getOptional();
        Optional<String> before = value.at("before").asCollectionOf(Value.RefV.class).map(c -> c.iterator().next().getId()).getOptional();

        List<T> data = value.at("data").collect(entityType).stream().collect(Collectors.toList());

        Page<T> page = new Page(data, before, after);

        return page;
    }

}

import java.util.concurrent.CompletableFuture;

public interface IdentityFactory {

    CompletableFuture<String> nextId();
}


import com.rulecheck.entity.Entity;
import com.rulecheck.entity.Page;
import com.rulecheck.entity.PaginationOptions;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;

public interface Repository<T extends Entity> {

    // This method saves the given Entity into the Repository.
    CompletableFuture<T> save(T entity);

    // This method finds an Entity for the given Id
    CompletableFuture<Optional<T>> find(String id);

    // This method retrieves a Page of TodoEntity entities for the given PaginationOptions
    CompletableFuture<Page<T>> findAll(PaginationOptions po);

    // This method finds the Entity for the given Id and removes it. If no Entity can be found for the given Id an empty result is returned.
    CompletableFuture<Optional<T>> remove(String id);
}
import com.rulecheck.entity.TodoEntity;
import org.springframework.stereotype.Repository;
@Repository
public class TodoRepository extends FaunaRepository<TodoEntity> {

    public TodoRepository(){
        super(TodoEntity.class, "todos", "all_todos");
    }

    //-- Custom repository operations specific to the TodoEntity will go below --//

}



import com.rulecheck.entity.CreateOrUpdateTodoData;
import com.rulecheck.entity.Page;
import com.rulecheck.entity.PaginationOptions;
import com.rulecheck.entity.TodoEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;

@Service
public class TodoService {

    @Autowired
    private TodoRepository todoRepository;

    public CompletableFuture<TodoEntity> createTodo(CreateOrUpdateTodoData data) {
        CompletableFuture<TodoEntity> result =
                todoRepository.nextId()
                        .thenApply(id -> new TodoEntity(id, data.getTitle(), data.getDescription()))
                        .thenCompose(todoEntity -> todoRepository.save(todoEntity));

        return result;
    }

    public CompletableFuture<Optional<TodoEntity>> getTodo(String id) {
        return todoRepository.find(id);
    }

    public CompletableFuture<Optional<TodoEntity>> updateTodo(String id, CreateOrUpdateTodoData data) {
        CompletableFuture<Optional<TodoEntity>> result =
                todoRepository.find(id)
                        .thenCompose(optionalTodoEntity ->
                                optionalTodoEntity
                                        .map(todoEntity -> todoRepository.save(new TodoEntity(id, data.getTitle(), data.getDescription())).thenApply(Optional::of))
                                        .orElseGet(() -> CompletableFuture.completedFuture(Optional.empty())));

        return result;
    }

    public CompletableFuture<Optional<TodoEntity>> deleteTodo(String id) {
        return todoRepository.remove(id);
    }

    public CompletableFuture<Page<TodoEntity>> getAllTodos(PaginationOptions po) {
        return todoRepository.findAll(po);
    }
}
import com.faunadb.client.FaunaClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;


/**
 * description:
 */

@Slf4j
@SpringBootApplication
public class RuleCheckApplication {

    @Value("${fauna-db.secret}")
    private String serverKey;

    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
    public FaunaClient faunaConfiguration() {
        log.info("serverKey:{}", serverKey);
        FaunaClient faunaClient = FaunaClient.builder()
                .withSecret(serverKey)
                .build();

        return faunaClient;
    }

    public static void main(String[] args) {
        SpringApplication.run(RuleCheckApplication.class, args);
    }

}

9.属性文件配置属性

fauna-db.secret=fnAFN6K4SxAAQWm.........  自己生成数据库秘钥,非账户秘钥或者密码

10.controller

package com.rulecheck.controller;


import com.rulecheck.entity.CreateOrUpdateTodoData;
import com.rulecheck.entity.Page;
import com.rulecheck.entity.PaginationOptions;
import com.rulecheck.entity.TodoEntity;
import com.rulecheck.service.TodoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;

@RestController
public class TodoRestController {

    @Autowired
    private TodoService todoService;


    @PostMapping("/todos")
    public CompletableFuture<ResponseEntity> createTodo(@RequestBody CreateOrUpdateTodoData data) {

        return todoService.createTodo(data)
                .thenApply(todoEntity -> new ResponseEntity(todoEntity, HttpStatus.CREATED));
    }


    @GetMapping("/todos/{id}")
    public CompletableFuture<ResponseEntity> getTodo(@PathVariable("id") String id) {
        CompletableFuture<ResponseEntity> result =
                todoService.getTodo(id)
                        .thenApply(optionalTodoEntity ->
                                optionalTodoEntity
                                        .map(todoEntity -> new ResponseEntity(todoEntity, HttpStatus.OK))
                                        .orElseGet(() -> new ResponseEntity(HttpStatus.NOT_FOUND))
                        );
        return result;
    }


    @PutMapping("/todos/{id}")
    public CompletableFuture<ResponseEntity> updateTodo(@PathVariable("id") String id, @RequestBody CreateOrUpdateTodoData data) {
        CompletableFuture<ResponseEntity> result =
                todoService.updateTodo(id, data)
                        .thenApply(optionalTodoEntity ->
                                optionalTodoEntity
                                        .map(todoEntity -> new ResponseEntity(todoEntity, HttpStatus.OK))
                                        .orElseGet(() -> new ResponseEntity(HttpStatus.NOT_FOUND)
                                        )
                        );
        return result;
    }

    @DeleteMapping(value = "/todos/{id}")
    public CompletableFuture<ResponseEntity> deletePost(@PathVariable("id")String id) {
        CompletableFuture<ResponseEntity> result =
                todoService.deleteTodo(id)
                        .thenApply(optionalTodoEntity ->
                                optionalTodoEntity
                                        .map(todo -> new ResponseEntity(todo, HttpStatus.OK))
                                        .orElseGet(() -> new ResponseEntity(HttpStatus.NOT_FOUND)
                                        )
                        );
        return result;
    }

    @GetMapping("/todos")
    public CompletableFuture<Page<TodoEntity>> getAllTodos(
            @RequestParam("size") Optional<Integer> size,
            @RequestParam("before") Optional<String> before,
            @RequestParam("after") Optional<String> after) {
        PaginationOptions po = new PaginationOptions(size, before, after);
        CompletableFuture<Page<TodoEntity>> result = todoService.getAllTodos(po);
        return result;
    }
}

11. 参考pom依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.3</version>
        <relativePath></relativePath>
    </parent>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <mybatis-plus-boot-starter>3.5.3.1</mybatis-plus-boot-starter>
        <mysql-connector-java>8.0.28</mysql-connector-java>
        <commons-io>2.11.0</commons-io>
    </properties>
<!--    <packaging>jar</packaging>-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus-boot-starter}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
           <version>${mysql-connector-java}</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>${mybatis-plus-boot-starter}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
        </dependency>

        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>${commons-io}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.faunadb</groupId>
            <artifactId>faunadb-java</artifactId>
            <version>4.4.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

11.启动后postman试试

http://localhost:8080/todos

{

    "title":"create a job",

    "description":"this post request is todos"

}

更多推荐

恒运资本:沪指震荡涨0.28%,医药板块强势拉升,金融等板块上扬

15日早盘,沪指盘中震荡上扬,科创50指数表现强势;北向资金小幅净流入。到午间收盘,沪指涨0.28%报3135.31点,深成指、创业板指涨均0.11%,科创50指数涨1.04%;两市合计成交4357亿元,北向资金净买入1.13亿元。盘面上看,医药、医疗保健板块涨幅居前,旅游、半导体、零售、纺织服装、钢铁、石油、地产、保

虚拟机Ubuntu操作系统常用终端命令(3)(详细解释+详细演示)

本篇概要本篇讲述了Ubuntu操作系统常用的几个功能,即修改文件权限、修改文件属性、可执行脚本、虚拟机网络、FTP服务器、SSH服务器、VIM等方面的知识。希望能够得到大家的支持。文章目录本篇概要1.修改文件权限2.修改文件属主3.可执行脚本3.1要点与细节3.2shell脚本3.3Python脚本4.虚拟机网络4.1

最长公共子序列(最详细的动态规划案例)

#include<iostream>#include<vector>usingnamespacestd;intmain(){stringtext1,text2;while(cin>>text1>>text2){//创建二维数组dp,行数text1.size()+1,列数text2.size()+1,并全部初始化为0ve

Python灰帽编程——初识Python下(函数与文件)

1.函数需求:随机密码生成器。逻辑上讲,函数就是一个功能;代码上讲,多条Python语句的集合,语句块。1.1函数介绍1.1.1函数基本概念逻辑上讲,函数就是一个功能;代码上讲,函数就是多条Python语句的集合,语句块。函数是对程序逻辑进行结构化或过程化的一种编程方法,将整块代码巧妙地隔离成易于管理的小块。把重复代码

13年12月CCF计算机软件能力认证

4、有趣的数时间限制:1.0s内存限制:256.0MB问题描述:问题描述我们把一个数称为有趣的,当且仅当:1.它的数字只包含0,1,2,3,且这四个数字都出现过至少一次。2.所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。3.最高位数字不为0。因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的

invoke与begininvoke区别

`Invoke`和`BeginInvoke`是用于在多线程应用程序中执行委托的两种不同方法,它们之间的主要区别在于同步和异步执行:1.`Invoke`:-`Invoke`是一个同步方法,它会在当前线程中执行委托。-调用`Invoke`方法会阻塞当前线程,直到委托的执行完成,然后才继续执行后续代码。-这意味着如果在主线程

计算机视觉与深度学习-经典网络解析-VGG-[北邮鲁鹏]

目录标题VGG参考VGG网络贡献使用尺寸更小的$3\times3$卷积串联来获得更大的感受野放弃使用$11\times11$和$5\times5$这样的大尺寸卷积核深度更深、非线性更强,网络的参数也更少;去掉了AlexNet中的局部响应归一化层(LRN)层。网络结构主要改进输入去均值小卷积核串联代替大卷积核无重叠池化卷

TikTok如何打造爆款视频?超店有数让你的视频上热门!

作为TikTok视频博主,你肯定面临着以下难题:播放量卡1000,粉丝数原地踏步。视频创意枯竭,不知道拍什么?不知道拍什么会火?流行趋势慢人一步,热点捉摸不透?一直在模仿,从未有超越。拍摄费时费力,视频制作效率低下...然而!别人家却是这样:粉丝量低的博主也能随随便便播放量破10W+,一条视频带爆粉丝数的翻几番。点赞、

C语言中的sizeof运算符的作用是什么?

在C语言中,sizeof运算符是一个非常重要的运算符,它用于计算数据类型或表达式的大小(以字节为单位)。这个运算符在C语言中的作用非常广泛,它可以帮助程序员确定内存的分配和数据类型的大小,从而更好地管理内存和优化程序性能。在本文中,我们将详细探讨sizeof运算符的作用、用法以及一些示例,以帮助C语言初学者更好地理解它

【计组】计算机系统体系结构

【计组】计算机系统体系结构文章目录【计组】计算机系统体系结构1、体系的发展与思维变化1.1计算机发展1.2冯诺依曼体系2、计算机系统2.1CPU2.2存储层次2.2.1寄存器2.2.2高速缓存(Cache)2.2.3动态随机访问存储器(DRAM)2.2.4硬盘2.3总线2.3.1总线层次2.3.2总线属性1、体系的发展

想要精通算法和SQL的成长之路 - 环形子数组的最大和

想要精通算法和SQL的成长之路-环形子数组的最大和前言一.环形子数组的最大和1.1空间优化前言想要精通算法和SQL的成长之路-系列导航一.环形子数组的最大和原题链接在写这道题目之前,可以先看下这个题:最大子数组和。本题是它的进阶版本,在原本的基础上,有一个环状的数组。那么我们如果将其平铺开来,就是一个两段数组拼接而成。

热文推荐