@@ -11,10 +11,16 @@ defmodule Electric.Shapes.Shape do
1111 require Logger
1212
1313 defprotocol Comparable do
14+ @ fallback_to_any true
15+
1416 @ spec comparable ( t ( ) ) :: t ( )
1517 def comparable ( term )
1618 end
1719
20+ defimpl Comparable , for: Any do
21+ def comparable ( term ) , do: term
22+ end
23+
1824 @ default_replica :default
1925
2026 @ enforce_keys [ :root_table , :root_table_id ]
@@ -67,14 +73,21 @@ defmodule Electric.Shapes.Shape do
6773 storage: % { required ( String . t ( ) ) => String . t ( ) }
6874 }
6975
76+ @ doc """
77+ Return a comparable representation of the shape.
78+
79+ This is used to compare shapes for equality as an ETS key - and thus it'll be matched in some cases,
80+ not just compared equal. This representation must therefore not contain any maps (as they are matched when one
81+ is missing a key for example).
82+
83+ This representation must contain all the information that identifies user-specified properties of the shape. We're
84+ omitting storage configuration and other internal state.
85+ """
7086 def comparable ( % __MODULE__ { } = shape ) do
71- shape
72- |> Map . drop ( [ :table_info , :storage ] )
73- |> Map . update! ( :where , fn
74- nil -> nil
75- % Expr { } = expr -> Electric.Shapes.Shape.Comparable . comparable ( expr )
76- statement when is_binary ( statement ) -> statement
77- end )
87+ { :shape , { shape . root_table_id , shape . root_table } , shape . root_pk ,
88+ Comparable . comparable ( shape . where ) , shape . selected_columns ,
89+ Enum . flat_map ( shape . flags , fn { k , v } -> if ( v , do: [ k ] , else: [ ] ) end ) |> Enum . sort ( ) ,
90+ shape . replica }
7891 end
7992
8093 def hash ( % __MODULE__ { } = shape ) ,
0 commit comments