Fauna
CloudEn distribueret dokument-relationel database med global konsistens, GraphQL API og serverløs arkitektur.
Beskrivelse
Fauna er en moderne cloud-database der kombinerer dokumenternes fleksibilitet med relationelle databasers konsistens og forespørgselsevner. Den er helt serverløs - ingen servere at administrere, automatisk skalering og pay-per-use prissætning. Fauna bruger Calvin-protokollen til at opnå distribuerede ACID-transaktioner uden koordineringsoverhead, hvilket giver både stærk konsistens og lav latenstid globalt. Data modelleres som JSON-lignende dokumenter organiseret i collections, men du kan definere relationer, indekser og constraints ligesom i relationelle databaser. Fauna tilbyder flere forespørgselsgrænseflader: FQL (Fauna Query Language - funktionel programmeringsstil), GraphQL (auto-genereret eller brugerdefineret) og en GraphQL-kompatibel API. En unik funktion er temporale forespørgsler - du kan forespørge data som det så ud på et hvilket som helst tidspunkt i fortiden (tidsrejse-forespørgsler). Fauna's sikkerhedsmodel bruger attributbaseret adgangskontrol (ABAC) med brugerdefinerede funktioner, hvilket giver granulære tilladelser. Den kører på flere clouds og regioner for høj tilgængelighed.
Features
- •Distribuerede ACID-transaktioner
- •GraphQL og FQL-forespørgselssprog
- •Temporale forespørgsler (tidsrejse)
- •Global replikering med stærk konsistens
- •Attributbaseret adgangskontrol (ABAC)
- •Automatisk indeksering
- •Serverløs arkitektur
- •Multi-tenancy support
Query Eksempel
// Fauna Query Language (FQL)
// 1. Opret collection
CreateCollection({ name: "users" })
CreateCollection({ name: "posts" })
// 2. Opret indexes
CreateIndex({
name: "users_by_email",
source: Collection("users"),
terms: [{ field: ["data", "email"] }],
unique: true
})
CreateIndex({
name: "posts_by_user",
source: Collection("posts"),
terms: [{ field: ["data", "userId"] }]
})
// 3. Opret document
Create(
Collection("users"),
{
data: {
email: "peter@email.dk",
name: "Peter Hansen",
createdAt: Time("now")
}
}
)
// 4. Find document
Get(
Match(Index("users_by_email"), "peter@email.dk")
)
// 5. Update document
Update(
Ref(Collection("users"), "12345"),
{
data: {
name: "Peter H. Hansen"
}
}
)
// 6. Query med relations
Let(
{
userRef: Match(Index("users_by_email"), "peter@email.dk"),
user: Get(Var("userRef")),
posts: Map(
Paginate(Match(Index("posts_by_user"), Select(["ref"], Var("user")))),
Lambda("postRef", Get(Var("postRef")))
)
},
{
user: Var("user"),
posts: Var("posts")
}
)
// 7. Transaction
Do(
Create(
Collection("users"),
{ data: { email: "new@email.dk", name: "New User" } }
),
Create(
Collection("posts"),
{ data: { userId: "123", title: "First Post" } }
)
)
// JavaScript Driver
import faunadb from 'faunadb'
const q = faunadb.query
const client = new faunadb.Client({
secret: 'your-secret-key'
})
// Create
const result = await client.query(
q.Create(
q.Collection('users'),
{
data: {
email: 'js@email.dk',
name: 'JavaScript User'
}
}
)
)
// Read
const user = await client.query(
q.Get(
q.Match(q.Index('users_by_email'), 'js@email.dk')
)
)
// Update
await client.query(
q.Update(
q.Ref(q.Collection('users'), user.ref.id),
{ data: { name: 'Updated Name' } }
)
)
// Delete
await client.query(
q.Delete(q.Ref(q.Collection('users'), user.ref.id))
)
// Temporal query (time-travel!)
const historicalData = await client.query(
q.At(
q.Time('2024-01-01T00:00:00Z'),
q.Get(q.Ref(q.Collection('users'), '12345'))
)
)
// GraphQL Schema
type User {
email: String! @unique
name: String!
posts: [Post!] @relation
}
type Post {
title: String!
content: String
author: User!
published: Boolean!
}
type Query {
allUsers: [User!]
userByEmail(email: String!): User
}
// GraphQL Query
query {
userByEmail(email: "peter@email.dk") {
name
email
posts {
data {
title
published
}
}
}
}
// GraphQL Mutation
mutation {
createUser(data: {
email: "graphql@email.dk"
name: "GraphQL User"
}) {
_id
email
name
}
}
// React eksempel
import { useQuery, useMutation } from '@apollo/client'
import { gql } from '@apollo/client'
const GET_USERS = gql`
query GetUsers {
allUsers {
data {
_id
name
email
}
}
}
`
function UserList() {
const { loading, error, data } = useQuery(GET_USERS)
if (loading) return <p>Loading...</p>
if (error) return <p>Error: {error.message}</p>
return (
<ul>
{data.allUsers.data.map(user => (
<li key={user._id}>{user.name} - {user.email}</li>
))}
</ul>
)
}Anvendelsesområder
- •Jamstack-websites og static site generators
- •Serverløse applikationer
- •Globale multi-region apps
- •Realtids-samarbejdsapplikationer
- •E-handel med lagerstyring
Fordele
- ✓Stærk konsistens globalt
- ✓Ingen servere at administrere
- ✓Native GraphQL-support
- ✓Temporale forespørgsler (indbygget versionering)
- ✓Fleksibel datamodel (dokument + relationel)
Ulemper
- ✗FQL har stejl indlæringskurve
- ✗Kan blive dyrt ved høj volumen
- ✗Leverandørbinding
- ✗Mindre community end etablerede databaser
- ✗Fejlfinding af forespørgsler kan være udfordrende
Bedst til
- →Jamstack-sites (Next.js, Gatsby)
- →Serverløse funktioner
- →Globale applikationer med konsistenskrav
- →GraphQL-first applikationer
- →Apps der har brug for revisionsspor (temporale)
Ikke anbefalet til
- ⚠Budgetbevidste projekter
- ⚠Simple CRUD-apps (overkill)
- ⚠Teams uden funktionel programmeringserfaring
- ⚠Applikationer med meget høj skrivevolumen
- ⚠Realtidsspil (latenstidsbegrænsninger)