77
88using Akka . Actor ;
99using Akka . Persistence . Sql . Common . Journal ;
10+ using Akka . Serialization ;
1011using Akka . Util ;
1112using Newtonsoft . Json ;
1213using Npgsql ;
1314using NpgsqlTypes ;
1415using System ;
15- using System . Collections . Generic ;
1616using System . Collections . Immutable ;
1717using System . Data ;
1818using System . Data . Common ;
@@ -24,8 +24,8 @@ namespace Akka.Persistence.PostgreSql.Journal
2424 public class PostgreSqlQueryExecutor : AbstractQueryExecutor
2525 {
2626 private readonly PostgreSqlQueryConfiguration _configuration ;
27- private readonly Func < IPersistentRepresentation , KeyValuePair < NpgsqlDbType , object > > _serialize ;
28- private readonly Func < Type , object , object > _deserialize ;
27+ private readonly Func < IPersistentRepresentation , SerializationResult > _serialize ;
28+ private readonly Func < Type , object , string , int ? , object > _deserialize ;
2929
3030 public PostgreSqlQueryExecutor ( PostgreSqlQueryConfiguration configuration , Akka . Serialization . Serialization serialization , ITimestampProvider timestampProvider )
3131 : base ( configuration , serialization , timestampProvider )
@@ -43,6 +43,7 @@ public PostgreSqlQueryExecutor(PostgreSqlQueryConfiguration configuration, Akka.
4343 { Configuration . ManifestColumnName } VARCHAR(500) NOT NULL,
4444 { Configuration . PayloadColumnName } { storedAs } NOT NULL,
4545 { Configuration . TagsColumnName } VARCHAR(100) NULL,
46+ { Configuration . SerializerIdColumnName } INTEGER NULL,
4647 CONSTRAINT { Configuration . JournalEventsTableName } _uq UNIQUE ({ Configuration . PersistenceIdColumnName } , { Configuration . SequenceNrColumnName } )
4748 );
4849 " ;
@@ -57,16 +58,32 @@ public PostgreSqlQueryExecutor(PostgreSqlQueryConfiguration configuration, Akka.
5758 switch ( _configuration . StoredAs )
5859 {
5960 case StoredAsType . ByteA :
60- _serialize = e => new KeyValuePair < NpgsqlDbType , object > ( NpgsqlDbType . Bytea , Serialization . FindSerializerFor ( e . Payload ) . ToBinary ( e . Payload ) ) ;
61- _deserialize = ( type , serialized ) => Serialization . FindSerializerForType ( type ) . FromBinary ( ( byte [ ] ) serialized , type ) ;
61+ _serialize = e =>
62+ {
63+ var serializer = Serialization . FindSerializerFor ( e . Payload ) ;
64+ return new SerializationResult ( NpgsqlDbType . Bytea , serializer . ToBinary ( e . Payload ) , serializer ) ;
65+ } ;
66+ _deserialize = ( type , serialized , manifest , serializerId ) =>
67+ {
68+ if ( serializerId . HasValue )
69+ {
70+ return Serialization . Deserialize ( ( byte [ ] ) serialized , serializerId . Value , manifest ) ;
71+ }
72+ else
73+ {
74+ // Support old writes that did not set the serializer id
75+ var deserializer = Serialization . FindSerializerForType ( type , Configuration . DefaultSerializer ) ;
76+ return deserializer . FromBinary ( ( byte [ ] ) serialized , type ) ;
77+ }
78+ } ;
6279 break ;
6380 case StoredAsType . JsonB :
64- _serialize = e => new KeyValuePair < NpgsqlDbType , object > ( NpgsqlDbType . Jsonb , JsonConvert . SerializeObject ( e . Payload , _configuration . JsonSerializerSettings ) ) ;
65- _deserialize = ( type , serialized ) => JsonConvert . DeserializeObject ( ( string ) serialized , type , _configuration . JsonSerializerSettings ) ;
81+ _serialize = e => new SerializationResult ( NpgsqlDbType . Jsonb , JsonConvert . SerializeObject ( e . Payload , _configuration . JsonSerializerSettings ) , null ) ;
82+ _deserialize = ( type , serialized , manifest , serializerId ) => JsonConvert . DeserializeObject ( ( string ) serialized , type , _configuration . JsonSerializerSettings ) ;
6683 break ;
6784 case StoredAsType . Json :
68- _serialize = e => new KeyValuePair < NpgsqlDbType , object > ( NpgsqlDbType . Json , JsonConvert . SerializeObject ( e . Payload , _configuration . JsonSerializerSettings ) ) ;
69- _deserialize = ( type , serialized ) => JsonConvert . DeserializeObject ( ( string ) serialized , type , _configuration . JsonSerializerSettings ) ;
85+ _serialize = e => new SerializationResult ( NpgsqlDbType . Json , JsonConvert . SerializeObject ( e . Payload , _configuration . JsonSerializerSettings ) , null ) ;
86+ _deserialize = ( type , serialized , manifest , serializerId ) => JsonConvert . DeserializeObject ( ( string ) serialized , type , _configuration . JsonSerializerSettings ) ;
7087 break ;
7188 default :
7289 throw new NotSupportedException ( $ "{ _configuration . StoredAs } is not supported Db type for a payload") ;
@@ -79,15 +96,34 @@ public PostgreSqlQueryExecutor(PostgreSqlQueryConfiguration configuration, Akka.
7996
8097 protected override void WriteEvent ( DbCommand command , IPersistentRepresentation e , IImmutableSet < string > tags )
8198 {
82- var manifest = string . IsNullOrEmpty ( e . Manifest ) ? QualifiedName ( e ) : e . Manifest ;
83- var t = _serialize ( e ) ;
99+ var serializationResult = _serialize ( e ) ;
100+ var serializer = serializationResult . Serializer ;
101+ var hasSerializer = serializer != null ;
102+
103+ string manifest = "" ;
104+ if ( hasSerializer && serializer is SerializerWithStringManifest )
105+ manifest = ( ( SerializerWithStringManifest ) serializer ) . Manifest ( e . Payload ) ;
106+ else if ( hasSerializer && serializer . IncludeManifest )
107+ manifest = QualifiedName ( e ) ;
108+ else
109+ manifest = string . IsNullOrEmpty ( e . Manifest ) ? QualifiedName ( e ) : e . Manifest ;
84110
85111 AddParameter ( command , "@PersistenceId" , DbType . String , e . PersistenceId ) ;
86112 AddParameter ( command , "@SequenceNr" , DbType . Int64 , e . SequenceNr ) ;
87113 AddParameter ( command , "@Timestamp" , DbType . Int64 , TimestampProvider . GenerateTimestamp ( e ) ) ;
88114 AddParameter ( command , "@IsDeleted" , DbType . Boolean , false ) ;
89115 AddParameter ( command , "@Manifest" , DbType . String , manifest ) ;
90- command . Parameters . Add ( new NpgsqlParameter ( "@Payload" , t . Key ) { Value = t . Value } ) ;
116+
117+ if ( hasSerializer )
118+ {
119+ AddParameter ( command , "@SerializerId" , DbType . Int32 , serializer . Identifier ) ;
120+ }
121+ else
122+ {
123+ AddParameter ( command , "@SerializerId" , DbType . Int32 , DBNull . Value ) ;
124+ }
125+
126+ command . Parameters . Add ( new NpgsqlParameter ( "@Payload" , serializationResult . DbType ) { Value = serializationResult . Payload } ) ;
91127
92128 if ( tags . Count != 0 )
93129 {
@@ -116,9 +152,19 @@ protected override IPersistentRepresentation ReadEvent(DbDataReader reader)
116152 var isDeleted = reader . GetBoolean ( IsDeletedIndex ) ;
117153 var manifest = reader . GetString ( ManifestIndex ) ;
118154 var raw = reader [ PayloadIndex ] ;
119- var type = Type . GetType ( manifest , true ) ;
120155
121- var deserialized = _deserialize ( type , raw ) ;
156+ int ? serializerId = null ;
157+ Type type = null ;
158+ if ( reader . IsDBNull ( SerializerIdIndex ) )
159+ {
160+ type = Type . GetType ( manifest , true ) ;
161+ }
162+ else
163+ {
164+ serializerId = reader . GetInt32 ( SerializerIdIndex ) ;
165+ }
166+
167+ var deserialized = _deserialize ( type , raw , manifest , serializerId ) ;
122168
123169 return new Persistent ( deserialized , sequenceNr , persistenceId , manifest , isDeleted , ActorRefs . NoSender , null ) ;
124170 }
@@ -141,12 +187,13 @@ public PostgreSqlQueryConfiguration(
141187 string isDeletedColumnName ,
142188 string tagsColumnName ,
143189 string orderingColumn ,
190+ string serializerIdColumnName ,
144191 TimeSpan timeout ,
145192 StoredAsType storedAs ,
146193 string defaultSerializer ,
147194 JsonSerializerSettings jsonSerializerSettings = null )
148195 : base ( schemaName , journalEventsTableName , metaTableName , persistenceIdColumnName , sequenceNrColumnName ,
149- payloadColumnName , manifestColumnName , timestampColumnName , isDeletedColumnName , tagsColumnName , orderingColumn , timeout , defaultSerializer )
196+ payloadColumnName , manifestColumnName , timestampColumnName , isDeletedColumnName , tagsColumnName , orderingColumn , serializerIdColumnName , timeout , defaultSerializer )
150197 {
151198 StoredAs = storedAs ;
152199 JsonSerializerSettings = jsonSerializerSettings ?? new JsonSerializerSettings
0 commit comments