Fauna
CloudEn distributed document-relational database med global consistency, GraphQL API, og serverless architecture.
Beskrivelse
Fauna er en moderne cloud database der kombinerer dokumenternes flexibilitet med relationelle databaser' konsistens og queryability. Den er helt serverless - ingen servere at administrere, automatic scaling, og pay-per-use pricing. Fauna bruger Calvin protokollen til at opnå distributed ACID transactions uden koordination overhead, hvilket giver både strong consistency og lav latency globally. Data modelleres som JSON-like documents organiseret i collections, men du kan definere relationships, indexes, og constraints ligesom i relationelle databaser. Fauna tilbyder multiple query interfaces: FQL (Fauna Query Language - functional programming style), GraphQL (auto-generated eller custom), og en GraphQL-compatible API. En unik feature er temporal queries - du kan query data som det så ud på et hvilket som helst tidspunkt i fortiden (time-travel queries). Fauna's security model bruger attribute-based access control (ABAC) med user-defined functions, hvilket giver granular permissions. Den kører på multiple clouds og regions for high availability.
Features
- •Distributed ACID transactions
- •GraphQL og FQL query languages
- •Temporal queries (time-travel)
- •Global replication med strong consistency
- •Attribute-based access control (ABAC)
- •Automatic indexing
- •Serverless architecture
- •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
- •Serverless applications
- •Global multi-region apps
- •Real-time collaborative applications
- •E-commerce med inventory management
Fordele
- ✓Strong consistency globally
- ✓Ingen servere at administrere
- ✓GraphQL native support
- ✓Temporal queries (versioning built-in)
- ✓Flexible data model (document + relational)
Ulemper
- ✗FQL har steep learning curve
- ✗Kan blive dyrt ved high volume
- ✗Vendor lock-in
- ✗Mindre community end etablerede databases
- ✗Query debugging kan være udfordrende
Bedst til
- →Jamstack sites (Next.js, Gatsby)
- →Serverless functions
- →Global applications med consistency requirements
- →GraphQL-first applications
- →Apps der har brug for audit trails (temporal)
Ikke anbefalet til
- ⚠Budget-conscious projekter
- ⚠Simple CRUD apps (overkill)
- ⚠Teams uden functional programming erfaring
- ⚠Applications med very high write volume
- ⚠Real-time gaming (latency constraints)