# Entities

Continuing from the setup, now we will be declaring entities for the GraphQL API.

Let's say for this example, we will have a user management system where the API can be used to create, find, update, and delete user profile(s).

# User profiles

Declaring the User model is fairly straight forward.

User.swift
struct User: Identifiable, Codable, Sendable {
    var id: UUID
    var username: String?
    var email: String
    var bio: String

    var displayName: String {
        username ?? email
    }

    var friendIDs: [UUID]
}

Here, we have a couple properties and some computed ones as well. All things should be pretty self-explanatory.

# User inputs

We also want an entity for the input that the API client will give to create and/or update a User profile.

import Pioneer

struct UserInput: Codable {
    var username: String?
    var email: String
    var bio: String
    var friendIDs: [ID]
}

extension User {
    init(id: ID = .uuid(), _ input: UserInput) {
        self.init(
            id: UUID(id.string) ?? UUID(),
            username: input.username,
            email: input.email,
            bio: input.bio,
            friendIDs: input.friendIDs.compactMap { UUID($0) },
        )
    }
}

# Datastore

In a real application, you want these User(s) to be stored in a persistent database like PostgreSQL or something similar. For this example, we will be simplying the workflow by just building one in memory.

Fluent FAQ
../../advanced/fluent/

We will be taking advantange of Swift 5.5 actor which a structure suitable for cocurrent state management.

import Pioneer

actor Datastore {
    private var users: [ID: User] = [:]

    func find(with ids: [ID]) async -> [User] {
        ids.compactMap { users[$0] }
    }

    func select() async -> [User] {
        users.values.filter(predicate)
    }

    func insert(_ newUser: User) async -> User {
        users[newUser._id] = newUser
        return newUser
    }

    func update(for id: ID, with newUser: User) async -> User? {
        guard let _ = users[id] else {
            return nil
        }

        users[id] = newUser
        return newUser
    }

    func delete(for id: ID) async -> User? {
        guard let user = users[id] else {
            return nil
        }
        users.removeValue(forKey: id)
        return user
    }

    static let shared: Self = .init()
}

This actor should look fairly straightforward.