diff --git a/README.md b/README.md index d32c00d..d9018b4 100644 --- a/README.md +++ b/README.md @@ -123,8 +123,8 @@ result = event_store.append( case result in En57::Success(position:) # credits consumed at event position -in En57::Failure - # lost the race; another writer already consumed credits +in En57::Failure(position:) + # lost the race; another writer already consumed credits at position end ``` @@ -161,7 +161,7 @@ result = event_store.append( case result in En57::Success(position:) # user registered at event position -in En57::Failure - # email already used +in En57::Failure(position:) + # email already used at event position end ``` diff --git a/db/schema/0.1.0.sql b/db/schema/0.1.0.sql index 67c05f1..4976580 100644 --- a/db/schema/0.1.0.sql +++ b/db/schema/0.1.0.sql @@ -45,6 +45,7 @@ DECLARE req_tags text[]; req_after bigint; appended_position bigint; + matched_position bigint; BEGIN FOREACH criterion IN ARRAY criteria LOOP req_after := (criterion ->> 'after')::bigint; @@ -54,43 +55,43 @@ BEGIN req_tags := ARRAY ( SELECT DISTINCT jsonb_array_elements_text(COALESCE(criterion -> 'tags', '[]'::jsonb))); IF cardinality(req_tags) > 0 THEN - IF EXISTS ( + SELECT + max(e.position) + FROM ( SELECT - 1 - FROM ( - SELECT - t.event_id - FROM - en57.tags AS t - WHERE - t.value = ANY (req_tags) - GROUP BY - t.event_id - HAVING - count(*) = cardinality(req_tags)) AS matched - JOIN en57.events AS e ON e.id = matched.event_id - WHERE (req_after IS NULL - OR e.position > req_after) + t.event_id + FROM + en57.tags AS t + WHERE + t.value = ANY (req_tags) + GROUP BY + t.event_id + HAVING + count(*) = cardinality(req_tags)) AS matched + JOIN en57.events AS e ON e.id = matched.event_id + WHERE (req_after IS NULL + OR e.position > req_after) AND (criterion -> 'types' IS NULL - OR e.type = ANY (req_types))) THEN - RETURN ROW ('append_condition_violated', - NULL)::en57.append_result; - END IF; - ELSE - IF EXISTS ( + OR e.type = ANY (req_types)) + INTO + matched_position; + ELSE SELECT - 1 + max(e.position) FROM en57.events AS e WHERE (req_after IS NULL OR e.position > req_after) - AND (criterion -> 'types' IS NULL - OR e.type = ANY (req_types))) THEN - RETURN ROW ('append_condition_violated', - NULL)::en57.append_result; - END IF; -END IF; -END LOOP; + AND (criterion -> 'types' IS NULL + OR e.type = ANY (req_types)) + INTO + matched_position; + END IF; + IF matched_position IS NOT NULL THEN + RETURN ROW ('append_condition_violated', + matched_position)::en57.append_result; + END IF; + END LOOP; WITH inserted_events AS ( INSERT INTO en57.events (id, type, data, meta) SELECT diff --git a/lib/en57.rb b/lib/en57.rb index 171dcc0..6f8a7bb 100644 --- a/lib/en57.rb +++ b/lib/en57.rb @@ -15,7 +15,7 @@ require_relative "en57/configuration" module En57 Success = Data.define(:position) - Failure = Data.define + Failure = Data.define(:position) AppendRetriesExhausted = Class.new(StandardError) def self.configuration = Configuration.instance diff --git a/lib/en57/repository.rb b/lib/en57/repository.rb index 2297259..323da9a 100644 --- a/lib/en57/repository.rb +++ b/lib/en57/repository.rb @@ -58,7 +58,7 @@ module En57 when "success" Success.new(position: row.first.fetch("position").then { Integer(it) }) when "append_condition_violated" - Failure.new + Failure.new(position: row.first.fetch("position").then { Integer(it) }) end rescue @adapter.serialization_error if attempts_remaining.positive? diff --git a/test/pg_regress/expected/001_schema.out b/test/pg_regress/expected/001_schema.out index 67c05f1..4976580 100644 --- a/test/pg_regress/expected/001_schema.out +++ b/test/pg_regress/expected/001_schema.out @@ -45,6 +45,7 @@ DECLARE req_tags text[]; req_after bigint; appended_position bigint; + matched_position bigint; BEGIN FOREACH criterion IN ARRAY criteria LOOP req_after := (criterion ->> 'after')::bigint; @@ -54,43 +55,43 @@ BEGIN req_tags := ARRAY ( SELECT DISTINCT jsonb_array_elements_text(COALESCE(criterion -> 'tags', '[]'::jsonb))); IF cardinality(req_tags) > 0 THEN - IF EXISTS ( + SELECT + max(e.position) + FROM ( SELECT - 1 - FROM ( - SELECT - t.event_id - FROM - en57.tags AS t - WHERE - t.value = ANY (req_tags) - GROUP BY - t.event_id - HAVING - count(*) = cardinality(req_tags)) AS matched - JOIN en57.events AS e ON e.id = matched.event_id - WHERE (req_after IS NULL - OR e.position > req_after) + t.event_id + FROM + en57.tags AS t + WHERE + t.value = ANY (req_tags) + GROUP BY + t.event_id + HAVING + count(*) = cardinality(req_tags)) AS matched + JOIN en57.events AS e ON e.id = matched.event_id + WHERE (req_after IS NULL + OR e.position > req_after) AND (criterion -> 'types' IS NULL - OR e.type = ANY (req_types))) THEN - RETURN ROW ('append_condition_violated', - NULL)::en57.append_result; - END IF; - ELSE - IF EXISTS ( + OR e.type = ANY (req_types)) + INTO + matched_position; + ELSE SELECT - 1 + max(e.position) FROM en57.events AS e WHERE (req_after IS NULL OR e.position > req_after) - AND (criterion -> 'types' IS NULL - OR e.type = ANY (req_types))) THEN - RETURN ROW ('append_condition_violated', - NULL)::en57.append_result; - END IF; -END IF; -END LOOP; + AND (criterion -> 'types' IS NULL + OR e.type = ANY (req_types)) + INTO + matched_position; + END IF; + IF matched_position IS NOT NULL THEN + RETURN ROW ('append_condition_violated', + matched_position)::en57.append_result; + END IF; + END LOOP; WITH inserted_events AS ( INSERT INTO en57.events (id, type, data, meta) SELECT diff --git a/test/test_integration.rb b/test/test_integration.rb index 1f3a788..a33cdec 100644 --- a/test/test_integration.rb +++ b/test/test_integration.rb @@ -68,7 +68,7 @@ module En57 ) assert_equal( - Failure.new, + Failure.new(position: 1), event_store.append( [Event.new(id: ids[1], type: "ShipmentScheduled")], fail_if: event_store.read.of_type("OrderPlaced"), @@ -110,7 +110,7 @@ module En57 ) assert_equal( - Failure.new, + Failure.new(position: 1), event_store.append( [Event.new(id: ids[1], type: "ShipmentScheduled")], fail_if: event_store.read.of_type("OrderPlaced").after(0), diff --git a/test/test_repository.rb b/test/test_repository.rb index 123dd1e..17cb8df 100644 --- a/test/test_repository.rb +++ b/test/test_repository.rb @@ -543,7 +543,7 @@ module En57 connection.expect(:exec, nil, ["COMMIT"]) assert_equal( - Failure.new, + Failure.new(position: 3), Repository.new( PgAdapter.for_connection(connection), JsonSerializer.new, @@ -644,7 +644,8 @@ module En57 def success_result = [{ "status" => "success", "position" => "1" }] - def failure_result = [{ "status" => "append_condition_violated" }] + def failure_result = + [{ "status" => "append_condition_violated", "position" => "3" }] def append_events = [Event.new(id: ids[0], type: "OrderPaid")]