作为幻影的作者,我略带偏见,因此我对幻影的设计目标有很强的把握。Quill库网站上提供了Quill和Phantom之间的现有比较,这自然会偏向另一个方向。
Phantom的目标是成为应用程序层的理想选择,而Quill的目标是成为最奇特的字符串生成器,当您在Cassandra之上构建大型应用程序时,这不是一个非常有用的比较。
使用幻影的优点
关于类型安全性以及DSL对Cassandra功能的改进程度,确实没有竞争。DSL对您的数据结构有非常“深入的”知识,并提供对Cassandra功能的完整支持。它知道在编译时相对于Cassandra有什么可能,而没有。
羽毛笔开发人员认为,幻影具有更多的依赖关系,但这并不完全准确,因为其中大多数是可选的,包括Play迭代和流支持之类的东西。您不想要的东西就这么简单。
Quill比较只是简单地指出:“您可以通过扩展DSL以添加新功能来扩展Phantom,尽管这可能不是一个简单的过程。”,这有点不准确。作为游戏中的一名新手,Quill是Cassandra功能支持方面的一个玩具,您经常会发现自己需要添加功能。无疑,Phantom有其不足之处,但它是成熟得多的替代方法,并且需要扩展的时间明显少得多。
我们已经在几天或几周内解决了大多数更复杂功能的错误,但是通常您可能需要的所有功能都已经存在,而Quill中目前找不到许多功能,甚至要写下来我都需要几个小时。
我并不是来自强大的JPA背景,但是Cassandra和phantom之间的映射是一个非常强大的层,因为它允许您直接从映射DSL自动生成表的整个架构。它还允许DSL在编译时完全模仿Cassandra的行为,它将知道关于您选择主键的哪些查询是可能的,等等,而羽毛笔完全没有这种支持。
Phantom具有非常强大的应用程序级别抽象层,例如连接器,数据库,数据库自动生成,这些可以帮助您将应用程序运行到生产环境中。
Quill背后的代码要复杂得多,虽然我将是第一个对它背后的工程能力给予高度赞扬的人,但是当我认为用户友好性时,故事并没有那么完美。
鹅毛笔尝试一口气做更多的事情。这是一个用于生成的微型引擎,几年前scalaquery试图做一些事情,然后他们决定完全专注于SQL数据库,并放弃了对其他任何东西的支持。它是现代Slick的前身,并使用类似的QDSL引用方法。
鹅毛笔是一个泄漏的抽象。由于它们旨在支持更广泛的数据库,因此它们对数据库特性的特殊性的支持大大逊色。下面是一个示例:
从比较中最基本的示例中,您可以了解到:
val getAllByCountry = quote {
(country: String) => query[WeatherStation]
.filter(_.country == country)
}
}
到目前为止,如果我们包括必要的映射代码,那么一切都很好,可能比等效的幻象要少。
select.where(_.country eqs country).fetch()
但是,让我们进一步探讨。如果您想这样获取一个国家怎么办?或者,如果您尝试获取PagingState
信息怎么办?或输入现有内容PagingState
以通过UI显示内容。
这是Quill至少在比较中无法为用户提供有关其最终体验的任何真实预览的地方。很自然地假设,每当您转到某个工具的页面时,它都会将自己描述为同类工具中最好的工具,就像我们在phantom背后所做的那样,但这绝不是全部。
简而言之,还有一些更酷的东西:
select.where(_.country eqs country).fetchRecord()
select.where(_.country eqs country).one()
那部分选择呢?
select(_.country, _.city).where(_.country eqs country)
Phantom在语义上区分了使用Cassandra在运行时可能发生的所有事情,并且首先尝试通过使用编译时技巧和领域知识来防止运行时错误。你怎么有相当于羽毛笔的?
此外,Quill非常有能力直接从生成查询case class
。
case class WeatherStation(
country: String,
city: String,
stationId: String,
entry: Int,
value: Int
)
object WeatherStation {
val getAllByCountry = quote {
(country: String) =>
query[WeatherStation].filter(_.country == country)
}
val getAllByCountryAndCity = quote {
(country: String, city: String) =>
getAllByCountry(country).filter(_.city == city)
}
val getAllByCountryCityAndId = quote {
(country: String, city: String, stationId: String) =>
getAllByCountryAndCity(country, city).filter(_.stationId == stationId)
}
}
但是它缺乏任何有关您的架构的知识。如果国家不属于主要国家,该怎么办?该查询无效,幻象不允许您对其进行编译,这只是最基本的示例。
Phantom可以直接从表中自动生成CQL,可以动态生成整个数据库,专业版甚至可以自动迁移表并帮助您处理架构不一致问题,并为您提供非常高级的UI和监视界面,可以即时升级和降级架构。
缺点
Phantom的确确实使扩展诸如之类的东西变得不那么冗长TypeCodec
,但是从phantom 2.9.0开始,我们引入了一种非常强大的宏机制来在Cassandra中对类型进行编码,而该机制根本不依赖TypeCodec
!
Phantom要求在定义表DSL方面花费最少的样板,并且从本质上说,与共享表列并不能很好地工作。可以做到,但这不是最漂亮的代码,也不是最糟糕的代码。
全面的
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句