作为 phantom 的作者,以一个略带偏见的观点来看,我对 phantom 的设计目标有很强的把握。Quill 图书馆网站上有一个现有的 Quill 和 Phantom 之间的比较,这自然偏向另一个方向。
Phantom 旨在成为应用程序层的完美选择,而 Quill 旨在成为最精美的字符串生成器,当您在 Cassandra 之上构建大型应用程序时,这不是一个非常有用的比较。
使用幻影的优点
关于类型安全以及 DSL 对 Cassandra 功能的改进程度,确实没有什么可比拟的。DSL 对您的数据结构有非常“深入”的了解,并为 Cassandra 功能提供完整的支持。它在编译时就知道 Cassandra 什么是可能的,什么不是。
Quill 开发人员认为 phantom 有更多的依赖项,但这并不完全准确,因为其中大多数是可选的,包括 Play iteratees 和流支持之类的东西。不想要的就得不到,就这么简单。
Quill 比较简单地说:“您可以通过扩展 DSL 来扩展 Phantom 以添加新功能,尽管这可能不是一个简单的过程。”,这有点不准确。作为游戏中的新手,Quill 在 Cassandra 功能支持方面是一个玩具,您经常会发现自己需要添加功能。毫无疑问,Phantom 有其差距,但它是一个成熟得多的替代方案,并且需要扩展的次数要少得多。
对于更复杂的功能,我们已经在几天或几周内解决了大多数错误,但通常您可能需要的一切都已经存在,目前在 Quill 中找不到许多功能,甚至需要我几个小时才能写下来。
我不是来自强大的 JPA 背景,但 Cassandra 和 phantom 之间的映射是一个非常强大的层,因为它允许您直接从映射 DSL 自动生成表的整个模式。它还允许 DSL 在编译时完全模仿 Cassandra 的行为,它会知道关于您选择的主键等哪些查询是可能的,quill 根本没有这样的支持。
Phantom 具有非常强大的应用程序级抽象层,例如连接器、数据库、数据库的自动生成,以及帮助您将应用程序运行到生产中的东西。
Quill 背后的代码要复杂得多,虽然我会是第一个对它背后的工程能力给予高度评价的人,但当我认为用户友好时,这个故事并不能成立。
奎尔试图一口气做更多的事情。它是一个用于生成的迷你引擎,几年前 scalaquery 尝试做的事情是在他们决定完全专注于 SQL dbs 并放弃对其他任何东西的支持之前。它是现代 Slick 的前身,并使用类似的 QDSL 引用方法。
Quill 是一个泄漏的抽象。由于它们旨在支持更广泛的数据库,因此它们对数据库细节的特殊性的支持要差得多。下面是一个例子:
从您阅读的比较中非常基本的示例中:
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 等价物?
此外,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 和监控界面,您可以在其中可以即时升级和降级模式。
缺点
总体
- Quill 是一款非常棒的软件,由非常有才华的人编写,对此毫无疑问。
- 严格来说,它比 phantom 在查询生成方面要好,如果我们要与谁是最精简最卑鄙的字符串生成器 Quill 获胜,则可以通过 QDSL 减少无法通过 EDSL 减少的样板。
- 它在应用层是一个非常低劣的工具,对大多数人来说更不自然。Slick 在一定程度上普及了这些概念,但是您希望作为应用程序生命周期一部分的一些最基本的功能无法通过 QDSL 轻松实现,或者至少尚未实现。
- Phantom 更加成熟,被广泛采用,拥有更多的资源和创始团队的投入,长期的路线图以及与 Datastax 的重要合作伙伴关系,帮助我们掌握所有功能。