### Enter Development Environment Source: https://github.com/mostlyobvious/en57/blob/master/README.md Use this command to enter the development environment managed by devenv. It sets up the Ruby and PostgreSQL toolchain and installs gem dependencies. ```sh devenv shell ``` -------------------------------- ### Migrate Database Schema Source: https://github.com/mostlyobvious/en57/blob/master/README.md Run this command to install or update the En57 PostgreSQL schema. Ensure DATABASE_URL is set. ```sh DATABASE_URL=postgres://localhost:5432/en57 bundle exec rake en57:migrate ``` -------------------------------- ### Start PostgreSQL Services Source: https://github.com/mostlyobvious/en57/blob/master/README.md Commands to bring PostgreSQL services up. Use the foreground option for interactive use or detached mode for background operation. Stop detached services with `devenv processes down`. ```sh devenv up # foreground; Ctrl-C to stop ``` ```sh devenv up -d # detached; stop later with `devenv processes down` ``` -------------------------------- ### Conditional Write for Optimistic Concurrency Source: https://github.com/mostlyobvious/en57/blob/master/README.md Append an event only if a specific condition is met, preventing race conditions. This example ensures credits are used only once per account. ```ruby account_scope = event_store.read.with_tag("account:x") result = event_store.append( [ En57::Event.new( type: "CreditsUsed", data: { amount: 100 }, tags: ["account:x"], ), ], fail_if: account_scope.of_type("CreditsUsed"), ) case result in En57::Success(position:) # credits consumed at event position in En57::Failure(position:, conflicting_events:) # lost the race; conflicting_events contains the events that matched # the fail_if condition, with position set to the latest conflict end ``` -------------------------------- ### Conditional Write for Email Uniqueness Source: https://github.com/mostlyobvious/en57/blob/master/README.md Append an event only if no prior event exists with a specific tag, ensuring uniqueness. This example prevents duplicate user registrations with the same email. ```ruby email_tag = "email:alice@example.com" result = event_store.append( [ En57::Event.new( type: "UserRegistered", data: { name: "Alice" }, tags: [email_tag], ), ], fail_if: event_store.read.with_tag(email_tag), ) case result in En57::Success(position:) # user registered at event position in En57::Failure(position:, conflicting_events:) # email already used; conflicting_events contains the matching event end ``` -------------------------------- ### Connect to Event Store with Raw PG Source: https://github.com/mostlyobvious/en57/blob/master/README.md Instantiate an EventStore instance using a direct PostgreSQL connection string. This is suitable when En57 should manage its own connection. ```ruby event_store = En57::EventStore.for_pg("postgres://localhost:5432/en57") ``` -------------------------------- ### Connect to Event Store with Sequel Source: https://github.com/mostlyobvious/en57/blob/master/README.md Instantiate an EventStore instance using an existing Sequel database connection. Use this when your application already manages a Sequel database. ```ruby database = Sequel.connect("postgres://localhost:5432/en57") event_store = En57::EventStore.for_sequel(database) ``` -------------------------------- ### Connect to Event Store with ActiveRecord Source: https://github.com/mostlyobvious/en57/blob/master/README.md Instantiate an EventStore instance when using ActiveRecord. Ensure ActiveRecord is already configured with a database connection. ```ruby ActiveRecord::Base.establish_connection("postgres://localhost:5432/en57") event_store = En57::EventStore.for_active_record ``` -------------------------------- ### EventStore.for_sequel Source: https://github.com/mostlyobvious/en57/blob/master/README.md Connects to the event store using an existing Sequel database connection. Assumes the database schema is already managed. ```APIDOC ## EventStore.for_sequel ### Description Connects the En57 event store to an existing Sequel database instance. This is useful when your application already manages a Sequel database connection. ### Method `EventStore.for_sequel(database_instance)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```ruby database = Sequel.connect("postgres://localhost:5432/en57") event_store = En57::EventStore.for_sequel(database) ``` ### Response #### Success Response An instance of `En57::EventStore` integrated with the provided Sequel database object. #### Response Example ```ruby # event_store object ``` ``` -------------------------------- ### EventStore.for_pg Source: https://github.com/mostlyobvious/en57/blob/master/README.md Connects to the event store using a raw PostgreSQL connection. En57 will manage its own schema. ```APIDOC ## EventStore.for_pg ### Description Establishes a connection to the En57 event store using a provided PostgreSQL connection URL. This method is suitable when En57 needs to manage its own database schema. ### Method `EventStore.for_pg(connection_url)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```ruby event_store = En57::EventStore.for_pg("postgres://localhost:5432/en57") ``` ### Response #### Success Response An instance of `En57::EventStore` connected to the specified PostgreSQL database. #### Response Example ```ruby # event_store object ``` ``` -------------------------------- ### Run Development Tasks Source: https://github.com/mostlyobvious/en57/blob/master/README.md Execute development tasks using `devenv tasks run`. Available tasks include running the full test suite, unit tests, mutation testing, and code formatting. ```sh devenv tasks run test ``` -------------------------------- ### Theme Toggling JavaScript Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.html Handles theme switching between light and dark modes, persisting the choice in local storage and updating the UI icon. ```javascript function getDefaultTheme() { const hour = new Date().getHours(); return (hour >= 7 && hour < 19) ? 'light' : 'dark'; } function setTheme(theme) { document.documentElement.setAttribute('data-theme', theme); localStorage.setItem('modularity-review-theme', theme); document.getElementById('theme-icon').textContent = theme === 'light' ? '☾' : '☀'; } function toggleTheme() { const current = document.documentElement.getAttribute('data-theme'); setTheme(current === 'light' ? 'dark' : 'light'); } const saved = localStorage.getItem('modularity-review-theme'); setTheme(saved || getDefaultTheme()); ``` -------------------------------- ### Ruby Repository Event Encoding Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.md Shows how the Repository builds an event record for the SQL function. The order and count of elements must match the SQL composite type definition. ```ruby @record_encoder.encode([event.id, event.type, serialized, description, tags]) ``` -------------------------------- ### EventStore.for_active_record Source: https://github.com/mostlyobvious/en57/blob/master/README.md Connects to the event store using an existing ActiveRecord connection. Assumes the database schema is already managed. ```APIDOC ## EventStore.for_active_record ### Description Integrates the En57 event store with an existing ActiveRecord connection. This method is suitable for applications already using ActiveRecord. ### Method `EventStore.for_active_record` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```ruby ActiveRecord::Base.establish_connection("postgres://localhost:5432/en57") event_store = En57::EventStore.for_active_record ``` ### Response #### Success Response An instance of `En57::EventStore` configured to use the current ActiveRecord connection. #### Response Example ```ruby # event_store object ``` ``` -------------------------------- ### Ruby Repository JSON Wrapping Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.md Shows how the Repository wraps the Criteria's JSON shape into a structure expected by the SQL functions. ```ruby {fail_if_events_match: [...]} ``` -------------------------------- ### Ruby Deserialization Fetching Result Columns Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.md Shows how the Ruby code fetches specific columns from the SQL function's result set. The names must match the SQL function's RETURNS clause. ```ruby deserialize_event ``` -------------------------------- ### SQL Function JSON Key Access Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.md Demonstrates how SQL functions access specific keys within the JSON payload provided by the Ruby side. The keys must match exactly. ```sql append_condition -> 'fail_if_events_match' ``` ```sql criterion -> 'types' ``` ```sql criterion -> 'tags' ``` ```sql criterion ->> 'after' ``` -------------------------------- ### event_store.read Source: https://github.com/mostlyobvious/en57/blob/master/README.md Reads events from the event store. Supports various filtering and ordering options. ```APIDOC ## event_store.read ### Description Initiates a read operation to retrieve events from the event store. Supports filtering by type, tags, position, and combining multiple read scopes. ### Method `event_store.read` ### Parameters None directly on `read`, but chaining methods provide filtering capabilities. ### Chained Methods for Filtering: - `.each`: - Iterates over all events matching the current scope. - `.each_with_position`: - Iterates over events along with their positions. - `.with_tag(*tags)`: - Filters events by one or more tags. - `.after(position)`: - Filters events that occurred after a specific position. - `.of_type(*types)`: - Filters events by their type. - `(scope1 | scope2)`: - Merges two read scopes, returning events that match either scope. ### Request Example ```ruby # Read all events events = event_store.read.each.to_a # Read events with positions first_event, first_position = event_store.read.each_with_position.first # Read events filtered by tags tagged_events = event_store.read.with_tag("order_id:123", "customer:42").each.to_a # Read events after a specific position recent_events = event_store.read.after(42).each.to_a # Read events filtered by type and tags order_placed_events = event_store.read.of_type("OrderPlaced").with_tag("order_id:123") ``` ### Response #### Success Response An enumerator yielding `En57::Event` objects (or `[En57::Event, position]` for `each_with_position`) that match the specified read criteria. #### Response Example ```ruby # Example of processing events events.each do |event| puts "Event Type: #{event.type}" end ``` ``` -------------------------------- ### Check Database Schema Status Source: https://github.com/mostlyobvious/en57/blob/master/README.md Inspect the current status of the En57 database schema without applying changes. Ensure DATABASE_URL is set. ```sh DATABASE_URL=postgres://localhost:5432/en57 bundle exec rake en57:status ``` -------------------------------- ### Read Events Filtered by Tags Source: https://github.com/mostlyobvious/en57/blob/master/README.md Retrieve events that match one or more specified tags. This allows for targeted event retrieval. ```ruby events = event_store.read.with_tag("order_id:123", "customer:42").each.to_a ``` -------------------------------- ### Read All Events Source: https://github.com/mostlyobvious/en57/blob/master/README.md Retrieve all events stored in the event store. The result is an enumerator that can be converted to an array. ```ruby events = event_store.read.each.to_a ``` -------------------------------- ### event_store.append Source: https://github.com/mostlyobvious/en57/blob/master/README.md Appends a list of events to the event store. Supports unconditional writes and conditional writes with optimistic concurrency. ```APIDOC ## event_store.append ### Description Appends one or more events to the event store. This method can be used for unconditional writes or conditional writes using the `fail_if` option for optimistic concurrency control. ### Method `event_store.append(events, fail_if: nil)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **events** (Array) - Required - An array of `En57::Event` objects to append. - **fail_if** (Object, optional) - A scope or condition that, if matched by existing events, will cause the append operation to fail. ### Request Example ```ruby event_store.append([ En57::Event.new( type: "OrderPlaced", data: { amount: 100 }, tags: ["order_id:123", "customer:42"], ), ]) # Conditional write example account_scope = event_store.read.with_tag("account:x") result = event_store.append([ En57::Event.new( type: "CreditsUsed", data: { amount: 100 }, tags: ["account:x"], ), ], fail_if: account_scope.of_type("CreditsUsed")) ``` ### Response #### Success Response - **Success(position)**: An object indicating a successful write, containing the position of the appended event. #### Failure Response - **Failure(position:, conflicting_events:)**: An object indicating a failed write due to a `fail_if` condition being met. `conflicting_events` contains the events that matched the condition. #### Response Example ```ruby case result when En57::Success(position:) puts "Event written at position: #{position}" when En57::Failure(position:, conflicting_events:) puts "Write failed. Conflicting events found at position: #{position}" end ``` ``` -------------------------------- ### Deserialize event data in Ruby Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.html Deserializes event data from the database, fetching specific columns by name. The column names must match the 'RETURNS' clauses of the PL/pgSQL functions. ```ruby position, conflicting_events, id, type, data, meta, tags ``` -------------------------------- ### Read Events with Positions Source: https://github.com/mostlyobvious/en57/blob/master/README.md Retrieve events along with their positions in the event stream. Useful for tracking progress or resuming reads. ```ruby event, position = event_store.read.each_with_position.first ``` -------------------------------- ### Require En57 Rake Tasks Source: https://github.com/mostlyobvious/en57/blob/master/README.md Add these rake tasks to your Rakefile to manage the En57 database schema. ```ruby require "en57/tasks" ``` -------------------------------- ### Append Events Unconditionally Source: https://github.com/mostlyobvious/en57/blob/master/README.md Append a new event or a list of events to the event store without any conditions. This is the simplest way to add events. ```ruby event_store.append( [ En57::Event.new( type: "OrderPlaced", data: { amount: 100 }, tags: ["order_id:123", "customer:42"], ), ], ) ``` -------------------------------- ### Read Events Filtered by Type and Tags Source: https://github.com/mostlyobvious/en57/blob/master/README.md Combine filters to read events of a specific type and matching certain tags. Merged scopes allow for complex queries. ```ruby orders = event_store.read.of_type("OrderPlaced").with_tag("order_id:123") price_changes = event_store.read.of_type("PriceChanged") events = (orders | price_changes).each.to_a ``` -------------------------------- ### Read Events After a Specific Position Source: https://github.com/mostlyobvious/en57/blob/master/README.md Retrieve events that occurred after a given position in the event stream. This is useful for incremental processing. ```ruby events = event_store.read.after(42).each.to_a ``` -------------------------------- ### SQL Composite Type Definition Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.md Defines the 'en57.event' composite type used by the SQL functions. The positional layout must match the Ruby encoder. ```sql CREATE TYPE en57.event AS ( id integer, type varchar(255), data jsonb, meta jsonb, tags text[] ); ``` -------------------------------- ### Ruby Criteria JSON Shape Generation Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.md Illustrates how the Criteria object generates a JSON shape for filtering events, which is then used by the Repository and SQL functions. ```ruby {types:, tags:, after:} ``` -------------------------------- ### Parse append condition in PL/pgSQL Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.html Parses the 'fail_if_events_match' key from the append condition JSON in PostgreSQL. This function is part of the logic that checks for conflicts before appending. ```sql append_condition -> 'fail_if_events_match' ``` -------------------------------- ### Parse 'after' timestamp from JSON in PL/pgSQL Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.html Extracts the 'after' timestamp from a JSON object in PostgreSQL. This is used for time-based filtering of events. ```sql ->> 'after' ``` -------------------------------- ### Conditional Write Ignoring Past Events Source: https://github.com/mostlyobvious/en57/blob/master/README.md Append an event conditionally, ignoring any matching events that occurred at or before a specified position. This is useful for resuming operations. ```ruby last_read_event_position = 42 event_store.append( [En57::Event.new(type: "CreditsUsed", tags: ["account:x"])], fail_if: event_store.read.of_type("CreditsUsed").after(last_read_event_position), ) ``` -------------------------------- ### Parse criterion JSON in PL/pgSQL Source: https://github.com/mostlyobvious/en57/blob/master/doc/modularity-review/2026-06-18/modularity-review.html Parses 'types' and 'tags' keys from a criterion JSON object within PostgreSQL functions. This is used to filter events based on specified criteria. ```sql criterion -> 'types' ``` ```sql criterion -> 'tags' ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.