본문으로 건너뛰기
cccskills
무료GitHub에 공개

grain-read-model

Build read models by reducing events into queryable state

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md4.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Grain Read Model Pattern

Required Imports

(ns my.service.core.read-models
  (:require [ai.obney.grain.event-store-v3.interface :as event-store]))

Event Type Sets

Define which events affect each read model:

(def contact-events
  #{:crm/contact-created
    :crm/contact-updated
    :crm/contact-field-set
    :crm/contact-archived
    :crm/contact-deleted})

(def relationship-events
  #{:crm/relationship-created
    :crm/relationship-updated
    :crm/relationship-ended})

Projection Multimethod

;; Dispatch on event type
(defmulti contacts*
  (fn [_state event] (:event/type event)))

;; Handle creation
(defmethod contacts* :crm/contact-created
  [state event]
  (assoc state (:contact-id event)
         {:id (:contact-id event)
          :type-slug (:type-slug event)
          :display-name (:display-name event)
          :field-values (:field-values event)
          :status :active
          :created-at (str (:event/timestamp event))}))

;; Handle update
(defmethod contacts* :crm/contact-updated
  [state event]
  (-> state
      (update (:contact-id event) merge (:changes event))
      (assoc-in [(:contact-id event) :updated-at] (str (:event/timestamp event)))))

;; Handle field set
(defmethod contacts* :crm/contact-field-set
  [state event]
  (-> state
      (assoc-in [(:contact-id event) :field-values (keyword (:field-slug event))]
                (:new-value event))
      (assoc-in [(:contact-id event) :updated-at] (str (:event/timestamp event)))))

;; Handle archive
(defmethod contacts* :crm/contact-archived
  [state event]
  (assoc-in state [(:contact-id event) :status] :archived))

;; Default: ignore unknown events
(defmethod contacts* :default [state _] state)

;; Reduction function
(defn contacts
  "Build contacts read model from events"
  [initial-state events]
  (reduce contacts* initial-state events))

Query Helper Functions

Get Single Entity

(defn get-contact
  "Get a single contact by ID"
  [event-store contact-id]
  (let [events (event-store/read event-store
                                 {:types contact-events
                                  :tags #{[:contact contact-id]}})]
    (get (contacts {} events) contact-id)))

Get All Entities

(defn get-contacts-all
  "Get all contacts"
  [event-store]
  (let [events (event-store/read event-store {:types contact-events})]
    (vals (contacts {} events))))

Get by Filter

(defn get-contacts-by-type
  "Get contacts of a specific type"
  [event-store type-slug]
  (let [events (event-store/read event-store {:types contact-events})]
    (->> (contacts {} events)
         vals
         (filter #(= type-slug (:type-slug %))))))

Batch Loading

(defn get-contacts-batch
  "Get multiple contacts by IDs in a single read"
  [event-store contact-ids]
  (when (seq contact-ids)
    (let [tags (set (map #(vector :contact %) contact-ids))
          events (event-store/read event-store
                                   {:types contact-events
                                    :tags tags})]
      (contacts {} events))))

Composing Projections

(defn get-contact-with-attribution
  "Get contact with attribution in single query"
  [event-store contact-id]
  (let [events (event-store/read event-store
                                 {:types (into contact-events attribution-events)
                                  :tags #{[:contact contact-id]}})
        contact (get (contacts {} events) contact-id)
        attr (get (attributions {} events) contact-id)]
    (cond-> contact
      attr (assoc :attribution attr))))

Event Store Read Options

;; By event types
{:types #{:crm/contact-created :crm/contact-updated}}

;; By tags (entities)
{:tags #{[:contact contact-id]}}

;; After specific event (for incremental updates)
{:types #{:crm/contact-field-set}
 :after last-processed-event-id}

;; Combined
{:types contact-events
 :tags #{[:contact contact-id]}
 :after last-event-id}

Conventions

  • State is a map keyed by entity ID: {uuid1 {...} uuid2 {...}}
  • Use assoc for create, update/assoc-in for modify
  • Always provide :default method to ignore unknown events
  • Query helpers read events then reduce to current state
  • Use tags for efficient filtering (avoid reading all events)
  • Batch load related data to avoid N+1 queries

Reference Files

  • components/user-service/src/ai/obney/workshop/user_service/core/read_models.clj - User projections
  • components/crm-service/src/ai/obney/workshop/crm_service/core/read_models.clj - CRM projections

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

allium

무료

Give your AI agents something more useful than a prompt. Velocity through clarity.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

ObneyAI/orc222026년 10월 8일 업데이트

distill

무료

Extract an Allium specification from an existing codebase. Use when the user has existing code and wants to distil behaviour into a spec, reverse engineer a specification from implementation, generate a spec from code, turn implementation into a behavioural specification, or document what a codebase does in Allium terms.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

ObneyAI/orc222026년 10월 8일 업데이트

elicit

무료

Run a structured discovery session to build an Allium specification through conversation. Use when the user wants to create a new spec from scratch, elicit or gather requirements, capture domain behaviour, specify a feature or system, define what a system should do, or is describing functionality and needs help shaping it into a specification.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

ObneyAI/orc222026년 10월 8일 업데이트

Implement command handlers that validate state and emit events using the Grain framework

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

ObneyAI/orc222026년 10월 8일 업데이트

Create scheduled background jobs that run on cron schedules

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

ObneyAI/orc222026년 10월 8일 업데이트

Implement query handlers that read from event-sourced read models

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

ObneyAI/orc222026년 10월 8일 업데이트

ObneyAI의 스킬 모두 보기

이 스킬의 문제 신고