什么可以让这个 dsl 更容易输入或阅读?
我编写了一个名为 ScalaDBTest 的工作语法来替换 scala 中的 dbunit。整个程序有效——只花了两天时间就写好了。我有很多抛光工作要做。
不管怎样,我使用 DSL 将数据输入数据库的语法是可塑的,我希望得到一些关于它的反馈。
基本语法如下所示。非常简单:
country:
- country_id: 1, name: "Canada"
- country_id: 2, name: "United States"
这肯定比 XML 或 SQL 插入语句更好。
我争论过使用“:”或“=”。前者看起来更好,但后者对我来说似乎是自动打字的。
还有一个可以“标记”记录的概念。从某种意义上说,上述语法是匿名记录。标签将是一个有趣的功能,因为您可以通过多种方式使用它们。
country:
record: Canada -> country_id: 1, name: $label # produces "Canada"
record: UnitedStates -> country_id: 2, name: $label.uncamel # produces "United States"
我不喜欢这种语法。有点罗嗦了。使用“-”看起来不太正确,但是如果我使用像“record”这样的实际命令词,我需要添加“->”将它们分开,否则看起来真的很糟糕(出于技术原因没有必要)。
$label 将简单地重复标签,因此您可以最少地使用标签作为重用字符串的方式。 $label.uncamel 会在看起来像驼峰式大小写的地方添加空格。
标签背后的想法是为 API 提供一种无需记住 id 即可访问记录的方法。如果您知道要获取的国家/地区对象是“加拿大”,那么您只需传递标签“加拿大”,它就会将其转换为唯一的 ID 并将其从数据库中提取出来。
这是一个可以指定默认参数的示例:
province:
? country_id: 1, nice_weather: true
- province_id: 1, name: "British Columbia"
- province_id: 2, name: "Manitoba", nice_weather: false
- province_id: 3, name: "New York", country_id: 2
在这里您可以看到一些真正的力量。所有这 3 个“省”记录都有 4 列。由于其中 2 个省份来自加拿大,因此它们会自动继承默认值。在第三种情况下,我们将纽约覆盖为美国。我们可以根据需要混合/匹配。
在实践中,这将节省大量的打字和认知负担,因为我们通常只关心实践中的几个值,其余的可能只是占位符,让数据库关闭缺少必填字段等问题。这对于测试多态对象也确实有帮助。
这是另一个:
article:
? date_create: $now
- article_id: 1, title: "The Fed Sucks"
- article_id: 2, title: null
此代码片段表明您实际上可以放置空值,而无需像在 dbUnit 中那样执行任何技巧。在 DbUnit 中,您必须首先创建一个转换器,将自定义字符串(如“[NULL]”)转换为实际的 null 值。
事实上,我们可以更具表现力,并提供各种表达式和函数来帮助生成数据。例如,$now 返回今天日期/时间的格式正确的 SQL 日期。我将扩展这些类型的功能,以帮助您更轻松地编写测试数据。
不管怎样,我正在寻求帮助来真正清理语法。我可以做出任何改变,而且由于这是新鲜的,我想从一开始就让它变得非常时髦,而不是以后再改变。
谢谢
I've written a working grammar to replace dbunit in scala called ScalaDBTest. The whole program works - only took 2 days to write. I got a lot of polishing to do.
Anyway, the grammar I'm using for the DSL to input data into the database is malleable and I'd like some feedback on it.
The basic syntax looks like this. It's pretty simple:
country:
- country_id: 1, name: "Canada"
- country_id: 2, name: "United States"
This is certainly better than XML or SQL insert statements.
I debated using ":" or "=". The former looks better, but the latter seems automatic for me to type.
There's also a concept where you can "label" a record. In a sense, the above syntax was anonymous records. Labels will be an interesting feature because you can use them in a variety of ways.
country:
record: Canada -> country_id: 1, name: $label # produces "Canada"
record: UnitedStates -> country_id: 2, name: $label.uncamel # produces "United States"
I dislike this syntax. It's a little two wordy. Using the "-" doesn't look right, but if I use an actual command word like "record", I need to put the "->" to separate them otherwise it looks really bad (it's not necessary for technical reasons).
$label will simply repeat the label, so you can use the label at the bare minimum as way to reuse the string. $label.uncamel will add spaces where it looks like camel case.
The idea behind labels is to give the APIs a way to access records without having to remember the ids. If you know the country object you want to get is "Canada", then you can just pass the label "Canada" and it will convert it to a unique id and pull it out of the database.
Here's an example where you can specify default parameters:
province:
? country_id: 1, nice_weather: true
- province_id: 1, name: "British Columbia"
- province_id: 2, name: "Manitoba", nice_weather: false
- province_id: 3, name: "New York", country_id: 2
Here's were you see some real power. All of these 3 'province' records will have 4 columns. Since 2 of the provinces are from Canada, they are automatically inherited from the default values. In the 3rd case, we override it with United States for New York. We can mix/match as required.
In practice, this is going to save a lot of typing and cognitive load as we often only care about a few values in practice, and the rest can be mere placeholders to get the database to shut up about missing required fields and so on. This really helps with testing polymorphic objects too.
Here's another:
article:
? date_create: $now
- article_id: 1, title: "The Fed Sucks"
- article_id: 2, title: null
This snippet shows that you can actually place null values without doing any tricks like in dbUnit. In DbUnit, you have to first create a transformer that translates a custom string (like "[NULL]") to actual null value.
In fact, we can be way more expressive and offer a variety of expressions and functions to help generate data. For example, $now returns a properly formatted sql date of today's date/time. I will expand on these kinds of features to help make writing test data easier.
Anyway, I'm looking for help to really clean up the syntax. I can make any change, and since this is fresh, I'd like to make it really snazzy from the start rather than change it later.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我建议通过以下方式扩展标签的初始语法:
国家:[标签:名称]
-country_id:1,名称:“加拿大”
-country_id:2,名称:“美国”
国家:[标签:2]
-country_id:1,名称:“加拿大”
-country_id:2,名称:“美国”
国家:
-[标签:2]country_id:1,名称:“加拿大”
-[label:name] Country_id: 2, name: "United States"
如果您不想跟踪记录中的列数,可以消除基于索引的标签。
如果您希望扩展该工具,您可以添加其他属性,例如记录组的并发性,例如使用 5 个线程创建 5K 行将如下所示:
国家/地区:[标签:名称] [并发:5]
-[标签:2]country_id:1,名称:“加拿大”
-[标签:名称]country_id:2,名称:“美国”
I will suggest to extent the initial syntax for the label in the following ways:
country: [label:name]
- country_id: 1, name: "Canada"
- country_id: 2, name: "United States"
country: [label:2]
- country_id: 1, name: "Canada"
- country_id: 2, name: "United States"
country:
-[label:2] country_id: 1, name: "Canada"
-[label:name] country_id: 2, name: "United States"
You can eliminate the index based labels if you dont want to track the number of columns in the record.
If you wish to extend the tool you can add another attributes like concurrency for the record groups, for instance create 5K rows with 5 Threads will be something like this:
country: [label:name] [concurrency:5]
-[label:2] country_id: 1, name: "Canada"
-[label:name] country_id: 2, name: "United States"
我会考虑将其嵌入到 Scala 中,而不是创建外部 DSL。有用的功能包括案例类、默认参数、编译器生成的复制方法。
I would consider embedding this in Scala rather than creating an external DSL. Features that would help are case classes, default parameters, compiler generated copy methods.
虽然拥有易于理解和简洁的格式当然很重要,但恕我直言,仍然没有理由在不寻找标准化替代方案的情况下编写自己的专有技术。您是否考虑过使用轻量级且更具可读性的 XML 替代方案,例如 JSON 或 HAML?请注意,如果您仅支持明确定义的子集,您仍然拥有工具支持和标准化的优势。
While it is certainly important to have an easy to understand and terse format, that IMHO still doesn't justify to write your own proprietary without looking for standardized alternatives. Did you consider using lightweight and more readable alternatives to XML, like JSON or HAML? Note that you have still the advantages of tool support and standardization if you only support a well-defined sub-set.
这看起来很像 YAML,所以我建议你看一下。以下是一些有效的 YAML 语法:
This looks a lot like YAML, so I suggest you take a look at that. Here are a couple of valid YAML syntax for what you have: