1 /* 2 * Make.org Core API 3 * Copyright (C) 2018 Make.org 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Affero General Public License as 7 * published by the Free Software Foundation, either version 3 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Affero General Public License for more details. 14 * 15 * You should have received a copy of the GNU Affero General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package org.make.core 21 22 import java.time.{LocalDate, ZonedDateTime} 23 import com.sksamuel.avro4s._ 24 import enumeratum.values.{StringEnum, StringEnumEntry} 25 import org.apache.avro.{Schema, SchemaBuilder} 26 import org.make.api.technical.crm.SendMessages 27 import org.make.core.history.HistoryActions.VoteTrust 28 import org.make.core.history.HistoryActions.VoteTrust.Trusted 29 import org.make.core.proposal.{ProposalStatus, ProposalType} 30 import org.make.core.reference.{Country, Language} 31 import org.make.core.technical.Multilingual 32 33 trait AvroSerializers { 34 35 implicit object LocalDateSchemaFor extends SchemaFor[LocalDate] { 36 override def schema(fieldMapper: FieldMapper): Schema = Schema.create(Schema.Type.STRING) 37 } 38 39 implicit object DateTimeEncoder extends Encoder[LocalDate] { 40 override def encode(value: LocalDate, schema: Schema, fieldMapper: FieldMapper): String = value.toString 41 } 42 43 implicit object DateTimeDecoder extends Decoder[LocalDate] { 44 override def decode(value: Any, schema: Schema, fieldMapper: FieldMapper): LocalDate = 45 LocalDate.parse(value.toString) 46 } 47 48 implicit object ZonedDateTimeSchemaFor extends SchemaFor[ZonedDateTime] { 49 override def schema(fieldMapper: FieldMapper): Schema = Schema.create(Schema.Type.STRING) 50 } 51 52 implicit object ZonedDateTimeEncoder extends Encoder[ZonedDateTime] { 53 override def encode(value: ZonedDateTime, schema: Schema, fieldMapper: FieldMapper): String = 54 DateHelper.format(value) 55 } 56 57 implicit object ZonedDateTimeDecoder extends Decoder[ZonedDateTime] { 58 override def decode(value: Any, schema: Schema, fieldMapper: FieldMapper): ZonedDateTime = 59 ZonedDateTime.parse(value.toString) 60 } 61 62 implicit object CountrySchemaFor extends SchemaFor[Country] { 63 override def schema(fieldMapper: FieldMapper): Schema = Schema.create(Schema.Type.STRING) 64 } 65 66 implicit object CountryEncoder extends Encoder[Country] { 67 override def encode(value: Country, schema: Schema, fieldMapper: FieldMapper): String = value.value 68 } 69 70 implicit object CountryDecoder extends Decoder[Country] { 71 override def decode(value: Any, schema: Schema, fieldMapper: FieldMapper): Country = Country(value.toString) 72 } 73 74 implicit object LanguageSchemaFor extends SchemaFor[Language] { 75 override def schema(fieldMapper: FieldMapper): Schema = Schema.create(Schema.Type.STRING) 76 } 77 78 implicit object LanguageEncoder extends Encoder[Language] { 79 override def encode(value: Language, schema: Schema, fieldMapper: FieldMapper): String = value.value 80 } 81 82 implicit object LanguageDecoder extends Decoder[Language] { 83 override def decode(value: Any, schema: Schema, fieldMapper: FieldMapper): Language = Language(value.toString) 84 } 85 86 implicit def multilingualSchema[T <: String](implicit schemaFor: SchemaFor[T]): SchemaFor[Multilingual[T]] = 87 fieldMapper => SchemaBuilder.map().values(schemaFor.schema(fieldMapper)) 88 89 implicit def multilingualEncoder[T <: String](implicit encoder: Encoder[Map[String, T]]): Encoder[Multilingual[T]] = 90 (value, schema, fieldMapper) => { 91 encoder.encode(value.toMap.map { 92 case (k, v) => (k.value, v) 93 }, schema, fieldMapper) 94 } 95 96 @SuppressWarnings(Array("org.wartremover.warts.AsInstanceOf")) 97 implicit def multilingualDecoder[T <: String]( 98 implicit valueDecoder: Decoder[Map[String, T]] 99 ): Decoder[Multilingual[T]] = 100 (value, schema, fieldMapper) => { 101 val map = valueDecoder.decode(value, schema, fieldMapper) 102 Multilingual.fromMap(map) 103 } 104 105 // do not use automatic StringEnum typeclasses, to keep legacy complex schema 106 implicit val proposalStatusSchemaFor: SchemaFor[ProposalStatus] = SchemaFor.gen[ProposalStatus] 107 implicit val proposalStatusDecoder: Decoder[ProposalStatus] = Decoder.gen 108 implicit val proposalStatusEncoder: Encoder[ProposalStatus] = Encoder.gen 109 110 // do not use automatic StringEnum typeclasses, to keep legacy complex schema 111 implicit val proposalTypeSchemaFor: SchemaFor[ProposalType] = SchemaFor.gen[ProposalType] 112 implicit val proposalTypeDecoder: Decoder[ProposalType] = Decoder.gen 113 implicit val proposalTypeEncoder: Encoder[ProposalType] = Encoder.gen 114 115 implicit val voteTrustDecoder: Decoder[VoteTrust] = (value: Any, schema: Schema, fieldMapper: FieldMapper) => { 116 // Add a fallback to trusted since some events in kafka are corrupted 117 Option(value).map(stringEnumDecoder[VoteTrust].decode(_, schema, fieldMapper)).getOrElse(Trusted) 118 } 119 120 implicit def stringEnumSchemaFor[A <: StringEnumEntry]: SchemaFor[A] = _ => Schema.create(Schema.Type.STRING) 121 122 implicit def stringEnumEncoder[A <: StringEnumEntry]: Encoder[A] = (a, _, _) => a.value 123 124 @SuppressWarnings(Array("org.wartremover.warts.Throw")) 125 implicit def stringEnumDecoder[A <: StringEnumEntry](implicit stringEnum: StringEnum[A]): Decoder[A] = 126 (value, _, _) => 127 stringEnum 128 .withValueOpt(value.toString) 129 .getOrElse(throw new IllegalArgumentException(s"$value is not a ${stringEnum.toString}")) 130 131 implicit val requestContextSchemaFor: SchemaFor[RequestContext] = SchemaFor.gen[RequestContext] 132 implicit val requestContextAvroDecoder: Decoder[RequestContext] = Decoder.gen[RequestContext] 133 implicit val requestContextAvroEncoder: Encoder[RequestContext] = Encoder.gen[RequestContext] 134 135 implicit val sendMessagesSchemaFor: SchemaFor[SendMessages] = SchemaFor.gen[SendMessages] 136 implicit val sendMessagesAvroDecoder: Decoder[SendMessages] = Decoder.gen[SendMessages] 137 implicit val sendMessagesAvroEncoder: Encoder[SendMessages] = Encoder.gen[SendMessages] 138 139 } 140 141 object AvroSerializers extends AvroSerializers
| Line | Stmt Id | Pos | Tree | Symbol | Tests | Code |
|---|---|---|---|---|---|---|
| 36 | 6906 | 1416 - 1449 | Apply | org.apache.avro.Schema.create | org.apache.avro.Schema.create(STRING) | |
| 40 | 6177 | 1612 - 1626 | Apply | java.time.LocalDate.toString | value.toString() | |
| 45 | 7577 | 1808 - 1822 | Apply | scala.Any.toString | value.toString() | |
| 45 | 7124 | 1792 - 1823 | Apply | java.time.LocalDate.parse | java.time.LocalDate.parse(value.toString()) | |
| 49 | 6314 | 1965 - 1998 | Apply | org.apache.avro.Schema.create | org.make.api.avro.avrocompatibilitytest,org.make.api.makekafkatest | org.apache.avro.Schema.create(STRING) |
| 54 | 7657 | 2180 - 2204 | Apply | org.make.core.DefaultDateHelper.format | org.make.api.kafkaconsumertest | DateHelper.format(value) |
| 59 | 6884 | 2403 - 2417 | Apply | scala.Any.toString | value.toString() | |
| 59 | 6042 | 2383 - 2418 | Apply | java.time.ZonedDateTime.parse | java.time.ZonedDateTime.parse(value.toString()) | |
| 63 | 7811 | 2548 - 2581 | Apply | org.apache.avro.Schema.create | org.make.api.avro.avrocompatibilitytest,org.make.api.makekafkatest | org.apache.avro.Schema.create(STRING) |
| 67 | 6912 | 2739 - 2750 | Select | org.make.core.reference.Country.value | org.make.api.kafkaconsumertest | value.value |
| 71 | 7579 | 2905 - 2928 | Apply | org.make.core.reference.Country.apply | org.make.core.reference.Country.apply(value.toString()) | |
| 71 | 6137 | 2913 - 2927 | Apply | scala.Any.toString | value.toString() | |
| 75 | 7077 | 3060 - 3093 | Apply | org.apache.avro.Schema.create | org.make.api.avro.avrocompatibilitytest,org.make.api.makekafkatest | org.apache.avro.Schema.create(STRING) |
| 79 | 6276 | 3254 - 3265 | Select | org.make.core.reference.Language.value | value.value | |
| 83 | 7660 | 3432 - 3446 | Apply | scala.Any.toString | value.toString() | |
| 83 | 6852 | 3423 - 3447 | Apply | org.make.core.reference.Language.apply | org.make.core.reference.Language.apply(value.toString()) | |
| 87 | 7816 | 3583 - 3640 | Apply | org.apache.avro.SchemaBuilder.MapBuilder.values | org.make.api.avro.avrocompatibilitytest,org.make.api.makekafkatest | org.apache.avro.SchemaBuilder.map().values(schemaFor.schema(fieldMapper)) |
| 87 | 6000 | 3610 - 3639 | Apply | com.sksamuel.avro4s.SchemaFor.schema | org.make.api.avro.avrocompatibilitytest,org.make.api.makekafkatest | schemaFor.schema(fieldMapper) |
| 91 | 7559 | 3820 - 3881 | Apply | scala.collection.MapOps.map | value.toMap.map[String, T](((x0$1: (org.make.core.reference.Language, T)) => x0$1 match { case (_1: org.make.core.reference.Language, _2: T): (org.make.core.reference.Language, T)((k @ _), (v @ _)) => scala.Tuple2.apply[String, T](k.value, v) })) | |
| 91 | 6693 | 3805 - 3903 | Apply | com.sksamuel.avro4s.Encoder.encode | encoder.encode(value.toMap.map[String, T](((x0$1: (org.make.core.reference.Language, T)) => x0$1 match { case (_1: org.make.core.reference.Language, _2: T): (org.make.core.reference.Language, T)((k @ _), (v @ _)) => scala.Tuple2.apply[String, T](k.value, v) })), schema, fieldMapper) | |
| 92 | 7038 | 3862 - 3869 | Select | org.make.core.reference.Language.value | k.value | |
| 92 | 6141 | 3861 - 3873 | Apply | scala.Tuple2.apply | scala.Tuple2.apply[String, T](k.value, v) | |
| 101 | 6282 | 4162 - 4209 | Apply | com.sksamuel.avro4s.Decoder.decode | valueDecoder.decode(value, schema, fieldMapper) | |
| 102 | 7728 | 4216 - 4241 | Apply | org.make.core.technical.Multilingual.fromMap | org.make.core.technical.Multilingual.fromMap[T](map) | |
| 117 | 7779 | 5089 - 5186 | Apply | scala.Option.getOrElse | scala.Option.apply[Any](value).map[org.make.core.history.HistoryActions.VoteTrust](((x$1: Any) => AvroSerializers.this.stringEnumDecoder[org.make.core.history.HistoryActions.VoteTrust]((VoteTrust: enumeratum.values.StringEnum[org.make.core.history.HistoryActions.VoteTrust])).decode(x$1, schema, fieldMapper))).getOrElse[org.make.core.history.HistoryActions.VoteTrust](org.make.core.history.HistoryActions.VoteTrust.Trusted) | |
| 117 | 6855 | 5107 - 5166 | Apply | com.sksamuel.avro4s.Decoder.decode | AvroSerializers.this.stringEnumDecoder[org.make.core.history.HistoryActions.VoteTrust]((VoteTrust: enumeratum.values.StringEnum[org.make.core.history.HistoryActions.VoteTrust])).decode(x$1, schema, fieldMapper) | |
| 117 | 5963 | 5178 - 5185 | Select | org.make.core.history.HistoryActions.VoteTrust.Trusted | org.make.core.history.HistoryActions.VoteTrust.Trusted | |
| 120 | 6905 | 5270 - 5303 | Apply | org.apache.avro.Schema.create | org.make.api.avro.avrocompatibilitytest,org.make.api.makekafkatest | org.apache.avro.Schema.create(STRING) |
| 122 | 6203 | 5387 - 5394 | Select | enumeratum.values.ValueEnumEntry.value | a.value | |
| 128 | 7489 | 5619 - 5633 | Apply | scala.Any.toString | value.toString() | |
| 129 | 6311 | 5586 - 5732 | Apply | scala.Option.getOrElse | stringEnum.withValueOpt(value.toString()).getOrElse[A](throw new scala.`package`.IllegalArgumentException(("".+(value).+(" is not a ").+(stringEnum.toString()): String))) | |
| 129 | 6696 | 5654 - 5731 | Throw | <nosymbol> | throw new scala.`package`.IllegalArgumentException(("".+(value).+(" is not a ").+(stringEnum.toString()): String)) |