forked from arrow-kt/arrow
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* First working POC * Allow for extracting reasonable typed values from Json * Bump version of Kotlin, Arrow and metadata. Arrow-optics bumped to SNAPSHOT Removed optics typeclasses. * Add some docs and cleanup * Complete genJson Complete tests
- Loading branch information
Showing
15 changed files
with
555 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
dependencies { | ||
compile project(":helios-core") | ||
compile project(":helios-meta") | ||
compile project(":helios-parser") | ||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlinVersion" | ||
compile "io.arrow-kt:arrow-optics:0.6.2-SNAPSHOT" | ||
compile "io.arrow-kt:arrow-typeclasses:$arrowVersion" | ||
compileOnly project(':helios-meta-compiler') | ||
|
||
kapt "io.arrow-kt:arrow-annotations-processor:$arrowVersion" | ||
kapt project(':helios-meta-compiler') | ||
|
||
testCompile "io.arrow-kt:arrow-test:$arrowVersion" | ||
kaptTest project(':helios-meta-compiler') | ||
kaptTest "io.arrow-kt:arrow-annotations-processor:$arrowVersion" | ||
testCompileOnly "io.arrow-kt:arrow-annotations-processor:$arrowVersion" | ||
|
||
testCompileOnly project(':helios-meta-compiler') | ||
testCompile "io.kotlintest:kotlintest:$kotlinTestVersion" | ||
} | ||
|
||
apply from: rootProject.file('gradle/gradle-mvn-push.gradle') | ||
apply from: rootProject.file('gradle/generated-kotlin-sources.gradle') | ||
apply plugin: 'kotlin-kapt' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Maven publishing configuration | ||
POM_NAME=Helios Optics | ||
POM_ARTIFACT_ID=helios-optics | ||
POM_PACKAGING=jar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package helios.optics | ||
|
||
import arrow.core.Option | ||
import arrow.optics.* | ||
import arrow.optics.typeclasses.At | ||
import arrow.optics.typeclasses.Index | ||
import arrow.optics.typeclasses.at | ||
import arrow.optics.typeclasses.index | ||
import helios.core.* | ||
import helios.typeclasses.Decoder | ||
import helios.typeclasses.Encoder | ||
import helios.typeclasses.decoder | ||
import helios.typeclasses.encoder | ||
|
||
/** | ||
* [JsonPath] is a Json DSL based on Arrow-Optics (http://arrow-kt.io/docs/optics/iso/). | ||
* | ||
* With [JsonPath] you can represent paths/relations within your [Json] and allows for working with [Json] in an elegant way. | ||
*/ | ||
data class JsonPath(val json: Optional<Json, Json>) { | ||
|
||
companion object { | ||
/** | ||
* [JsonPath] [root] which is the start of any path. | ||
*/ | ||
val root = JsonPath(Optional.id()) | ||
|
||
/** | ||
* Overload constructor to point to [root]. | ||
*/ | ||
operator fun invoke() = root | ||
} | ||
|
||
/** | ||
* Extract value as [Boolean] from path. | ||
*/ | ||
val boolean: Optional<Json, Boolean> = json compose jsonJsBoolean() compose jsBooleanIso() | ||
|
||
/** | ||
* Extract value as [String] from path. | ||
*/ | ||
val string: Optional<Json, CharSequence> = json compose jsonJsString() compose jsStringIso() | ||
|
||
/** | ||
* Extract value as [JsNumber] from path. | ||
*/ | ||
val number: Optional<Json, JsNumber> = json compose jsonJsNumber() | ||
|
||
/** | ||
* Extract value as [JsDecimal] from path. | ||
*/ | ||
val decimal: Optional<Json, String> = number compose jsNumberJsDecimal() compose jsDecimalIso() | ||
|
||
/** | ||
* Extract value as [Long] from path. | ||
*/ | ||
val long: Optional<Json, Long> = number compose jsNumberJsLong() compose jsLongIso() | ||
|
||
/** | ||
* Extract value as [Float] from path. | ||
*/ | ||
val float: Optional<Json, Float> = number compose jsNumberJsFloat() compose jsFloatIso() | ||
|
||
/** | ||
* Extract value as [Int] from path. | ||
*/ | ||
val int: Optional<Json, Int> = number compose jsNumberJsInt() compose jsIntIso() | ||
|
||
/** | ||
* Extract [JsArray] as `List<Json>` from path. | ||
*/ | ||
val array: Optional<Json, List<Json>> = json compose jsonJsArray() compose jsArrayIso() | ||
|
||
/** | ||
* Extract [JsObject] as `Map<String, Json>` from path. | ||
*/ | ||
val `object`: Optional<Json, Map<String, Json>> = json compose jsonJsObject() compose jsObjectIso() | ||
|
||
/** | ||
* Extract [JsNull] from path. | ||
*/ | ||
val `null`: Optional<Json, JsNull> = json compose jsonJsNull() | ||
|
||
/** | ||
* Select field with [name] in [JsObject] from path. | ||
*/ | ||
fun select(name: String): JsonPath = JsonPath(json compose jsonJsObject() compose Index.index(name)) | ||
|
||
/** | ||
* Extract field with [name] from [JsObject] from path. | ||
*/ | ||
fun at(field: String): Optional<Json, Option<Json>> = json compose jsonJsObject() compose At.at(field) | ||
|
||
/** | ||
* Get element at index [i] from [JsArray]. | ||
*/ | ||
operator fun get(i: Int): JsonPath = JsonPath(json compose jsonJsArray() compose Index.index(i)) | ||
|
||
/** | ||
* Extract [A] from path. | ||
*/ | ||
fun <A> extract(DE: Decoder<A>, EN: Encoder<A>): Optional<Json, A> = | ||
json compose parse(DE, EN) | ||
|
||
/** | ||
* Select field with [name] in [JsObject] and extract as [A] from path. | ||
*/ | ||
fun <A> selectExtract(DE: Decoder<A>, EN: Encoder<A>, name: String): Optional<Json, A> = | ||
select(name).extract(DE, EN) | ||
|
||
} | ||
|
||
/** | ||
* Extract [A] from path. | ||
*/ | ||
inline fun <reified A> JsonPath.extract(EN: Encoder<A> = encoder(), DE: Decoder<A> = decoder()): Optional<Json, A> = extract(DE, EN) | ||
|
||
/** | ||
* Select field with [name] in [JsObject] and extract as [A] from path. | ||
*/ | ||
inline fun <reified A> JsonPath.selectExtract(name: String, DE: Decoder<A> = decoder(), EN: Encoder<A> = encoder()): Optional<Json, A> = | ||
selectExtract(DE, EN, name) | ||
|
||
/** | ||
* Unsafe optic: needs some investigation because it is required to extract reasonable typed values from Json. | ||
* https://github.com/circe/circe/blob/master/modules/optics/src/main/scala/io/circe/optics/JsonPath.scala#L152 | ||
*/ | ||
@PublishedApi | ||
internal fun <A> parse(DE: Decoder<A>, EN: Encoder<A>): Prism<Json, A> = Prism( | ||
getOrModify = { json -> DE.decode(json).mapLeft { _ -> json } }, | ||
reverseGet = EN::encode | ||
) | ||
|
||
/** | ||
* Unsafe optic: needs some investigation because it is required to extract reasonable typed values from Json. | ||
* https://github.com/circe/circe/blob/master/modules/optics/src/main/scala/io/circe/optics/JsonPath.scala#L152 | ||
*/ | ||
@PublishedApi | ||
internal inline fun <reified A> parse(EN: Encoder<A> = encoder(), DE: Decoder<A> = decoder()): Prism<Json, A> = parse(DE, EN) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package helios.optics | ||
|
||
import arrow.core.Option | ||
import arrow.data.getOption | ||
import arrow.data.k | ||
import arrow.data.updated | ||
import arrow.instance | ||
import arrow.optics.Lens | ||
import arrow.optics.Optional | ||
import arrow.optics.typeclasses.At | ||
import arrow.optics.typeclasses.Index | ||
import arrow.syntax.either.left | ||
import arrow.syntax.either.right | ||
import helios.core.JsArray | ||
import helios.core.JsObject | ||
import helios.core.Json | ||
|
||
@instance(JsObject::class) | ||
interface JsObjectIndexInstance : Index<JsObject, String, Json> { | ||
override fun index(i: String): Optional<JsObject, Json> = Optional( | ||
getOrModify = { it.value[i]?.right() ?: it.left() }, | ||
set = { js -> { jsObj -> jsObj.copy(jsObj.value.k().updated(i, js)) } } | ||
) | ||
} | ||
|
||
@instance(JsObject::class) | ||
interface JsObjectAtInstance : At<JsObject, String, Option<Json>> { | ||
override fun at(i: String): Lens<JsObject, Option<Json>> = Lens( | ||
get = { it.value.getOption(i) }, | ||
set = { optJs -> | ||
{ js -> | ||
optJs.fold({ | ||
js.copy(value = js.value - i) | ||
}, { | ||
js.copy(value = js.value + (i to it)) | ||
}) | ||
} | ||
} | ||
) | ||
|
||
} | ||
|
||
@instance(JsArray::class) | ||
interface JsArrayIndexInstance : Index<JsArray, Int, Json> { | ||
override fun index(i: Int): Optional<JsArray, Json> = Optional( | ||
getOrModify = { it.value.getOrNull(i)?.right() ?: it.left() }, | ||
set = { js -> { jsArr -> jsArr.copy(jsArr.value.mapIndexed { index, t -> if (index == i) js else t }) } } | ||
) | ||
} |
Oops, something went wrong.