texlive[61634] Master/texmf-dist: dbshow (17jan22)

commits+karl at tug.org commits+karl at tug.org
Mon Jan 17 21:56:23 CET 2022


Revision: 61634
          http://tug.org/svn/texlive?view=revision&revision=61634
Author:   karl
Date:     2022-01-17 21:56:22 +0100 (Mon, 17 Jan 2022)
Log Message:
-----------
dbshow (17jan22)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/dbshow/dbshow.pdf
    trunk/Master/texmf-dist/source/latex/dbshow/dbshow.dtx
    trunk/Master/texmf-dist/tex/latex/dbshow/dbshow.sty

Modified: trunk/Master/texmf-dist/doc/latex/dbshow/dbshow.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/dbshow/dbshow.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/dbshow/dbshow.dtx	2022-01-17 20:56:07 UTC (rev 61633)
+++ trunk/Master/texmf-dist/source/latex/dbshow/dbshow.dtx	2022-01-17 20:56:22 UTC (rev 61634)
@@ -143,10 +143,10 @@
 \fi
 %</internal>
 %<package>\NeedsTeXFormat{LaTeX2e}
-%<+package|config>\GetIdInfo$Id: dbshow.dtx 461d9bb 2022-01-14 02:50:24 +0800 Changkai Li <lichangkai225 at qq.com> $
+%<+package|config>\GetIdInfo$Id: dbshow.dtx 1a507c4 2022-01-17 22:53:24 +0800 Changkai Li <lichangkai225 at qq.com> $
 %<package>  {Database to store and display data}
 %<package>\ProvidesExplPackage{\ExplFileName}
-%<package|config>  {\ExplFileDate}{1.4}{\ExplFileDescription}
+%<package|config>  {\ExplFileDate}{1.5}{\ExplFileDescription}
 %<*driver>
 \documentclass[full]{l3doc}
 \usepackage[scheme=plain, fontset=ubuntu]{ctex}
@@ -161,6 +161,9 @@
 \usepackage{xcolor}
 \usepackage{tabularray}
 \usepackage{zhnumber}
+\usepackage{tcolorbox}
+\tcbuselibrary{skins, minted, breakable, xparse}
+\usepackage{accsupp}
 
 \geometry{
   left=4.5cm,
@@ -197,8 +200,6 @@
   \addcontentsline{toc}{part}{Change~History}
 }
 
-\let\subsubitem\subitem
-
 \DoNotIndex{\begin, \end}
 \setlength{\parskip}{\medskipamount}
 
@@ -217,6 +218,56 @@
   \par\textbf{\textsf{NOTE:~}}#1\par
 } {}
 
+\definecolor {exambg}    {RGB}  {248, 241, 224} % 示例背景
+\definecolor {examno}    {RGB}  {176, 101, 90}  % 示例行号
+\definecolor {examnobg}  {RGB}  {241, 225, 208} % 示例行号背景
+\definecolor {examframe} {RGB}  {156, 129, 110} % 示例边框(标题背景)
+\definecolor {option}    {HTML} {009933}        % 选项
+\definecolor {cs}        {HTML} {FF6600}        % 命令
+\definecolor {env}       {HTML} {C81531}        % 环境
+\definecolor {link}      {HTML} {33539E}        % 链接
+
+% \definecolor {exambg}    {RGB}  {241, 225, 208} % 示例背景
+% \definecolor {examno}    {HTML} {F3AA20} % 示例行号
+% \definecolor {examnobg}  {HTML} {8B4C70} % 示例行号背景
+% \definecolor {examframe} {HTML} {58094F} % 示例边框(标题背景)
+% \definecolor {option}    {HTML} {8B4C70} % 选项
+% \definecolor {cs}        {HTML} {F3AA20} % 命令
+% \definecolor {cs}        {HTML} {F9A911} % 命令
+% \definecolor {env}       {HTML} {669933} % 环境
+\hypersetup{linkcolor=link}
+\tcbset{
+  exam-base/.style={
+    listing engine=minted, listing and text,
+    minted style=emacs, breakable,
+    minted options={fontsize=\small,breaklines,linenos,numbersep=3mm},
+    colback=exambg, colframe=examframe,
+    left=5mm, enhanced,
+    fonttitle=\small\sffamily\bfseries, fontlower=\small,
+    overlay={
+      \begin{tcbclipinterior}
+        \fill[examnobg]
+        (frame.south west) rectangle ([xshift=5mm]frame.north west);
+      \end{tcbclipinterior}
+    }
+  }
+}
+\DeclareTCBListing[auto counter]{example}{ O{} D(){} m }{%
+  exam-base, title={示例 \thetcbcounter:#3}, label={cn-#2}, #1
+}
+\DeclareTCBListing[auto counter]{example*}{ O{} D(){} m }{%
+  exam-base, title={Example \thetcbcounter: #3}, label={en-#2}, #1
+}
+\renewcommand{\theFancyVerbLine}{%
+  \ttfamily\textcolor{examno}{%
+    \scriptsize\oldstylenums{%
+      \protect\BeginAccSupp{ActualText={}}%
+      \arabic{FancyVerbLine}%
+      \protect\EndAccSupp{}%
+    }%
+  }%
+}
+
 \ExplSyntaxOn
 \makeatletter
 
@@ -274,7 +325,7 @@
   \int_compare:nNnT { \str_count:n {#1} } = { 3 } { \phantom{0} }
   \c_space_tl
 }
-\cs_set_eq:NN \dbshowdocver \dbshowdoc_print_version:n
+\cs_gset_eq:NN \dbshowdocver \dbshowdoc_print_version:n
 
 % #1 ver #2 date #3 type #4 desc
 \cs_new_protected:Nn \dbshowdoc_changes_what:nnnn {
@@ -336,13 +387,26 @@
   \end{itemize}
 } {}
 
-\cs_new_protected:Nn \dbshowdoc_function_begin:N {
+\cs_gset_protected:Npn \__codedoc_typeset_function_block:nN #1#2 {
+    \__codedoc_function_index:x
+      { #1 \bool_if:NT #2 { \tl_to_str:n {TF} } }
+    \__codedoc_function_label:xN {#1} #2
+    \color{cs}\bfseries #1
+    \bool_if:NT #2 { \__codedoc_typeset_TF: }
+    \__codedoc_typeset_expandability:
+    \seq_if_empty:NF \g__codedoc_variants_seq
+      { \__codedoc_typeset_variant_list:nN {#1} #2 }
+    \\
+}
+\cs_new_protected:Nn \dbshowdoc_function_begin:Nn {
   \cs_set_eq:NN \__codedoc_tmp_cs:nN \__codedoc_typeset_function_block:nN
   \cs_set_protected:Npn \__codedoc_typeset_function_block:nN ##1##2 {
     \__codedoc_function_label:xN {##1} ##2
     \hbox_set:Nn \l_tmpa_box {##1}
-    \int_compare:nTF { \str_count:n {##1} <= 22 }
+    \group_begin: \color{#2}\bfseries
+    \int_compare:nTF { \str_count:n {##1} <= 20 }
       {##1} { \adjustbox{width=.7\marginparwidth, height=\box_ht:N \l_tmpa_box}{##1} }
+    \group_end:
     #1{##1}
     \__codedoc_typeset_expandability: \\
   }
@@ -352,7 +416,7 @@
 }
 \DeclareDocumentEnvironment { option } { O{} +v }
   {
-    \dbshowdoc_function_begin:N \SpecialOptionIndex
+    \dbshowdoc_function_begin:Nn \SpecialOptionIndex { option }
     \__codedoc_function:nnw {#1} {#2}
   }
   {
@@ -361,7 +425,7 @@
   }
 \DeclareDocumentEnvironment { environment } { O{} +v }
   {
-    \dbshowdoc_function_begin:N \SpecialEnvIndex
+    \dbshowdoc_function_begin:Nn \SpecialEnvIndex { env }
     \__codedoc_function:nnw {#1} {#2}
   }
   {
@@ -369,8 +433,81 @@
     \dbshowdoc_function_end:
   }
 
+\makeatletter
+\cs_gset_protected:Npn \__codedoc_cmd:nn #1#2
+  {
+    \bool_set_false:N \l__codedoc_cmd_noindex_bool
+    \bool_set_true:N \l__codedoc_cmd_replace_bool
+    \tl_set:Nn \l__codedoc_cmd_index_tl { \q_no_value }
+    \tl_set:Nn \l__codedoc_cmd_module_tl { \q_no_value }
+    \keys_set:nn { l3doc/cmd } {#1}
+    \tl_set:Nn \l__codedoc_cmd_tl {#2}
+    \bool_if:NT \l__codedoc_cmd_replace_bool
+      {
+        \tl_set_rescan:Nnn \l__codedoc_tmpb_tl { } { _ }
+        \tl_replace_all:Non \l__codedoc_cmd_tl \l__codedoc_tmpb_tl { _ }
+        \__codedoc_replace_at_at:N \l__codedoc_cmd_tl
+        \tl_replace_all:Nno \l__codedoc_cmd_tl { _ } \l__codedoc_tmpb_tl
+      }
+    \mode_if_math:T { \mbox }
+      {
+        \bool_if:NT \l__codedoc_allow_indexing_bool { \__codedoc_target: }
+        \verbatim at font
+        \__codedoc_if_almost_str:VT \l__codedoc_cmd_tl
+          {
+            \__kernel_tl_set:Nx \l__codedoc_cmd_tl { \tl_to_str:N \l__codedoc_cmd_tl }
+            \bool_if:NT \g__codedoc_cs_break_bool
+              {
+                \regex_replace_all:nnN
+                  { ([^\\\_]\_*) \_ ([^\_]) }
+                  { \1 \c{BreakableUnderscore} \2 }
+                  \l__codedoc_cmd_tl
+              }
+          }
+        \tl_replace_all:Nnn \l__codedoc_cmd_tl { ~ } { \@xobeysp }
+        \textbf{\l__codedoc_cmd_tl}
+        \@
+      }
+    \bool_if:NT \l__codedoc_allow_indexing_bool
+     {
+      \bool_if:NF \l__codedoc_cmd_noindex_bool
+       {
+        \quark_if_no_value:NF \l__codedoc_cmd_index_tl
+          {
+            \__kernel_tl_set:Nx \l__codedoc_cmd_tl
+              { \c_backslash_str \exp_not:o { \l__codedoc_cmd_index_tl } }
+          }
+        \exp_args:No \__codedoc_key_get:n { \l__codedoc_cmd_tl }
+        \quark_if_no_value:NF \l__codedoc_cmd_module_tl
+          {
+            \__kernel_tl_set:Nx \l__codedoc_index_module_tl
+              { \tl_to_str:N \l__codedoc_cmd_module_tl }
+          }
+        \__codedoc_special_index_module:ooonN
+          { \l__codedoc_index_key_tl }
+          { \l__codedoc_index_macro_tl }
+          { \l__codedoc_index_module_tl }
+          { usage }
+          \l__codedoc_index_internal_bool
+       }
+     }
+  }
+\cs_generate_variant:Nn \__codedoc_cmd:nn { no }
+\makeatother
+
+% #1 color #2 opt #3 content
+\cs_new_protected:Nn \dbshowdoc_cmd:nnn {
+  \__codedoc_get_hyper_target:xN {#3} \l_tmpa_tl
+  \hyperref[\l_tmpa_tl]{\textcolor{#1}{\__codedoc_cmd:no {#2} {#3}}}
+}
 \DeclareDocumentCommand \opt { O{} m }
-  { \__codedoc_cmd:no {#1} {#2} }
+  { \dbshowdoc_cmd:nnn { option } {#1} {#2} }
+\DeclareDocumentCommand \nopt { O{} m }
+  { \textcolor{option}{\textbf{#2}} }
+\DeclareDocumentCommand \env { O{} m }
+  { \dbshowdoc_cmd:nnn { env } {#1} {#2} }
+\DeclareDocumentCommand \cs  { O{} m }
+  { \dbshowdoc_cmd:nnn { cs } {#1} { \c_backslash_str #2 } }
 
 \NewDocumentCommand \linktarget { m m m } {%
   \hyperlink{#1}{#3}%
@@ -385,6 +522,19 @@
     { \GetIdInfo $Id$ }
     { \fileinfo }
 }
+
+\DeclareDocumentCommand \inidef { s d() s o } {
+  \group_begin:
+  \hfill\normalfont(
+  initially~
+  \IfBooleanTF {#1} {empty}
+    { \IfValueTF {#2} { \texttt{#2} } { unset } }
+  ,~
+  \IfBooleanTF {#3} {default empty}
+    { \IfValueTF {#4} { default~\texttt{#4} } { no~default } }
+  )
+  \group_end:
+}
 \ExplSyntaxOff
 
 \begin{document}
@@ -402,7 +552,7 @@
 %</driver>
 % \fi
 %
-% \CheckSum{882}
+% \CheckSum{0}
 % \GetFileId{dbshow.sty}
 %
 % \ExplSyntaxOn
@@ -428,15 +578,11 @@
 % \begin{documentation}
 %
 % \section{引言}
+%
 % 编写本宏包的动机来源于当前没有一个很好的错题本宏包,可以方便的根据各种条件对错
 % 题进行筛选、排序,然后以自定义的样式展示出来。\pkg{dbshow} 宏包实现了四个核心
 % 功能:数据存储和使用、数据筛选、数据排序、数据展示。
 %
-% 数据只需要存储一次,就可以通过预定义的筛选、排序条件和样式展示部分或全部的数据。
-% 如上所述,本宏包其实实现了一个非常简单的数据库,复习错题的功能只是其中一个应用,
-% 和其他数据库宏包比如 \pkg{datatool} 相比,\pkg{dbshow} 更专注于非图表类型的数
-% 据展示。
-%
 % \changes{1.4}{2022-01-10}{Add check}{version of \pkg{l3kernel}}
 % \pkg{dbshow} 依赖版本日期至少为 |2022-11-07| 的 \pkg{l3kernel}。
 %
@@ -473,20 +619,9 @@
 % 除了日期类型,所有类型都是 \pkg{expl3} 的内置类型。\pkg{dbshow} 构建了一个简单
 % 的 |date| 类型,支持转换成整数以及带样式的打印。
 %
-% \subsection{与 \pkg{datatool} 的区别}
-%
 % \changes{1.2}{2022-01-07}{Add doc}{add comparison to \pkg{datatool}}
+% \changes{1.3}{2022-01-07}{Remove doc}{remove comparison to \pkg{datatool}}
 %
-% 从核心功能上看,\pkg{dbshow} 和 \pkg{datatool} 实现了相同的功能。区别在于
-% \pkg{dbshow} 基于 \pkg{expl3} 实现,支持字符串的正则匹配,还支持多级排序。使用
-% 方式上更倾向于样式与内容分离,所有的样式都可以通过选项提前定义好并且可以复用。
-% \pkg{dbshow} 并没有实现从外部文件读取数据以及将数据持久化的功能,我认为这些应
-% 该是更专业的外部程序的工作而不应该在 \LaTeX 中设计这些功能。因此,\pkg{dbshow}
-% 只提供了一个运行时的临时数据库,足够轻便且满足大部分正常需求。如果你想删除或修
-% 改数据库中某一条记录,请去对应的位置删除或修改掉对应的 \env{dbitem} 环境,而不
-% 是让宏包提供一个输出某一行记录的命令。某种意义上记录数据库的 \TeX 源文件本身就
-% 是数据的一种持久化。
-%
 % \section{接口文档}
 %
 % \subsection{创建、展示和清空数据库}
@@ -531,18 +666,6 @@
 %     每个数据库都有一个默认的属性 |id| 用来存储数据的索引。
 %   \end{note}
 %
-%   下面是定义一个错题数据库的示例,|question| 和 |answer| 属性用来存储问题和答
-%   案,|date| 属性存储日期,|info| 属性存储额外信息,|labels| 存储题目标签。
-% \begin{verbatim}
-%   \dbNewDatabase{ques}{
-%     question = tl,
-%     answer = tl,
-%     date = date,
-%     info = tl,
-%     labels = clist
-%   }
-% \end{verbatim}
-%
 % \begin{function}[added=2022-01-05]{\dbshow}
 %   \begin{syntax}
 %     \cs{dbshow} \marg{style} \marg{database}
@@ -561,7 +684,7 @@
 %
 % \subsection{\cs{dbNewStyle} 和样式选项}
 %
-% \begin{function}[added=2022-01-05]{\dbNewStyle}
+% \begin{function}[added=2022-01-05, updated=2022-01-15]{\dbNewStyle}
 %   \begin{syntax}
 %     \cs{dbNewStyle} \oarg{base styles} \marg{style} \marg{database} \marg{opts}
 %   \end{syntax}
@@ -574,222 +697,343 @@
 %
 % \begin{option}[added=2022-01-05]{filter}
 %   \begin{syntax}
-%     filter = <filter>
+%     \opt{filter} = <filter> \inidef(-none-)
 %   \end{syntax}
 %
-%   为当前样式设置由 \cs{dbCombineFilters} 所定义的过滤器
+%   为当前样式设置由 \cs{dbCombineFilters} 所定义的过滤器。示例 \ref{cn-filter}
+%   演示了如何定义条件,将条件组合成过滤器以及使用过滤器。
 % \end{option}
 %
+% \iffalse
+%<*verb>
+% \fi
+\DeleteShortVerb{\|}
+\begin{example}(filter){使用过滤器筛选数据}
+  \dbNewDatabase{filter-db}{name=str, count=int}
+  \begin{dbFilters}{filter-db}
+    \dbNewCond {cond1}{count}{\dbval > 3}
+    \dbNewCond*{cond2}{name} {\d+}
+    \dbCombCond{filter-and}{cond1 && cond2}
+    \dbCombCond{filter-or} {cond1 || cond2}
+  \end{dbFilters}
+  \dbitemkv{filter-db}{name=123, count=4}
+  \dbitemkv{filter-db}{name=ab3, count=2}
+  \dbitemkv{filter-db}{name=bag, count=5}
+  \dbNewStyle{filter-and-style}{filter-db}{
+    filter      = filter-and,
+    before-code = \par Filter And\par,
+    item-code   = {\dbuse{name}: \dbuse{count}\quad},
+  }
+  \dbNewStyle{filter-or-style}{filter-db}{
+    filter      = filter-or,
+    before-code = \par Filter Or\par,
+    item-code   = {\dbuse{name}: \dbuse{count}\quad},
+  }
+  \dbshow{filter-and-style}{filter-db}
+  \dbshow{filter-or-style} {filter-db}
+\end{example}
+\MakeShortVerb{\|}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.1}{2022-01-06}{Add option}{\opt{raw-filter}}
 % \begin{option}[added=2022-01-06]{raw-filter}
 %   \begin{syntax}
-%     raw-filter = <conditional expression>
+%     \opt{raw-filter} = <conditional expression> \inidef
 %   \end{syntax}
 %
 %   使用条件表达式设置匿名过滤器,这里的条件指通过 \cs{dbNewConditional} 定义的
-%   条件。下面代码中两个示例的过滤器具有相同的功能。
+%   条件。示例 \ref{cn-raw-filter} 使用 \opt{raw-filter} 选项,直接组合筛选条
+%   件,达到与示例 \ref{cn-filter} 相同的效果。
 % \end{option}
 %
-% \changes{1.1}{2022-01-06}{Add option}{\opt{raw-filter}}
+% \DeleteShortVerb{\|}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(raw-filter){使用匿名过滤器筛选数据}
+  \dbNewDatabase{filter-db}{name=str, count=int}
+  \begin{dbFilters}{filter-db}
+    \dbNewCond {cond1}{count}{\dbval > 3}
+    \dbNewCond*{cond2}{name} {\d+}
+  \end{dbFilters}
+  \dbitemkv{filter-db}{name=123, count=4}
+  \dbitemkv{filter-db}{name=ab3, count=2}
+  \dbitemkv{filter-db}{name=bag, count=5}
+  \dbNewStyle{filter-and-style}{filter-db}{
+    raw-filter  = {cond1 && cond2},
+    before-code = \par Filter And\par,
+    item-code   = {\dbuse{name}: \dbuse{count}\quad},
+  }
+  \dbNewStyle{filter-or-style}{filter-db}{
+    raw-filter  = {cond1 || cond2},
+    before-code = \par Filter Or\par,
+    item-code   = {\dbuse{name}: \dbuse{count}\quad},
+  }
+  \dbshow{filter-and-style}{filter-db}
+  \dbshow{filter-or-style} {filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+% \MakeShortVerb{\|}
 %
-% \begin{verbatim}
-%   % method 1
-%   \begin{dbFilters}{db}
-%     \dbNewConditional{cond1}{int-attr}{\rval > 1}
-%     \dbNewConditional*{cond2}{str-attr}{\d+}
-%   \end{dbFilters}
-%   \dbNewStyle{style}{db}{raw-filter={cond1 && cond2}}
-%   % method 2
-%   \begin{dbFilters}{db}
-%     \dbNewConditional{cond1}{int-attr}{\rval > 1}
-%     \dbNewConditional*{cond2}{str-attr}{\d+}
-%     \dbCombineFilters{filter}{cond1 && cond2}
-%   \end{dbFilters}
-%   \dbNewStyle{style}{db}{filter=filter}
-% \end{verbatim}
-%
 % \changes{1.2}{2022-01-08}{Fix bug}{string sorting bug}
 % \begin{option}[added=2022-01-05]{sort}
 %   \begin{syntax}
-%     sort = \{ <attr spec1>, <attr spec2>, \ldots{} \}
+%     \opt{sort} = \{ <attr spec1>, <attr spec2>, \ldots{} \} \inidef
 %   \end{syntax}
 %
-%   为当前样式设置排序规则。支持根据 |str|,|date|,|int|,|fp| 类型的数据进行排
-%   序,支持多级排序。\meta{attr} 表示增序,\meta{attr}* 表示降序。下面例子中,
-%   使用 |sort-style| 展示数据时的顺序为先按 |level| 降序,|level| 相同的再按出
-%   生日期 |birth| 增序,以此类推。
+%   为当前样式设置排序规则。支持对 |str|,|date|,|int|,|fp| 类型的数据进行排
+%   序,支持多级排序。\meta{attr} 表示增序,\meta{attr}\texttt{*} 表示降序。示
+%   例 \ref{cn-sort} 的排序规则为先按 |count| 降序排序,|count| 相同的再按
+%   |name| 增序排序。
 % \end{option}
 %
-% \begin{verbatim}
-%   \dbNewDatabase{sort-example}{
-%     name = str,
-%     birth = date,
-%     level = int,
-%     weight = fp,
-%   }
-%   \dbNewStyle{sort-style}{sort-example}{
-%     sort = { level*, birth, name, weight }
-%   }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(sort){多级排序}
+  \dbNewDatabase{sort-db}{name=str, count=int}
+  \dbNewStyle{sort-style}{sort-db}{
+    sort = {count*, name},
+    item-code = {\dbuse{name}: \dbuse{count}\quad}
+  }
+  \dbitemkv{sort-db}{name=bag, count=1}
+  \dbitemkv{sort-db}{name=box, count=1}
+  \dbitemkv{sort-db}{name=tag, count=2}
+  \dbitemkv{sort-db}{name=pen, count=3}
+  \dbshow{sort-style}{sort-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
 %
-% \begin{option}[added=2022-01-05, rEXP]{item-code}
+% \begin{option}[added=2022-01-05, rEXP]{before-code}
 %   \begin{syntax}
-%     item-code = <code>
+%     \opt{before-code} = <before code> \inidef*
 %   \end{syntax}
 %
-%   该选项用来设置展示数据库中每条记录的代码。你可以使用 \cs{dbuse} 来展示属性的
-%   值。
+%   该选项用来设置在展示整个数据库之\zhbefore 需要执行的代码(见示例
+%   \ref{cn-db-wrap})。
 % \end{option}
 %
-% \changes{1.3}{2022-01-09}{Update option}{\opt{<attr>/sep}}
-% \begin{option}[added=2022-01-05, updated=2022-01-08, rEXP]{<attr>/sep}
+% \begin{option}[added=2022-01-05, rEXP]{after-code}
 %   \begin{syntax}
-%     <attr>/sep = <separator> \\
-%     <attr>/sep = \{ \\
-%     ~~\meta{separator between two}, \\
-%     ~~\meta{separator between more than two}, \\
-%     ~~\meta{separator between final two} \\
-%     \} \\
-%     <attr>/sep = \{ \\
-%     ~~\meta{separator before year}, \\
-%     ~~\meta{separator between year and month}, \\
-%     ~~\meta{separator between month and day}, \\
-%     ~~\meta{separator after day} \\
-%     \} \\
+%     \opt{after-code} = <after code> \inidef*
 %   \end{syntax}
 %
-%   该选项只适用于类型为 |clist| 或 |date| 的属性,用来设置列表间元素的间隔。参
-%   数为一个 \meta{separator} 时,所有元素间的分隔符被设置为 \meta{separator}。
-%   \meta{separator before year} 和 \meta{separator after day} 被设置为空。
+%   该选项用来设置在展示整个数据库之\zhafter 需要执行的代码(见示例
+%   \ref{cn-db-wrap})。
 % \end{option}
 %
-%   参数为3个元素的逗号分隔的列表时,此选项用来设置列表元素的分隔符,分别用来设
-%   置只有两个元素时的分隔符 \meta{separator between two},超过两个元素时的分隔
-%   符 \meta{separator between more than two},和最后两个元素之间的分隔符
-%   \meta{separator between final two}。对于类型为 |clist| 的属性,设置此选项时
-%   如果参数列表数量不是1或者3会触发报错。
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(db-wrap){设置展示数据库前后的代码}
+  \dbNewDatabase{wrap-db}{text=tl}
+  \dbNewStyle{wrap-style}{wrap-db}{
+    before-code = \textit{before code}\quad,
+    after-code  = \textit{after code},
+    item-code   = \dbarabic.~\dbuse{text}\quad
+  }
+  \dbitemkv{wrap-db}{text=text1}
+  \dbitemkv{wrap-db}{text=text2}
+  \dbitemkv{wrap-db}{text=text3}
+  \dbshow{wrap-style}{wrap-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
 %
-% \begin{verbatim}
-%   % clist-attr is an attribute of database db
-%   % suppose the val of clist-attr is { 1, 2, 3 }
-%   \dbNewStyle{clist-sep}{db}{
-%     clist-attr/sep = { ,~ },                % print 1, 2, 3
-%     clist-attr/sep = { {,~}, {,~}, {and~} } % print 1, 2 and 3
-%   }
-% \end{verbatim}
-%
-%   参数为4个元素的逗号分隔的列表时,此选项用来设置日期的分隔符,分别用来设
-%   置 \meta{year} 之前的分隔符 \meta{separator before year} ,\meta{year} 和
-%   \meta{month} 之间的分隔符 \meta{separator between year and month} ,
-%   \meta{month} 和 \meta{day} 之间的分隔符,以及 \meta{day} 之后的分隔符。对于
-%   类型为 |date| 的属性,设置此选项时如果参数列表数量不是1或者4会触发报错。
-%
-% \begin{verbatim}
-%   % date-attr is an attribute of database db
-%   % suppose the val of date-attr is 2022/01/01
-%   \dbNewStyle{date-sep}{db}{
-%     date-attr/sep = -,             % print 2022-01-01
-%     date-attr/sep = { |, -, -, | } % print |2022-01-01|
-%   }
-% \end{verbatim}
-%
-% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/zfill}}
-% \begin{option}[added=2022-01-08, EXP]{<attr>/zfill}
+% \begin{option}[added=2022-01-05, rEXP]{item-code}
 %   \begin{syntax}
-%     <attr>/zfill = <\TTF>
+%     \opt{item-code} = <item code> \inidef
 %   \end{syntax}
 %
-%   该选项只适用于类型为 |date| 的属性。控制输出月份和天时是否补零。
+%   该选项用来设置展示数据库中每条记录的代码。你可以使用 \cs{dbuse}\marg{attr}
+%   来指代属性 \meta{attr} 的值。示例 \ref{cn-item-code} 演示了如何展示一个首
+%   字母缩写词表。
 % \end{option}
 %
-% \changes{1.4}{2022-01-13}{Add macro}{\cs{dbdatesep}}
-% \begin{function}[added=2022-01-13, EXP]{\dbdatesep}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(item-code){展示数据库条目}
+  \dbNewDatabase{item-db}{acronym=str, desc=tl}
+  \dbNewStyle{item-style}{item-db}{
+    before-code = {\dbIfEmptyF{\begin{description}}},
+    after-code  = {\dbIfEmptyF{\end{description}}},
+    item-code   = {\item[\dbuse{acronym}] \dbuse{desc}},
+    sort        = acronym,
+  }
+  \dbitemkv{item-db}{acronym=PM,  desc={Prime Minister}}
+  \dbitemkv{item-db}{acronym=CBD, desc={Central Business District}}
+  \dbitemkv{item-db}{acronym=DL,  desc={Deep Learning}}
+  \dbshow{item-style}{item-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-17}{Add option}{\opt{item-code*}}
+% \begin{option}[added=2022-01-17, rEXP]{item-code*}
 %   \begin{syntax}
-%     \cs{dbdatesep} \marg{separator}
+%     \opt{item-code*} = <item code> \inidef
 %   \end{syntax}
 %
-%   设置内部解析日期时的间隔符,默认为 |/|,即存储数据的格式为 |yyyy/mm/dd|。
-% \end{function}
+%   使用该选项设置的代码在被插入到最终执行代码序列之前会先通过
+%   \cs{protected at edef} 完全展开。示例 \ref{cn-item-exp} 展示了如何通过该选项
+%   使用表格来展示数据。
+% \end{option}
 %
-% \subsubsection{装饰器}
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example}(item-exp){用表格展示数据}
+  \dbNewDatabase{tab-db}{name=str, count=int}
+  \dbNewStyle{tab-style}{tab-db}{
+    before-code = {%
+      \begin{tabular}{ll}
+        name & count \\
+    },
+    after-code  = \end{tabular},
+    item-code*  = {%
+      \textcolor{red}{\dbuse{name}} & \dbuse{count} \\
+    },
+  }
+  \dbitemkv{tab-db}{name=bag, count=100}
+  \dbitemkv{tab-db}{name=pig, count=20}
+  \dbshow{tab-style}{tab-db}
+\end{example}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
 %
-% 下面这些选项在不同层次上装饰原有的展示代码,有些其实不必通过选项的形式来装饰,
-% 但这样做的好处是可以进一步使样式与内容分离。下面的例子中,\meta{style1} 和
-% \meta{style2} 是相同的样式,都用 * 将 \meta{attr1} 包裹住了,但是如果你还想定
-% 义一个样式用 = 将 \meta{attr1} 包裹住,如果用 \meta{style1} 的方式,那就可能
-% 需要重复大片代码,用 \meta{style2} 的方式则可以很轻松的继承 \meta{style1} 中的
-% 代码。
-%
-% \begin{verbatim}
-%   \dbNewStyle{style1}{db}{
-%     item-code = {%
-%       *\rvuse{attr1}*\rvuse{attr2}
-%       % more code
-%     }
-%   }
-%   \dbNewStyle{base-style}{db}{
-%     item-code = {%
-%       \rvuse{attr1}\rvuse{attr2}
-%       % more code
-%     }
-%   }
-%   \dbNewStyle[base-style]{style2}{db}{
-%     attr1/before-code = { * },
-%     attr1/after-code = { * },
-%   }
-%   \dbNewStyle[base-style]{style3}{db}{
-%     attr1/before-code = { = },
-%     attr1/after-code = { = },
-%   }
-% \end{verbatim}
-%
-% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/wrapper}}
-% \begin{option}[added=2022-01-08, rEXP]{<attr>/wrapper}
+% \changes{1.2}{2022-01-08}{Add options}{\opt{record-before-code},
+% \opt{record-after-code}}
+% \changes{1.5}{2022-01-14}{Update options}{Rename \opt{record-before-code}
+% and \opt{record-after-code} to \opt{item-before-code} and
+% \opt{item-after-code}}
+% \begin{option}[added=2022-01-08, updated=2022-01-14, rEXP]{item-before-code}
 %   \begin{syntax}
-%     <attr>/wrapper = <control sequence>
+%     \opt{item-before-code} = <before code> \inidef*
 %   \end{syntax}
 %
-%   该选项只适用于类型为 |date| 的属性。\meta{control sequence} 只接收一个参数即
-%   日期,如果设置了此选项,则最后输出的日期为
-%   \meta{control sequence}\marg{date}。
+%   在 \meta{item code} 之\zhbefore 执行的代码(见示例 \ref{cn-item-wrapper})。
 % \end{option}
 %
-% \begin{option}[added=2022-01-05, rEXP]{before-code}
+% \begin{option}[added=2022-01-08, updated=2022-01-14, rEXP]{item-after-code}
 %   \begin{syntax}
-%     before-code = <code>
+%     \opt{item-after-code} = <after code> \inidef*
 %   \end{syntax}
 %
-%   该选项用来设置在展示整个数据库之\zhbefore 需要执行的代码。
+%   在 \meta{item code} 之\zhafter 执行的代码(见示例 \ref{cn-item-wrapper})。
 % \end{option}
 %
-% \begin{option}[added=2022-01-05, rEXP]{after-code}
-%   \begin{syntax}
-%     after-code = <code>
-%   \end{syntax}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(item-wrapper){设置展示条目之前和之后的代码}
+  \dbNewDatabase{item-wrap-db}{text=tl, hint=tl}
+  \dbNewStyle{item-wrap-style}{item-wrap-db}{
+    item-before-code = \begingroup\ttfamily<,
+    item-after-code  = >\endgroup,
+    item-code        = \dbuse{text}~(\dbuse{hint}),
+  }
+  \dbitemkv{item-wrap-db}{text=example, hint={this is an example}}
+  \dbshow{item-wrap-style}{item-wrap-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
 %
-%   该选项用来设置在展示整个数据库之\zhafter 需要执行的代码。
-% \end{option}
+% \subsubsection{属性选项}
 %
-% \changes{1.2}{2022-01-08}{Add options}{\opt{record-before-code},
-% \opt{record-after-code}}
-% \begin{option}[added=2022-01-05, rEXP]{record-before-code}
+% \changes{1.5}{2022-01-14}{Remove option}{\opt{<attr>/wrapper}}
+%
+% \changes{1.5}{2022-01-14}{Add options}{\opt{<attr>/code},
+% \opt{<attr>/code*}}
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/code}
 %   \begin{syntax}
-%     record-before-code = <code>
+%     \nopt{<attr>/code} = <code> \inidef(\#1)
 %   \end{syntax}
 %
-%   该选项用来设置在展示当前记录之\zhbefore 需要执行的代码。
+%     设置 \meta{attr} 的样式代码。在 \meta{code} 中用 |#1| 指代属性的值。示例
+%     \ref{cn-attr-code} 将数量超过10个的物品打印为红色,少于10个的则打印为青色。
 % \end{option}
 %
-% \begin{option}[added=2022-01-05, rEXP]{record-after-code}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(attr-code){设置单个属性样式}
+  \dbNewDatabase{attr-code-db}{name=str, count=int}
+  \begin{dbFilters}{attr-code-db}
+    \dbNewCond{large}{count}{\dbval >= 10}
+  \end{dbFilters}
+  \dbNewStyle{base-style}{attr-code-db}{
+    item-code  = \dbuse{name}:~\dbuse{count}\quad,
+  }
+  \dbNewStyle[base-style]{large-style}{attr-code-db}{
+    raw-filter = large,
+    name/code  = \textcolor{red}{#1},
+  }
+  \dbNewStyle[base-style]{small-style}{attr-code-db}{
+    raw-filter = !large,
+    name/code  = \textcolor{teal}{#1},
+  }
+  \dbitemkv{attr-code-db}{name=bag, count=1}
+  \dbitemkv{attr-code-db}{name=pen, count=12}
+  \dbitemkv{attr-code-db}{name=pig, count=5}
+  \dbitemkv{attr-code-db}{name=egg, count=50}
+  \dbshow{large-style}{attr-code-db}
+  \dbshow{small-style}{attr-code-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/code*}
 %   \begin{syntax}
-%     record-after-code = <code>
+%     \nopt{<attr>/code*} = <code> \inidef
 %   \end{syntax}
 %
-%   该选项用来设置在展示当前记录之\zhafter 需要执行的代码。
+%     设置 \meta{attr} 的样式代码。在 \meta{code} 中用 |#1| 指代\textbf{展开}的
+%     属性的值。这对某些需要以特定格式解析参数的命令比较有用。
 % \end{option}
 %
+%     示例 \ref{cn-exp-code} 中 \pkg{zhnumber} 宏包的 \cs{zhdate} 命令接收
+%     |yyyy/mm/dd| 格式的时期并输出中文日期,本宏包默认的日期输出格式是
+%     |yyyy/mm/dd|,因此可以通过 \opt{date/code*} 选项,将日期完全展开后然后传递
+%     给 \cs{zhdate} 命令,如果不展开,\cs{zhdate} 接收到的是若干个用来展示日期
+%     的控制序列,而不是 |yyyy/mm/dd| 格式的时期,进而触发报错。
+%
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example}(exp-code){中文日期}
+  % \usepackage{zhnumber}
+  \dbNewDatabase{exp-db}{date=date, event=tl}
+  \dbNewStyle{exp-style}{exp-db}{
+    item-code  = \par\makebox[4cm][l]{\dbuse{date}}\dbuse{event},
+    date/code* = \zhdate{#1},
+  }
+  \dbitemkv{exp-db}{date=2020/12/31, event=eat}
+  \dbitemkv{exp-db}{date=2021/01/01, event=sleep}
+  \dbshow{exp-style}{exp-db}
+\end{example}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
+%
 % \begin{option}[added=2022-01-05, rEXP]{<attr>/before-code}
 %   \begin{syntax}
-%     <attr>/before-code = <code>
+%     \nopt{<attr>/before-code} = <before code> \inidef*
 %   \end{syntax}
 %
 %   该选项用来设置展示数据库中属性 \meta{attr} 对应数据之\zhbefore 需要执行的代
@@ -798,7 +1042,7 @@
 %
 % \begin{option}[added=2022-01-05, rEXP]{<attr>/after-code}
 %   \begin{syntax}
-%     <attr>/after-code = <code>
+%     \nopt{<attr>/after-code} = <after code> \inidef*
 %   \end{syntax}
 %
 %   该选项用来设置展示数据库中属性 \meta{attr} 对应数据之\zhafter 需要执行的代码。
@@ -805,9 +1049,53 @@
 %   \cs{dbuse} 会在展示属性数据\zhafter 执行此代码。
 % \end{option}
 %
+% 属性样式代码的执行顺序为:
+% \begin{enumerate}[nolistsep]
+%   \item \opt{<attr>/before-code}
+%   \item \opt{<attr>/code} or \opt{<attr>/code*}
+%   \item \opt{<attr>/after-code}
+% \end{enumerate}
+%
+% \changes{1.5}{2022-01-16}{Add options}{\opt{<attr>/item-code},
+% \opt{<attr>/item-code*}}
+% \begin{option}[added=2022-01-16, rEXP]{<attr>/item-code}
+%   \begin{syntax}
+%     \nopt{<attr>/item-code} = <item code> \inidef(\#1)
+%   \end{syntax}
+%
+%   设置列表元素的样式代码。在 \meta{item code} 中用 |#1| 指代列表元素的值。示例
+%   \ref{cn-clist-code} 演示了如何为列表元素设置额外的样式。
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(clist-code){设置列表元素样式代码}
+  \dbNewDatabase{clist-db}{name=str, label=clist}
+  \dbNewStyle{clist-style}{clist-db}{
+    item-code       = \par\dbuse{name}:~\dbuse{label},
+    label/item-code = (\textcolor{red}{\textit{#1}}),
+  }
+  \dbitemkv{clist-db}{name=pig,  label={animal, meat}}
+  \dbitemkv{clist-db}{name=Alex, label={person, male}}
+  \dbshow{clist-style}{clist-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \begin{option}[added=2022-01-16, rEXP]{<attr>/item-code*}
+%   \begin{syntax}
+%     \nopt{<attr>/item-code*} = <item code> \inidef
+%   \end{syntax}
+%
+%   设置列表元素的样式代码。在 \meta{item code} 中用 |#1| 指代\textbf{展开}的列
+%   表元素的值。
+% \end{option}
+%
 % \begin{option}[added=2022-01-05, rEXP]{<attr>/item-before-code}
 %   \begin{syntax}
-%     <attr>/item-before-code = <code>
+%     \nopt{<attr>/item-before-code} = <code> \inidef*
 %   \end{syntax}
 %
 %   该选项只适用于类型为 |clist| 的属性,用来设置展示列表每个元素\zhbefore 需要
@@ -816,7 +1104,7 @@
 %
 % \begin{option}[added=2022-01-05, rEXP]{<attr>/item-after-code}
 %   \begin{syntax}
-%     <attr>/item-after-code = <code>
+%     \nopt{<attr>/item-after-code} = <code> \inidef*
 %   \end{syntax}
 %
 %   该选项只适用于类型为 |clist| 的属性,用来设置展示列表每个元素\zhafter 需要执
@@ -823,58 +1111,284 @@
 %   行的代码。
 % \end{option}
 %
-% \subsection{使用 \cs{dbNewReviewPoints} 定义复习点}
+% 列表元素样式代码的执行顺序为:
+% \begin{enumerate}[nolistsep]
+%   \item \opt{<attr>/item-before-code}
+%   \item \opt{<attr>/item-code} or \opt{<attr>/item-code*}
+%   \item \opt{<attr>/item-after-code}
+% \end{enumerate}
 %
+% \def\sepini{%
+%   \begingroup\normalfont%
+%   \hfill%
+%   (initially \texttt{\{,\char`~\}} for \texttt{clist}%
+%   and \texttt{/} for \texttt{date}, no default)%
+%   \endgroup%
+% }
+% \changes{1.3}{2022-01-09}{Update option}{\opt{<attr>/sep}}
+% \begin{option}[added=2022-01-05, updated=2022-01-08, rEXP]{<attr>/sep}
+%   \begin{syntax}
+%     \nopt{<attr>/sep} = <separator> \sepini\\
+%     \nopt{<attr>/sep} = \{ \\
+%     ~~\meta{separator between two}, \\
+%     ~~\meta{separator between more than two}, \\
+%     ~~\meta{separator between final two} \\
+%     \} \\
+%     \nopt{<attr>/sep} = \{ \\
+%     ~~\meta{separator before year}, \\
+%     ~~\meta{separator between year and month}, \\
+%     ~~\meta{separator between month and day}, \\
+%     ~~\meta{separator after day} \\
+%     \} \\
+%   \end{syntax}
+%
+%   该选项只适用于类型为 |clist| 或 |date| 的属性,用来设置列表间元素的间隔。参
+%   数为一个 \meta{separator} 时,所有元素间的分隔符被设置为 \meta{separator}。
+%   \meta{separator before year} 和 \meta{separator after day} 被设置为空。
+% \end{option}
+%
+%   参数为3个元素的逗号分隔的列表时,此选项用来设置列表元素的分隔符,分别用来设
+%   置只有两个元素时的分隔符 \meta{separator between two},超过两个元素时的分隔
+%   符 \meta{separator between more than two},和最后两个元素之间的分隔符
+%   \meta{separator between final two}。对于类型为 |clist| 的属性,设置此选项时
+%   如果参数列表数量不是1或者3会触发报错。示例 \ref{cn-clist-sep} 展示了如何设
+%   置列表元素间隔。
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(clist-sep){设置列表元素间隔}
+  \dbNewDatabase{clist-db}{label=clist}
+  \dbNewStyle{clist-base}{clist-db}{
+    before-code = {\dbIfEmptyF{\begin{enumerate}}},
+    after-code  = {\dbIfEmptyF{\end{enumerate}}},
+    item-code   = \item \dbuse{label},
+  }
+  \dbNewStyle[clist-base]{clist-style1}{clist-db}{
+    label/sep = {{,~}}
+  }
+  \dbNewStyle[clist-base]{clist-style2}{clist-db}{
+    label/sep = {{,~}, {,~}, ~and~}
+  }
+  \dbitemkv{clist-db}{label={a, b, c}}
+  \dbitemkv{clist-db}{label={1, 2, 3}}
+  \dbshow{clist-style1}{clist-db}
+  \dbshow{clist-style2}{clist-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+%   参数为4个元素的逗号分隔的列表时,此选项用来设置日期的分隔符,分别用来设
+%   置 \meta{year} 之前的分隔符 \meta{separator before year} ,\meta{year} 和
+%   \meta{month} 之间的分隔符 \meta{separator between year and month} ,
+%   \meta{month} 和 \meta{day} 之间的分隔符,以及 \meta{day} 之后的分隔符。对于
+%   类型为 |date| 的属性,设置此选项时如果参数列表数量不是1或者4会触发报错。示例
+%   \ref{cn-date-sep} 展示了如何自定义日期间隔符。
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(date-sep){设置日期间隔符}
+  \dbNewDatabase{date-db}{date=date}
+  \dbNewStyle{date-style1}{date-db}{
+    item-code = \dbuse{date}\quad,
+    date/sep  = -,
+  }
+  \dbNewStyle{date-style2}{date-db}{
+    item-code = \dbuse{date}\quad,
+    date/sep  = {\$, +, !, \$},
+  }
+  \dbitemkv{date-db}{date=2020/01/02}
+  \dbitemkv{date-db}{date=2022/07/12}
+  \dbshow{date-style1}{date-db}
+  \dbshow{date-style2}{date-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-14}{Add option}{\opt{<attr>/format-code}}
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/format-code}
+%   \begin{syntax}
+%     \nopt{<attr>/format-code} = <format code> \inidef
+%   \end{syntax}
+%
+%   该选项用来更精细地控制日期的输出格式。在 \meta{format code}中,|#1| 代表年份,
+%   |#2| 代表月份,|#3| 代表天。示例 \ref{cn-date-code} 演示了如何使用该选项。
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(date-code){任意日期格式}
+  \dbNewDatabase{date-db}{date=date}
+  \dbNewStyle{date-style}{date-db}{
+    item-code        = \dbuse{date},
+    date/format-code = {日:#3\quad 月:#2\quad 年:#1}
+  }
+  \dbitemkv{date-db}{date=2022/01/01}
+  \dbshow{date-style}{date-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/zfill}}
+% \begin{option}[added=2022-01-08, EXP]{<attr>/zfill}
+%   \begin{syntax}
+%     \nopt{<attr>/zfill} = <\TTF> \inidef(true)[true]
+%   \end{syntax}
+%
+%   该选项只适用于类型为 |date| 的属性。控制输出月份和天时是否补零。示例
+%   \ref{cn-date-zfill} 展示了补零和不补零的日期。
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(date-zfill){月份和天补零}
+  \dbNewDatabase{date-db}{date=date}
+  \dbNewStyle {zfill-style}{date-db}{
+    item-code = \dbuse{date},
+  }
+  \dbNewStyle{nofill-style}{date-db}{
+    item-code  = \dbuse{date},
+    date/zfill = false,
+  }
+  \dbitemkv{date-db}{date=2022/01/01}
+  \dbshow {zfill-style}{date-db}
+  \dbshow{nofill-style}{date-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.4}{2022-01-13}{Add macro}{\cs{dbdatesep}}
+% \begin{function}[added=2022-01-13]{\dbdatesep}
+%   \begin{syntax}
+%     \cs{dbdatesep} \marg{separator}
+%   \end{syntax}
+%
+%   设置内部解析日期时的分隔符,默认为 |/|,即存储数据的格式为 |yyyy/mm/dd|。
+%   示例 \ref{cn-inner-date-sep} 演示了使用两种格式存储数据,但实际上分隔符并
+%   没有被存储,而是被内部用来解析年、月和日然后存储为三个整数。
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(inner-date-sep){设置日期解析格式}
+  \dbNewDatabase{inner-date-db}{date=date}
+  \dbNewStyle{inner-date-style}{inner-date-db}{
+    item-code = \dbuse{date}\quad,
+  }
+  \dbitemkv{inner-date-db}{date=2020/01/20}
+  \dbdatesep{-}
+  \dbitemkv{inner-date-db}{date=2022-01-10}
+  \dbshow{inner-date-style}{inner-date-db}
+\end{example}
+\dbdatesep{/}
+% \iffalse
+%</verb>
+% \fi
+% \subsection{过滤器}
+%
+% 过滤器是一些条件的组合,只有满足过滤器指定条件的数据才会被展现出来。
+%
 % \begin{function}[added=2022-01-05]{\dbNewReviewPoints}
 %   \begin{syntax}
 %     \cs{dbNewReviewPoints} \marg{name} \marg{points}
 %   \end{syntax}
 %
-%   定义名为 \meta{name} 的复习点。这是专门为错题本或复习所定制的功能,
-%   \meta{points}是一系列整数,现在假设每道错题你都将写错时的日期记录在了 |date|
-%   属性中,并且你希望每隔2,5,15天复习一次。下面的代码给出了一个实现示例。
+%   定义名为 \meta{name} 的复习间隔列表。\meta{points} 是一系列整数或整数表达
+%   式,用于设置日期的过滤器。示例 \ref{cn-review-points} 中,预定义了一个复习
+%   间隔列表 |review| 和一个时间锚点 |2022/02/06|,筛选时,将当前条目的日期与
+%   描点相比较,计算得到时间间隔 $\meta{interval} = \meta{date anchor} -
+%   \meta{date cmp}$,只有当 \meta{interval} 的值在 \meta{points} 中时,条件才
+%   成立。
 % \end{function}
 %
-% \begin{verbatim}
-%   \dbNewReviewPoints{review-point}{2, 5, 15}            % 定义复习点
-%   \begin{dbFilters}
-%     \dbNewConditional{cond1}{date}{review-point|\Today} % 定义复习条件
-%     \dbCombineConditionals{filter1}{cond1}              % 定义过滤器
-%   \end{dbFilters}
-%   \dbNewStyle{review-style}{ques}{filter=filter1}       % 定义展示样式
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\DeleteShortVerb{\|}
+\begin{example}(review-points){按时间间隔筛选}
+  \dbNewDatabase{filter-db}{date=date}
+  \dbNewReviewPoints{review}{2, 5}
+  \dbNewRawFilter*{review-filter}{filter-db}{date}{review|2022/02/06}
+  \dbNewStyle{filter-style}{filter-db}{
+    item-code = \dbuse{date}\quad,
+    filter    = review-filter,
+  }
+  \dbitemkv{filter-db}{date=2022/01/30}
+  \dbitemkv{filter-db}{date=2022/02/01}
+  \dbitemkv{filter-db}{date=2022/02/04}
+  \dbshow{filter-style}{filter-db}
+\end{example}
+\MakeShortVerb{\|}
+% \iffalse
+%</verb>
+% \fi
 %
-% \subsection{在 \env{dbFilters} 环境中定义过滤器}
-%
-% \begin{environment}[added=2022-01-05]{dbFilters}
+% \changes{1.5}{2022-01-16}{Update env}{add starred version of \env{dbFilters}}
+% \begin{environment}[added=2022-01-05, updated=2022-01-16]{dbFilters}
 %   \begin{syntax}
-%     |\begin{dbFilters}|\marg{database} \\
+%     |\begin|\{\env{dbFilters}\}   \marg{database} \\
 %     ~~\meta{code}
-%     |\end{dbFilters}| \\
+%     |\end|\{\env{dbFilters}\} \\
+%     |\begin|\{\env{dbFilters}\} * \marg{database} \\
+%     ~~\meta{code}
+%     |\end|\{\env{dbFilters}\} \\
 %   \end{syntax}
 %
 %   \env{dbFilters}用来定义过滤器,此环境中定义了 \cs{dbNewConditional} 命令用来
-%   定义条件和 \cs{dbCombineConditionals} 命令用来组合条件定义过滤器。过滤器独立
-%   于每个 \meta{database},这意味着你可以在不同数据库中定义名称相同的过滤条件和
-%   过滤器。
+%   定义条件和 \cs{dbCombineConditionals} 命令用来组合条件定义过滤器。星号版本在
+%   定义条件的同时会定义一个与条件同名且只使用这个条件的过滤器。示例
+%   \ref{cn-star-filter} 中定义 |greater| 条件的同时也定义了一个同名的过滤器,你
+%   可以直接在 \opt{filter} 中使用这个过滤器。过滤器独立于每个 \meta{database},
+%   这意味着你可以在不同数据库中定义名称相同的过滤条件和过滤器。
 % \end{environment}
 %
-% \begin{function}[added=2022-01-05, updated=2022-01-08]{\dbNewConditional, \dbNewConditional*}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(star-filter){定义与条件同名的过滤器}
+  \dbNewDatabase{filter-db}{count=int}
+  \begin{dbFilters}*{filter-db}
+    \dbNewCond{greater}{count}{\dbval > 3}
+  \end{dbFilters}
+  \dbNewStyle{filter-style}{filter-db}{
+    filter    = greater,
+    item-code = \dbuse{count}\quad,
+  }
+  \dbitemkv{filter-db}{count=2}
+  \dbitemkv{filter-db}{count=5}
+  \dbshow{filter-style}{filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-15}{Add macros}{\cs{dbNewCond}, \cs{dbCombCond}}
+% \begin{function}[added=2022-01-05, updated=2022-01-16]{\dbNewConditional,
+% \dbNewCond, \dbNewConditional*, \dbNewCond*}
 %   \begin{syntax}
-%     \cs{dbNewConditional}  \marg{name}        \marg{attr} \marg{cond spec} \\
-%     \cs{dbNewConditional}* \marg{name}        \marg{attr} \marg{cond spec} \\[2pt]
-%     \cs{dbNewConditional}  \marg{name} \marg{int/fp attr} \marg{expr} \\
-%     \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{expr} \\
-%     \cs{dbNewConditional}  \marg{name} \marg{str/tl attr} \marg{regex expr} \\
-%     \cs{dbNewConditional}* \marg{name} \marg{str/tl attr} \marg{regex expr} \\
-%     \cs{dbNewConditional}  \marg{name}  \marg{clist attr} \marg{val list} \\
-%     \cs{dbNewConditional}* \marg{name}  \marg{clist attr} \marg{val list} \\
-%     \cs{dbNewConditional}  \marg{name}   \marg{date attr} \marg{expr}
-%     \cs{dbNewConditional}* \marg{name}   \marg{date attr} \{\meta{review points}\orbar\meta{date}\} \\
+%     \cs{dbNewConditional}  \marg{name}        \marg{attr} \marg{cond spec}  \oarg{filter info}
+%     \cs{dbNewConditional}* \marg{name}        \marg{attr} \marg{cond spec}  \oarg{filter info} \\[2pt]
+%     \cs{dbNewConditional}  \marg{name} \marg{int/fp attr} \marg{expr}       \oarg{filter info}
+%     \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{expr}       \oarg{filter info}
+%     \cs{dbNewConditional}  \marg{name} \marg{str/tl attr} \marg{regex expr} \oarg{filter info}
+%     \cs{dbNewConditional}* \marg{name} \marg{str/tl attr} \marg{regex expr} \oarg{filter info}
+%     \cs{dbNewConditional}  \marg{name}  \marg{clist attr} \marg{val list}   \oarg{filter info}
+%     \cs{dbNewConditional}* \marg{name}  \marg{clist attr} \marg{val list}   \oarg{filter info}
+%     \cs{dbNewConditional}  \marg{name}   \marg{date attr} \marg{date expr}  \oarg{filter info}
+%     \cs{dbNewConditional}* \marg{name}   \marg{date attr} \{\meta{review points}\orbar\meta{date}\} \oarg{filter info}
 %   \end{syntax}
 %
 %   \cs{dbNewConditional} 用来定义名为 \meta{name} 的条件,\meta{attr} 指定条件
 %   所绑定的属性,在 \meta{cond spec} 中可以用 \cs{dbval} 指代属性的值。
+%   \cs{dbNewCond} 是 \cs{dbNewConditional} 的别名。
 % \end{function}
 %
 %   \changes{1.3}{2022-01-10}{Update doc}{truncated division}
@@ -885,31 +1399,156 @@
 %   \end{note}
 %
 %   对于类型为 |str| 和 |tl| 的属性,\meta{regex} 为正则表达式,
-%   \cs{dbNewConditional} 表示部分匹配,\cs{dbNewConditional*} 表示整体匹配。
+%   \cs{dbNewConditional} 表示部分匹配,\cs{dbNewConditional*} 表示整体匹配。该
+%   选项依赖于 \pkg{l3regex}。示例 \ref{cn-filter-str} 演示了部分匹配和全部匹
+%   配的区别,|part| 过滤器匹配所有含数字的 |name|,而 |all| 过滤器匹配全部为
+%   数字的 |name|。
 %
-% \begin{verbatim}
-%   \dbNewConditional {cond1}{str-attr}{abc} % 匹配 abc, abcd, 1abc, =abc= 等
-%   \dbNewConditional*{cond2}{str-attr}{abc} % 只匹配 abc
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(filter-str){匹配字符串}
+  \dbNewDatabase{filter-db}{name=str}
+  \begin{dbFilters}*{filter-db}
+    \dbNewCond{part}{name}{\d+}
+    \dbNewCond*{all}{name}{\d+}
+  \end{dbFilters}
+  \dbNewStyle{part-style}{filter-db}{
+    before-code = Match part:~,
+    item-code   = \dbuse{name}\quad,
+    filter      = part,
+  }
+  \dbNewStyle{all-style}{filter-db}{
+    before-code = Match all:~,
+    item-code   = \dbuse{name}\quad,
+    filter      = all,
+  }
+  \dbitemkv{filter-db}{name=123}
+  \dbitemkv{filter-db}{name=int12}
+  \dbitemkv{filter-db}{name=variable}
+  \dbshow{part-style}{filter-db}
+  \dbshow {all-style}{filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
 %
 %   对于类型为 |clist| 的属性,使用 \cs{dbNewConditional} 定义的条件只要
 %   \meta{val list} 中的任意一个元素在属性值(列表)中则条件成立;使用
 %   \cs{dbNewConditional*} 定义的条件只有 \meta{val list} 中每一个值都在属性值
-%   (列表)中条件才成立。
+%   (列表)中条件才成立。示例 \ref{cn-filter-clist} 中过滤器 |or| 匹配含有
+%   hard \textbf{或者} red 的标签,而过滤器 |and| 匹配含有 hard \textbf{并且}
+%   含有 red 的标签。
 %
-% \begin{verbatim}
-%   \dbNewConditional {cond1}{clist-attr}{a, b, c} % a, b, d 满足条件
-%   \dbNewConditional*{cond2}{clist-attr}{a, b, c} % a, b, d 不满足条件
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(filter-clist){筛选列表}
+  \dbNewDatabase{filter-db}{label=clist}
+  \begin{dbFilters}*{filter-db}
+    \dbNewCond  {or}{label}{hard, red}
+    \dbNewCond*{and}{label}{hard, red}
+  \end{dbFilters}
+  \def\emph#1{\textit{\textbf{#1}}}
+  \dbNewStyle{base-style}{filter-db}{
+    before-code = {
+      \begin{minipage}[t]{.3\textwidth}
+        All items
+    },
+    after-code  = {\end{minipage}},
+    item-code   = \par\dbarabic.~\dbuse{label},
+  }
+  \dbNewStyle[base-style] {or-style}{filter-db}{
+    before-code = {
+      \begin{minipage}[t]{.3\textwidth}
+        Match \emph{any} of hard \emph{or} red
+    },
+    filter      = or,
+  }
+  \dbNewStyle[base-style]{and-style}{filter-db}{
+    before-code = {
+      \begin{minipage}[t]{.3\textwidth}
+        Match \emph{all} of hard \emph{and} red
+    },
+    filter      = and,
+  }
+  \dbitemkv{filter-db}{label={hard, red}}
+  \dbitemkv{filter-db}{label={hard, blue}}
+  \dbitemkv{filter-db}{label={easy, blue}}
+  \dbitemkv{filter-db}{label={easy, red}}
+  \dbitemkv{filter-db}{label={hard, red, flat}}
+  \dbshow {base-style}{filter-db}
+  \dbshow   {or-style}{filter-db}
+  \dbshow  {and-style}{filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
 %
 %   \changes{1.3}{2022-01-08}{Update logic}{swap definition of starred and
 %   unstarred conditionals of date}
 %   对于类型为 |date| 的属性,\cs{dbNewConditional} 定义的条件后续处理中会将
-%   \meta{expr} 中的所有日期转换成相对\textit{1971年1月1日}的一个整数值,然后将
-%   处理后的表达式传递给 \cs{int_compare:nTF} 做进一步处理;
-%   \cs{dbNewConditional*} 使用复习点来定义过滤条件,\meta{review points} 是
-%   \cs{dbNewReviewPoints} 定义的复习点,\meta{date} 是用来比较的日期。
+%   \meta{expr} 中的所有日期转换成相对1971年1月1日的一个整数值,然后将处理后的
+%   表达式传递给 \cs{int_compare:nTF} 做进一步处理。示例 \ref{cn-filter-date}
+%   展示了如何使用该选项。
 %
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(filter-date){根据日期表达式过滤}
+  \dbNewDatabase{filter-db}{date=date}
+  \dbNewRawFilter{date-filter}{filter-db}{date}{\dbval >= 2022/02/01}
+  \dbNewStyle{filter-style}{filter-db}{
+    item-code = \dbuse{date}\quad,
+    filter    = date-filter,
+  }
+  \dbitemkv{filter-db}{date=2022/01/30}
+  \dbitemkv{filter-db}{date=2022/02/01}
+  \dbitemkv{filter-db}{date=2022/02/04}
+  \dbshow{filter-style}{filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
+%   对于类型为 |date| 的属性,\cs{dbNewConditional*} 使用复习点来定义过滤条件,
+%   \meta{review points} 是 \cs{dbNewReviewPoints} 定义的复习点,\meta{date}
+%   是用来比较的日期(见示例 \ref{cn-review-points})。
+%
+% \changes{1.5}{2022-01-16}{Add macro}{\cs{dbNewRawFilter}}
+% \begin{function}[added=2022-01-16]{\dbNewRawFilter}
+%   \begin{syntax}
+%     \cs{dbNewRawFilter}  \marg{name} \marg{database} \marg{attr} \marg{cond spec} \oarg{filter info}
+%     \cs{dbNewRawFilter}* \marg{name} \marg{database} \marg{attr} \marg{cond spec} \oarg{filter info}
+%     等同于
+%     |\begin|\{\env{dbFilters}\}*\phantom{\marg{name}}\marg{database}
+%     ~~\cs{dbNewCond}     \marg{name} \phantom{\marg{database}} \marg{attr} \marg{cond spec} \oarg{filter info}
+%     ~~\cs{dbNewCond}*    \marg{name} \phantom{\marg{database}} \marg{attr} \marg{cond spec} \oarg{filter info}
+%     |\end|\{\env{dbFilters}\}
+%   \end{syntax}
+%
+%   该命令用来快捷地定义单个过滤器。示例 \ref{cn-new-raw-filter} 展示了如何使
+%   用该命令,它和示例 \ref{cn-star-filter} 本质上是相同的。
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(new-raw-filter){定义与条件同名的过滤器}
+  \dbNewDatabase{filter-db}{count=int}
+  \dbNewRawFilter{greater}{filter-db}{count}{\dbval > 3}
+  \dbNewStyle{filter-style}{filter-db}{
+    filter    = greater,
+    item-code = \dbuse{count}\quad,
+  }
+  \dbitemkv{filter-db}{count=2}
+  \dbitemkv{filter-db}{count=5}
+  \dbshow{filter-style}{filter-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
 % \begin{function}[added=2022-01-05]{\dbCombineConditionals}
 %   \begin{syntax}
 %     \cs{dbCombineConditionals} \marg{name} \marg{cond combination} \oarg{info}
@@ -916,37 +1555,60 @@
 %   \end{syntax}
 %
 %   \cs{dbCombineConditionals} 定义名为 \marg{name} 的过滤器,并将
-%   \cs{dbNewConditional} 定义的条件组合起来,比如
-%   \verb=\dbCombineConditionals{filter}{(cond1 && cond2) || !cond3}=。
-%   \meta{cond combination} 中可以使用的关系操作符为 \verb=&&, ||, !=。
-%   可以将 \opt{filter} 选项设置为 \meta{name} 来应用过滤器。\meta{info} 为过滤
-%   器的相关信息,在展示数据库的时候可以用 \cs{dbFilterInfo} 指代。
+%   \cs{dbNewConditional} 定义的条件组合起来。\meta{cond combination} 中可以使
+%   用的关系操作符为 \verb=&&, ||, !=。可以将 \opt{filter} 选项设置为
+%   \meta{name} 来应用过滤器。\meta{info} 为过滤器的相关信息,在展示数据库的时
+%   候可以用 \cs{dbFilterInfo} 指代。使用示例见示例 \ref{cn-filter}.
 % \end{function}
 %
-% \subsection{使用 \env{dbitem} 环境存储数据}
+% \subsection{存储和使用数据}
 %
 % \changes{1.4}{2022-01-13}{Update env}{dbitem}
 % \begin{environment}[added=2022-01-05, updated=2022-01-13]{dbitem}
 %   \begin{syntax}
-%     |\begin{dbitem}| \marg{database} \oarg{attr-val list}
+%     |\begin|\marg{\env{dbitem}} \marg{database} \oarg{attr-val list}
 %     ~~\meta{code} \\
-%     |\end{dbitem}|
+%     |\end|\marg{\env{dbitem}}
 %   \end{syntax}
 %
 %   \env{dbitem} 环境用来存储数据。有两种存储数据的方法,较短的数据可以在选项列
 %   表中通过键值对设置值,较长的数据可以在 \meta{code} 中使用 \cs{dbsave} 存储。
 %   \meta{attr} = \meta{val} 等同于 \cs{dbsave}\marg{attr}\marg{val},
-%   \meta{attr}* = \meta{val} 等同于 \cs{dbsave*}\marg{attr}\marg{val},数据在
-%   |e| 或者 |x| 类型的参数中不可展开。\cs{dbsave}会覆盖选项中设置的值。没有设
-%   置的值将会被设置为全局默认值,下面给出一个存储示例。
+%   \meta{attr}\texttt{*} = \meta{val} 等同于 \cs{dbsave*}\marg{attr}
+%   \marg{val},数据在 |e| 或者 |x| 类型的参数中不可展开。\cs{dbsave}会覆盖选
+%   项中设置的值。没有设置的值将会被设置为全局默认值。示例 \ref{cn-dbitem} 展
+%   示了如何存储数据。
 % \end{environment}
 %
-% \begin{verbatim}
-%   \begin{dbitem}[date = 2022-01-01, info = 测试]
-%     \dbsave{question}{这是一个测试问题}
-%     \dbsave{answer}  {这是一个测试答案}
-%   \end{dbitem}
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example}(dbitem){存储数据}
+  \dbNewDatabase{ques-db}{date=date, ques=tl, ans=tl}
+  \dbNewStyle{ques-style}{ques-db}{
+    item-code       = {%
+      \par\dbuse{date}
+      \par\dbarabic.~\dbuse{ques}
+      \par\textbf{答案:}~\dbuse{ans}
+    },
+    item-after-code = \medskip,
+    date/code*      = \zhdate{#1},
+  }
+  \begin{dbitem}{ques-db}[date=2022/01/01]
+    \dbsave{ques}{地球到月亮的距离}
+    \dbsave{ans} {384,401公里}
+  \end{dbitem}
+  \begin{dbitem}{ques-db}[date=2022/01/02]
+    \dbsave{ques}{鲁迅的本名}
+    \dbsave{ans} {周树人}
+  \end{dbitem}
+  \dbshow{ques-style}{ques-db}
+\end{example}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
 %
 % \changes{1.4}{2022-01-13}{Add macro}{\cs{dbitemkv}}
 % \begin{function}[added=2022-01-13]{\dbitemkv}
@@ -957,8 +1619,6 @@
 %   只使用 \meta{attr-val list} 来存储数据。
 % \end{function}
 %
-% \subsection{\cs{dbsave} 和 \cs{dbuse}}
-%
 % \changes{1.3}{2022-01-08}{Add macro}{\cs{dbsave*}}
 % \begin{function}[added=2022-01-05, updated=2022-01-08]{\dbsave, \dbsave*}
 %   \begin{syntax}
@@ -976,8 +1636,8 @@
 %     \cs{dbuse} \marg{attr}
 %   \end{syntax}
 %
-%   \cs{dbuse} 用来展示数据,只能在 \opt{item-code} 选项中使用。\cs{dbuse} 是可
-%   展开的。
+%   \cs{dbuse} 用来展示数据,只能在 \opt{item-code}, \opt{item-before-code},
+%   \opt{item-after-code} 选项中使用。\cs{dbuse} 是可展开的。
 % \end{function}
 %
 % \subsection{条件判别式}
@@ -985,21 +1645,70 @@
 % \begin{function}[added=2022-01-05, EXP]{\dbIfEmptyT, \dbIfEmptyF, \dbIfEmptyTF}
 %   \begin{syntax}
 %     \cs{dbIfEmptyTF} \marg{true code} \marg{false code} \\
-%     \cs{dbIfEmptyT} \marg{true code} \\
+%     \cs{dbIfEmptyT}  \marg{true code} \\
 %     \cs{dbIfEmptyF} \marg{false code}
 %   \end{syntax}
 %
-%   该判别式用来判断当前数据库是否为空。下面的示例展示了如何预防空的列表环境。
+%   该判别式用来判断当前数据库是否为空。示例 \ref{cn-empty-db} 演示了如何使用
+%   该判别式来预防空的列表环境。
 % \end{function}
 %
-% \begin{verbatim}
-%   \dbNewStyle{style-cond1}{database-test}{
-%     before-code = {\dbIfEmptyF{\begin{enumerate}}},
-%     after-code = {\dbIfEmptyF{\end{enumerate}}},
-%     item-code = {\item \dbuse{attr-test}}
-%   }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(empty-db){预防空列表环境}
+  \dbNewDatabase{test-db}{text=tl}
+  \dbNewRawFilter{alph}{test-db}{text}{\d}
+  \dbNewStyle{base-style}{test-db}{
+    before-code = \dbIfEmptyTF{Empty db}{\begin{enumerate}},
+    after-code  = \dbIfEmptyF{\end{enumerate}}\medskip,
+    item-code   = \item \dbuse{text},
+  }
+  \dbNewStyle[base-style]{empty-style}{test-db}{
+    raw-filter=!alph
+  }
+  \dbitemkv{test-db}{text={$1 + 1 = 2$.}}
+  \dbitemkv{test-db}{text={I have 2 pens.}}
+  \dbshow {base-style}{test-db}
+  \dbshow{empty-style}{test-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
 %
+% \changes{1.5}{2022-01-17}{Add macros}{\cs{dbIfLastT}, \cs{dbIfLastF},
+% \cs{dbIfLastTF}}
+% \begin{function}[added=2022-01-17, EXP]{\dbIfLastT, \dbIfLastF, \dbIfLastTF}
+%   \begin{syntax}
+%     \cs{dbIfLastTF} \marg{true code} \marg{false code}
+%     \cs{dbIfLastT}  \marg{true code}
+%     \cs{dbIfLastF} \marg{false code}
+%   \end{syntax}
+%
+%   该判别式用来判断当前是否为数据库要展示的最后一条数据。示例
+%   \ref{cn-last} 演示了如何设置条目之间的间隔。
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(last){设置条目之间的间隔}
+  \dbNewDatabase{last-db}{text=tl}
+  \dbNewStyle{last-style}{last-db}{
+    item-code  = {%
+      \par\dbuse{text}\par%
+      \dbIfLastF{\textcolor{red}{\hrulefill separator\hrulefill}}%
+    },
+  }
+  \dbitemkv{last-db}{text=This is the first paragraph.}
+  \dbitemkv{last-db}{text=This is the second paragraph.}
+  \dbitemkv{last-db}{text=This is the last paragraph.}
+  \dbshow{last-style}{last-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
 % \changes{1.2}{2022-01-08}{Remove macros}{\cs{dbItemIfEmpty(TF)}, \cs{dbClistItemIfEmpty(TF)}}
 %
 % \subsection{表达式函数}
@@ -1010,26 +1719,49 @@
 %   \dbIntMin, \dbIntMod, \dbFpSign,
 % }
 %   \begin{syntax}
-%     \cs{dbIntAbs} \Arg{intexpr}
-%     \cs{dbIntSign} \Arg{intexpr}
-%     \cs{dbIntDivRound} \Arg{intexpr_1} \marg{intexpr_2}
-%     \cs{dbIntDivTruncate} \Arg{intexpr_1} \marg{intexpr_2}
-%     \cs{dbIntMax} \Arg{intexpr_1} \marg{intexpr_2}
-%     \cs{dbIntMin} \Arg{intexpr_1} \marg{intexpr_2}
-%     \cs{dbIntMod} \Arg{intexpr_1} \marg{intexpr_2}
-%     \cs{dbFpSign} \Arg{fpexpr}
+%     \cs{dbIntAbs}         \Arg{intexpr}
+%     \cs{dbIntSign}        \Arg{intexpr}
+%     \cs{dbIntDivRound}    \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{dbIntDivTruncate} \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{dbIntMax}         \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{dbIntMin}         \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{dbIntMod}         \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{dbFpSign}         \Arg{fpexpr}
 %   \end{syntax}
-%   \cs{dbIntAbs} 等同于 \cs{int_abs:n} \\
-%   \cs{dbIntSign} 等同于 \cs{int_sign:n} \\
-%   \cs{dbIntDivRound} 等同于 \cs{int_div_round:nn} \\
-%   \cs{dbIntDivTruncate} 等同于 \cs{int_div_truncate:nn} \\
-%   \cs{dbIntMax} 等同于 \cs{int_max:nn} \\
-%   \cs{dbIntMin} 等同于 \cs{int_min:nn} \\
-%   \cs{dbIntMod} 等同于 \cs{int_mod:nn} \\
-%   \cs{dbFpSign} 等同于 \cs{fp_sign:n} \\
-%    详细的文档见 \pkg{interface3} \\
+% \begin{tblr}{ll}
+%   \cs{dbIntAbs}         & 等同于 \cs{int_abs:n} \\
+%   \cs{dbIntSign}        & 等同于 \cs{int_sign:n} \\
+%   \cs{dbIntDivRound}    & 等同于 \cs{int_div_round:nn} \\
+%   \cs{dbIntDivTruncate} & 等同于 \cs{int_div_truncate:nn} \\
+%   \cs{dbIntMax}         & 等同于 \cs{int_max:nn} \\
+%   \cs{dbIntMin}         & 等同于 \cs{int_min:nn} \\
+%   \cs{dbIntMod}         & 等同于 \cs{int_mod:nn} \\
+%   \cs{dbFpSign}         & 等同于 \cs{fp_sign:n} \\
+% \end{tblr}
+%
+%   详细的文档见 \pkg{interface3}。示例 \ref{cn-expr-db} 展示了如何筛选3的倍数。
 % \end{function}
 %
+% \iffalse
+%<*verb>
+% \fi
+\begin{example}(expr-db){筛选3的倍数}
+  \dbNewDatabase{expr-db}{n=int}
+  \dbNewRawFilter{mod}{expr-db}{n}{\dbIntMod{\dbval}{3} = 0}
+  \dbNewStyle{expr-style}{expr-db}{
+    item-code = \dbuse{n}\quad,
+    filter    = mod,
+  }
+  \dbitemkv{expr-db}{n=2}
+  \dbitemkv{expr-db}{n=3}
+  \dbitemkv{expr-db}{n=6}
+  \dbitemkv{expr-db}{n=7}
+  \dbshow{expr-style}{expr-db}
+\end{example}
+% \iffalse
+%</verb>
+% \fi
+%
 % \subsection{特殊命令}
 %
 % \pkg{dbshow} 定义了一些特殊的命令,会根据语境展开为不同的内容。
@@ -1040,27 +1772,64 @@
 % }
 % \changes{1.1}{2022-01-06}{Fix bug}{\cs{dbIndex} not defined}
 % \begin{function}[added=2022-01-05, EXP]{
-%   \dbval, \dbDatabase, \dbFilterName, \dbFilterInfo,
+%   \dbval, \dbtoday, \dbDatabase, \dbFilterName, \dbFilterInfo,
 %   \dbIndex, \dbarabic, \dbalph, \dbAlph, \dbroman, \dbRoman
 % }
 % \begin{tblr}{ll}
-%   \cs{dbval} & 当前属性的值 \\
-%   \cs{dbDatabase} & 数据库名称 \\
+%   \cs{dbval}        & 当前属性的值 \\
+%   \cs{dbtoday}      & 当天的日期 \\
+%   \cs{dbDatabase}   & 数据库名称 \\
 %   \cs{dbFilterName} & 当前样式过滤器的名称 \\
 %   \cs{dbFilterInfo} & 当前样式过滤器的相关信息 \\
-%   \cs{dbIndex} & 数据索引,等同于 \cs{dbuse}|{id}| \\
-%   \cs{dbarabic} & 用数字表示的查询集数据计数 \\
-%   \cs{dbalph} & 用小写字母表示的查询集数据计数 \\
-%   \cs{dbAlph} & 用大写字母表示的查询集数据计数 \\
-%   \cs{dbroman} & 用小写罗马字母表示的查询集数据计数 \\
-%   \cs{dbroman} & 用大写罗马字母表示的查询集数据计数 \\
-%   \end{tblr}
+%   \cs{dbIndex}      & 数据索引,等同于 \cs{dbuse}\marg{id} \\
+%   \cs{dbarabic}     & 用数字表示的查询集数据计数 \\
+%   \cs{dbalph}       & 用小写字母表示的查询集数据计数 \\
+%   \cs{dbAlph}       & 用大写字母表示的查询集数据计数 \\
+%   \cs{dbroman}      & 用小写罗马字母表示的查询集数据计数 \\
+%   \cs{dbroman}      & 用大写罗马字母表示的查询集数据计数 \\
+% \end{tblr}
+%
+%   \cs{dbtoday} 使用 \cs{dbdatesep} 确定的分隔符来展示日期。见示例
+%   \ref{cn-spespecial-cs}.
 % \end{function}
 %
-% \section{错题本示例}
-% 见第 \ref{sec:example} 节。
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example}(special-cs){特殊命令}
+  \dbNewDatabase{special-db}{name=str}
+  \dbNewRawFilter*{number}{special-db}{name}{\d+}[name that is a number]
+  \dbNewStyle{special-style}{special-db}{
+    before-code = {
+      Date: \dbtoday \\
+      Database: \dbDatabase
+      Filter: \dbFilterName \\
+      Filter info: \dbFilterInfo \par
+      \begin{tabular}{@{}lllllll}
+        Index & arabic & alph & Alph & roman & Roman & value \\
+    },
+    after-code  = \end{tabular},
+    item-code*  = {%
+      \dbIndex & \dbarabic & \dbalph & \dbAlph &
+      \dbroman & \dbRoman & \dbuse{name} \\
+    },
+    sort        = name,
+    filter      = number,
+  }
+  \dbitemkv{special-db}{name=test}
+  \dbitemkv{special-db}{name=12}
+  \dbitemkv{special-db}{name=int2}
+  \dbitemkv{special-db}{name=99}
+  \dbshow{special-style}{special-db}
+\end{example}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
 %
 % \changes{1.1}{2022-01-07}{Update doc}{improve example}
+% \changes{1.5}{2022-01-17}{Remove doc}{Remove big example}
 %
 % \title{
 %   Package \pkg{dbshow} \fileversion%
@@ -1085,7 +1854,7 @@
 % certain times or questions having not been reviewed for certain days. So this
 % package provides a database to do such thing.
 %
-% The package provides four core functions: data storage and display, data
+% The package provides four core functions: data storage, data
 % filtering, data sorting and data display. All data is saved once and then you
 % can display these data with custom filters, orders and styles.
 %
@@ -1129,24 +1898,9 @@
 % by \pkg{dbshow} itself and supports converting to integer and printing with
 % style.
 %
-% \subsection{Comparison to \pkg{datatool}}
-%
 % \changes{1.2}{2022-01-07}{Add doc}{add comparison to \pkg{datatool}}
+% \changes{1.3}{2022-01-07}{Remove doc}{remove comparison to \pkg{datatool}}
 %
-% \pkg{dbshow} and \pkg{datatool} implement the same core functions. But
-% \pkg{dbshow} is based on \pkg{expl3} and it supports string regex and
-% multi-level sorting. \pkg{dbshow} tries to divide style from the contents
-% (data in database): all styles are predefined and can be reused conveniently
-% so that there can be only codes to save data and one-line code to show the
-% database inside the \env{document} environment. You can hide the details in
-% the preamble and focus on the data you want to display. \pkg{dbshow} provides
-% a simple temporary runtime database, which means it can not input and output
-% data from/to extern files (they should be responsible by some professional
-% programming languages). When you need to delete or revise a record, just go to
-% where it is recorded in the source code rather than use a macro to manipulate
-% data after they are saved. In a sense, \TeX~file is also a kind of data
-% persistence.
-%
 % \section{Interfaces}
 %
 % \subsection{Create, Display and Clear Database}
@@ -1186,17 +1940,6 @@
 %   Every database has a default attribute |id| to store the index of the item.
 % \end{note}
 %
-% The example below define a database named |ques|.
-% \begin{verbatim}
-%   \dbNewDatabase{ques}{
-%     question = tl, % store question
-%     answer = tl,   % store corresponding answer
-%     date = date,   % store the date when you were wrong
-%     info = tl,     % store extra info
-%     labels = clist % store question labels
-%   }
-% \end{verbatim}
-%
 % \begin{function}[added=2022-01-05]{\dbshow}
 %   \begin{syntax}
 %     \cs{dbshow} \marg{style} \marg{database}
@@ -1216,7 +1959,7 @@
 %
 % \subsection{\cs{dbNewStyle} and Style Options}
 %
-% \begin{function}[added=2022-01-05]{\dbNewStyle}
+% \begin{function}[added=2022-01-05, updated=2022-01-15]{\dbNewStyle}
 %   \begin{syntax}
 %     \cs{dbNewStyle} \oarg{base styles} \marg{style} \marg{database} \marg{opts}
 %   \end{syntax}
@@ -1230,253 +1973,412 @@
 %
 % \begin{option}[added=2022-01-05]{filter}
 %   \begin{syntax}
-%     filter = <filter>
+%     \opt{filter} = <filter> \inidef(-none-)
 %   \end{syntax}
 %
-%   Set the \meta{filter} defined by \cs{dbCombineFilters}.
+%   Set the \meta{filter} defined by \cs{dbCombineFilters}. Example
+%   \ref{en-filter} shows how to define conditionals and combine them into
+%   a filter.
 % \end{option}
 %
+% \DeleteShortVerb{\|}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(filter){Filter Items}
+  \dbNewDatabase{filter-db}{name=str, count=int}
+  \begin{dbFilters}{filter-db}
+    \dbNewCond {cond1}{count}{\dbval > 3}
+    \dbNewCond*{cond2}{name} {\d+}
+    \dbCombCond{filter-and}{cond1 && cond2}
+    \dbCombCond{filter-or} {cond1 || cond2}
+  \end{dbFilters}
+  \dbitemkv{filter-db}{name=123, count=4}
+  \dbitemkv{filter-db}{name=ab3, count=2}
+  \dbitemkv{filter-db}{name=bag, count=5}
+  \dbNewStyle{filter-and-style}{filter-db}{
+    filter      = filter-and,
+    before-code = \par Filter And\par,
+    item-code   = {\dbuse{name}: \dbuse{count}\quad},
+  }
+  \dbNewStyle{filter-or-style}{filter-db}{
+    filter      = filter-or,
+    before-code = \par Filter Or\par,
+    item-code   = {\dbuse{name}: \dbuse{count}\quad},
+  }
+  \dbshow{filter-and-style}{filter-db}
+  \dbshow{filter-or-style} {filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+% \MakeShortVerb{\|}
+%
 % \changes{1.1}{2022-01-06}{Add option}{\opt{raw-filter}}
 % \begin{option}[added=2022-01-06]{raw-filter}
 %   \begin{syntax}
-%     raw-filter = <conditional expression>
+%     \opt{raw-filter} = <conditional expression> \inidef
 %   \end{syntax}
 %
-%   Set anonymous with conditionals defined by \cs{dbNewConditional}. Two
-%   filters shows in the code below have the same meaning.
+%   Set anonymous filter with conditionals defined by \cs{dbNewConditional}.
+%   Example \ref{en-raw-filter} shows how to simplify the code of example
+%   \ref{en-filter} with \opt{raw-filter} option.
 % \end{option}
 %
-% \begin{verbatim}
-%   % method 1
-%   \begin{dbFilters}{db}
-%     \dbNewConditional{cond1}{int-attr}{\rval > 1}
-%     \dbNewConditional*{cond2}{str-attr}{\d+}
-%   \end{dbFilters}
-%   \dbNewStyle{style}{db}{raw-filter={cond1 && cond2}}
-%   % method 2
-%   \begin{dbFilters}{db}
-%     \dbNewConditional{cond1}{int-attr}{\rval > 1}
-%     \dbNewConditional*{cond2}{str-attr}{\d+}
-%     \dbCombineFilters{filter}{cond1 && cond2}
-%   \end{dbFilters}
-%   \dbNewStyle{style}{db}{filter=filter}
-% \end{verbatim}
+% \DeleteShortVerb{\|}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(raw-filter){Using Anonymous Filter}
+  \dbNewDatabase{filter-db}{name=str, count=int}
+  \begin{dbFilters}{filter-db}
+    \dbNewCond {cond1}{count}{\dbval > 3}
+    \dbNewCond*{cond2}{name} {\d+}
+  \end{dbFilters}
+  \dbitemkv{filter-db}{name=123, count=4}
+  \dbitemkv{filter-db}{name=ab3, count=2}
+  \dbitemkv{filter-db}{name=bag, count=5}
+  \dbNewStyle{filter-and-style}{filter-db}{
+    raw-filter  = {cond1 && cond2},
+    before-code = \par Filter And\par,
+    item-code   = {\dbuse{name}: \dbuse{count}\quad},
+  }
+  \dbNewStyle{filter-or-style}{filter-db}{
+    raw-filter  = {cond1 || cond2},
+    before-code = \par Filter Or\par,
+    item-code   = {\dbuse{name}: \dbuse{count}\quad},
+  }
+  \dbshow{filter-and-style}{filter-db}
+  \dbshow{filter-or-style} {filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+% \MakeShortVerb{\|}
 %
 % \changes{1.2}{2022-01-08}{Fix bug}{string sorting bug}
 % \begin{option}[added=2022-01-05]{sort}
 %   \begin{syntax}
-%     sort = \{ <attr spec1>, <attr spec2>, \ldots{} \}
+%     \opt{sort} = \{ <attr spec1>, <attr spec2>, \ldots{} \} \inidef
 %   \end{syntax}
 %
 %   Set sorting rules. Attributes of type |str, date, int, fp| is supported to
-%   sort.  Multi-level sort is allowed. \meta{attr} represents for ascending
-%   order, and \meta{attr}* represents for descending order. The example below
-%   use four fields to determine the order of the records. It sorts on |level|
-%   in descending order first and if two |levels| are same then sorts on |birth|
-%   in ascending order and so on.
+%   sort. Multi-level sort is allowed. \meta{attr} represents for ascending
+%   order, and \meta{attr}\texttt{*} represents for descending order. Example
+%   \ref{en-sort} shows how to sort items by |count| in descending order and
+%   for the same |count|, sort by |name| in ascending order.
 % \end{option}
 %
-% \begin{verbatim}
-%   \dbNewDatabase{sort-example}{
-%     name = str,
-%     birth = date,
-%     level = int,
-%     weight = fp,
-%   }
-%   \dbNewStyle{sort-style}{sort-example}{
-%     sort = { level*, birth, name, weight }
-%   }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(sort){Multi-level Sorting}
+  \dbNewDatabase{sort-db}{name=str, count=int}
+  \dbNewStyle{sort-style}{sort-db}{
+    sort = {count*, name},
+    item-code = {\dbuse{name}: \dbuse{count}\quad}
+  }
+  \dbitemkv{sort-db}{name=bag, count=1}
+  \dbitemkv{sort-db}{name=box, count=1}
+  \dbitemkv{sort-db}{name=tag, count=2}
+  \dbitemkv{sort-db}{name=pen, count=3}
+  \dbshow{sort-style}{sort-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
 %
-% \begin{option}[added=2022-01-05, rEXP]{item-code}
+% \begin{option}[added=2022-01-05, rEXP]{before-code}
 %   \begin{syntax}
-%     item-code = <code>
+%     \opt{before-code} = <before code> \inidef*
 %   \end{syntax}
 %
-%   Set the code that show a single record. You can use \cs{dbuse} to display
-%   certian attribute.
+%   Set the \meta{code} that is executed \enbefore displaying the database.
+%   See Example \ref{en-db-wrap}.
 % \end{option}
 %
-% \changes{1.3}{2022-01-09}{Update option}{\opt{<attr>/sep}}
-% \begin{option}[added=2022-01-05, updated=2022-01-08, rEXP]{<attr>/sep}
+% \begin{option}[added=2022-01-05, rEXP]{after-code}
 %   \begin{syntax}
-%     <attr>/sep = <separator> \\
-%     <attr>/sep = \{ \\
-%     ~~\meta{separator between two}, \\
-%     ~~\meta{separator between more than two}, \\
-%     ~~\meta{separator between final two} \\
-%     \} \\
-%     <attr>/sep = \{ \\
-%     ~~\meta{separator before year}, \\
-%     ~~\meta{separator between year and month}, \\
-%     ~~\meta{separator between month and day}, \\
-%     ~~\meta{separator after day} \\
-%     \} \\
+%     \opt{after-code} = <after code> \inidef*
 %   \end{syntax}
 %
-%   Only for attributes of type |clist| or |date|. Set the separator between
-%   items. If the argument is an one-item comma list, all separators are set to
-%   \meta{separator} but \meta{separator before year} and \meta{separator after
-%   day} is set empty.
+%   Set the \meta{code} that is executed \enafter displaying the database.
+%   See Example \ref{en-db-wrap}.
 % \end{option}
 %
-%   If the argument is a comma list of 3 items, it is used to set the separator
-%   between items of the comma list. Following documentation is quoted from
-%   \pkg{interface3}:
-%   \begin{quote}
-%     If the comma list has more than two items, the \meta{separator between
-%     more than two} is placed between each pair of items except the last, for
-%     which the \meta{separator between final two} is used. If the comma list
-%     has exactly two items, then they are placed in the input stream separated
-%     by the \meta{separator between two}. If the comma list has a single item,
-%     it is placed in the input stream, and a comma list with no items produces
-%     no output.
-%   \end{quote}
-%   For attributes of type |clist|, incorrect number (numbers exclude 1 and 3)
-%   of items of the argument will raise an error.
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(db-wrap){Set the Before and After Code of the Database}
+  \dbNewDatabase{wrap-db}{text=tl}
+  \dbNewStyle{wrap-style}{wrap-db}{
+    before-code = \textit{before code}\quad,
+    after-code  = \textit{after code},
+    item-code   = \dbarabic.~\dbuse{text}\quad
+  }
+  \dbitemkv{wrap-db}{text=text1}
+  \dbitemkv{wrap-db}{text=text2}
+  \dbitemkv{wrap-db}{text=text3}
+  \dbshow{wrap-style}{wrap-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
 %
-% \begin{verbatim}
-%   % clist-attr is an attribute of database db
-%   % suppose the val of clist-attr is { 1, 2, 3 }
-%   \dbNewStyle{clist-sep}{db}{
-%     clist-attr/sep = { ,~ },                % print 1, 2, 3
-%     clist-attr/sep = { {,~}, {,~}, {and~} } % print 1, 2 and 3
-%   }
-% \end{verbatim}
+% \begin{option}[added=2022-01-05, rEXP]{item-code}
+%   \begin{syntax}
+%     \opt{item-code} = <item code> \inidef
+%   \end{syntax}
 %
-%   If the argument is a comma list of 4 items, it is used to set the separators
-%   of the date. For attributes of type |date|, incorrect number (numbers
-%   exclude 1 and 4) will raise an error.
+%   Set the code that display a record. You can use \cs{dbuse} to denote the
+%   value of attribute. Example \ref{en-item-code} shows how to display an
+%   acronym glossary table.
+% \end{option}
 %
-% \begin{verbatim}
-%   % date-attr is an attribute of database db
-%   % suppose the val of date-attr is 2022/01/01
-%   \dbNewStyle{date-sep}{db}{
-%     date-attr/sep = -,             % print 2022-01-01
-%     date-attr/sep = { |, -, -, | } % print |2022-01-01|
-%   }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(item-code){Display Database Items}
+  \dbNewDatabase{item-db}{acronym=str, desc=tl}
+  \dbNewStyle{item-style}{item-db}{
+    before-code = {\dbIfEmptyF{\begin{description}}},
+    after-code  = {\dbIfEmptyF{\end{description}}},
+    item-code   = {\item[\dbuse{acronym}] \dbuse{desc}},
+    sort        = acronym,
+  }
+  \dbitemkv{item-db}{acronym=PM,  desc={Prime Minister}}
+  \dbitemkv{item-db}{acronym=CBD, desc={Central Business District}}
+  \dbitemkv{item-db}{acronym=DL,  desc={Deep Learning}}
+  \dbshow{item-style}{item-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
 %
-% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/zfill}}
-% \begin{option}[added=2022-01-08, EXP]{<attr>/zfill}
+% \changes{1.5}{2022-01-17}{Add option}{\opt{item-code*}}
+% \begin{option}[added=2022-01-17, rEXP]{item-code*}
 %   \begin{syntax}
-%     <attr>/zfill = <\TTF>
+%     \opt{item-code*} = <item code> \inidef
 %   \end{syntax}
 %
-%   Only for attributes of type |date|. Control whether to fill zero on the left
-%   of the month or day.
+%   The \meta{item code} will be expanded through \cs{protected at edef} before
+%   it is used. \ref{en-item-exp} shows how to display data with table using
+%   the expanded code.
 % \end{option}
 %
-% \changes{1.4}{2022-01-13}{Add macro}{\cs{dbdatesep}}
-% \begin{function}[added=2022-01-13, EXP]{\dbdatesep}
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example*}(item-exp){Display Data with Table}
+  \dbNewDatabase{tab-db}{name=str, count=int}
+  \dbNewStyle{tab-style}{tab-db}{
+    before-code = {%
+      \begin{tabular}{ll}
+        name & count \\
+    },
+    after-code  = \end{tabular},
+    item-code*  = {%
+      \textcolor{red}{\dbuse{name}} & \dbuse{count} \\
+    },
+  }
+  \dbitemkv{tab-db}{name=bag, count=100}
+  \dbitemkv{tab-db}{name=pig, count=20}
+  \dbshow{tab-style}{tab-db}
+\end{example*}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.2}{2022-01-08}{Add options}{\opt{record-before-code},
+% \opt{record-after-code}}
+% \changes{1.5}{2022-01-14}{Update options}{Rename \opt{record-before-code}
+% and \opt{record-after-code} to \opt{item-before-code} and
+% \opt{item-after-code}}
+% \begin{option}[added=2022-01-08, updated=2022-01-14, rEXP]{item-before-code}
 %   \begin{syntax}
-%     \cs{dbdatesep} \marg{separator}
+%     \opt{item-before-code} = <before code> \inidef*
 %   \end{syntax}
 %
-%   Set the separator for internal date parsing. The default value is |/|,
-%   i.e. the date must be store in the format of |yyyy/mm/dd|.
-% \end{function}
+%   Set the \meta{code} that is executed \enbefore displaying a item. See
+%   Example \ref{en-item-wrapper}.
+% \end{option}
 %
-% \subsubsection{Decorators}
-%
-% The options below serves as decorators. In some cases, decorator can also be
-% encoded directly into |item-code| or some other places, which is convenient
-% sometimes. The benefit of defining decorators with options is that styles step
-% further to be divided with contents. In the examples below, \meta{style1} and
-% \meta{style2} is the same style, which wrap \meta{attr1} with *. When you want
-% another style which wrap \meta{attr1} with =, if you choose the way of
-% \meta{style1}, \meta{item code} are repeated, otherwise if you choose the way
-% of \meta{style2}, \meta{item code} is inherited and you only need define the
-% decorators.
-%
-% \begin{verbatim}
-%   \dbNewStyle{style1}{db}{
-%     item-code = {%
-%       *\rvuse{attr1}*\rvuse{attr2}
-%       % more code
-%     }
-%   }
-%   \dbNewStyle{base-style}{db}{
-%     item-code = {%
-%       \rvuse{attr1}\rvuse{attr2}
-%       % more code
-%     }
-%   }
-%   \dbNewStyle[base-style]{style2}{db}{
-%     attr1/before-code = { * },
-%     attr1/after-code = { * },
-%   }
-%   \dbNewStyle[base-style]{style3}{db}{
-%     attr1/before-code = { = },
-%     attr1/after-code = { = },
-%   }
-% \end{verbatim}
-%
-% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/wrapper}}
-% \begin{option}[added=2022-01-08, rEXP]{<attr>/wrapper}
+% \begin{option}[added=2022-01-08, updated=2022-01-14, rEXP]{item-after-code}
 %   \begin{syntax}
-%     <attr>/wrapper = <control sequence>
+%     \opt{item-after-code} = <after code> \inidef*
 %   \end{syntax}
 %
-%   Only for attributes of type |date|. Output of \cs{dbuse}\marg{date attr}
-%   will be \meta{control sequence}\marg{date}.
+%   Set the \meta{code} that is executed \enafter displaying the item. See
+%   Example \ref{en-item-wrapper}.
 % \end{option}
 %
-% \begin{option}[added=2022-01-05, rEXP]{before-code}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(item-wrapper){Set the Before and After Code of the Item}
+  \dbNewDatabase{item-wrap-db}{text=tl}
+  \dbNewStyle{item-wrap-style}{item-wrap-db}{
+    item-before-code = \begingroup\ttfamily<,
+    item-after-code  = >\endgroup,
+    item-code        = \dbuse{text},
+  }
+  \dbitemkv{item-wrap-db}{text=example}
+  \dbshow{item-wrap-style}{item-wrap-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \subsubsection{Attribute Options}
+%
+% \changes{1.5}{2022-01-14}{Remove option}{\opt{<attr>/wrapper}}
+%
+% \changes{1.5}{2022-01-14}{Add options}{\opt{<attr>/code},
+% \opt{<attr>/code*}}
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/code}
 %   \begin{syntax}
-%     before-code = <code>
+%     \nopt{<attr>/code} = <code> \inidef(\#1)
 %   \end{syntax}
 %
-%   Set the \meta{code} that is executed \enbefore displaying the database.
+%   Set the style code of \meta{attr}. In \meta{code}, |#1| is replaced with the
+%   value of \meta{attr}. Example \ref{en-attr-code} prints |name| whose |count|
+%   is less than 10 in teal color, otherwise in red color.
 % \end{option}
 %
-% \begin{option}[added=2022-01-05, rEXP]{after-code}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(attr-code){Set Style Code of Attribute}
+  \dbNewDatabase{attr-code-db}{name=str, count=int}
+  \begin{dbFilters}{attr-code-db}
+    \dbNewCond{large}{count}{\dbval >= 10}
+  \end{dbFilters}
+  \dbNewStyle{base-style}{attr-code-db}{
+    item-code  = \dbuse{name}:~\dbuse{count}\quad,
+  }
+  \dbNewStyle[base-style]{large-style}{attr-code-db}{
+    raw-filter = large,
+    name/code  = \textcolor{red}{#1},
+  }
+  \dbNewStyle[base-style]{small-style}{attr-code-db}{
+    raw-filter = !large,
+    name/code  = \textcolor{teal}{#1},
+  }
+  \dbitemkv{attr-code-db}{name=bag, count=1}
+  \dbitemkv{attr-code-db}{name=pen, count=12}
+  \dbitemkv{attr-code-db}{name=pig, count=5}
+  \dbitemkv{attr-code-db}{name=egg, count=50}
+  \dbshow{large-style}{attr-code-db}
+  \dbshow{small-style}{attr-code-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/code*}
 %   \begin{syntax}
-%     after-code = <code>
+%     \nopt{<attr>/code*} = <code> \inidef
 %   \end{syntax}
 %
-%   Set the \meta{code} that is executed \enafter displaying the database.
+%   Set the style code of \meta{attr}. In \meta{code}, |#1| is replaced with the
+%   \textbf{expanded} value of \meta{attr}. This is useful to commands that
+%   require special format of the arguments.
 % \end{option}
 %
-% \changes{1.2}{2022-01-08}{Add options}{\opt{record-before-code},
-% \opt{record-after-code}}
-% \begin{option}[added=2022-01-05, rEXP]{record-before-code}
+%   Example \ref{en-exp-code} shows how to print Chinese date with \cs{zhdate}
+%   of package \pkg{zhnumber}. \cs{zhdate} require argument to be the date of
+%   |yyyy/mm/dd|, which is the default date format of \pkg{dbshow}. But we need
+%   to expand the date through \opt{date/code*} first because \cs{zhdate} cannot
+%   parse the token list other than |yyyy/mm/dd|.
+%
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example*}(exp-code){Show Chinese Date}
+  % \usepackage{zhnumber}
+  \dbNewDatabase{exp-db}{date=date, event=tl}
+  \dbNewStyle{exp-style}{exp-db}{
+    item-code  = \par\makebox[4cm][l]{\dbuse{date}}\dbuse{event},
+    date/code* = \zhdate{#1},
+  }
+  \dbitemkv{exp-db}{date=2020/12/31, event=eat}
+  \dbitemkv{exp-db}{date=2021/01/01, event=sleep}
+  \dbshow{exp-style}{exp-db}
+\end{example*}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
+%
+% \begin{option}[added=2022-01-05, rEXP]{<attr>/before-code}
 %   \begin{syntax}
-%     record-before-code = <code>
+%     \nopt{<attr>/before-code} = <before code> \inidef*
 %   \end{syntax}
 %
-%   Set the \meta{code} that is executed \enbefore displaying a record.
+%   Set the \meta{code} that is executed by \cs{dbuse} \enbefore displaying
+%   the value of attribute.
 % \end{option}
 %
-% \begin{option}[added=2022-01-05, rEXP]{record-after-code}
+% \begin{option}[added=2022-01-05, rEXP]{<attr>/after-code}
 %   \begin{syntax}
-%     record-after-code = <code>
+%     \nopt{<attr>/after-code} = <after code> \inidef*
 %   \end{syntax}
 %
-%   Set the \meta{code} that is executed \enafter displaying the record.
+%   Set the \meta{code} that is executed by \cs{dbuse} \enafter displaying
+%   the value of attribute.
 % \end{option}
 %
-% \begin{option}[added=2022-01-05, rEXP]{<attr>/before-code}
+% The style code execution order of attribute is:
+% \begin{enumerate}[nolistsep]
+%   \item \opt{<attr>/before-code}
+%   \item \opt{<attr>/code} or \opt{<attr>/code*}
+%   \item \opt{<attr>/after-code}
+% \end{enumerate}
+%
+% \changes{1.5}{2022-01-16}{Add options}{\opt{<attr>/item-code},
+% \opt{<attr>/item-code*}}
+% \begin{option}[added=2022-01-16, rEXP]{<attr>/item-code}
 %   \begin{syntax}
-%     <attr>/before-code = <code>
+%     \nopt{<attr>/item-code} = <item code> \inidef(\#1)
 %   \end{syntax}
 %
-%   Set the \meta{code} that is executed by \cs{dbuse} \enbefore displaying
-%   certain attribute.
+%   Set the style code of \meta{attr}. In \meta{item code}, |#1| is replaced
+%   with the item of the comma list. Example \ref{en-clist-code} shows how to
+%   set the style code of the item of the comma list.
 % \end{option}
 %
-% \begin{option}[added=2022-01-05, rEXP]{<attr>/after-code}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(clist-code){Set the Style Code of Clist Item}
+  \dbNewDatabase{clist-db}{name=str, label=clist}
+  \dbNewStyle{clist-style}{clist-db}{
+    item-code       = \par\dbuse{name}:~\dbuse{label},
+    label/item-code = (\textcolor{red}{\textit{#1}}),
+  }
+  \dbitemkv{clist-db}{name=pig,  label={animal, meat}}
+  \dbitemkv{clist-db}{name=Alex, label={person, male}}
+  \dbshow{clist-style}{clist-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \begin{option}[added=2022-01-16, rEXP]{<attr>/item-code*}
 %   \begin{syntax}
-%     <attr>/after-code = <code>
+%     \nopt{<attr>/item-code*} = <item code> \inidef
 %   \end{syntax}
 %
-%   Set the \meta{code} that is executed by \cs{dbuse} \enafter displaying
-%   certain attribute.
+%   Set the style code of \meta{attr}. In \meta{item code}, |#1| is replaced
+%   with the \textbf{expanded} item of the comma list.
 % \end{option}
 %
 % \begin{option}[added=2022-01-05, rEXP]{<attr>/item-before-code}
 %   \begin{syntax}
-%     <attr>/item-before-code = <code>
+%     \nopt{<attr>/item-before-code} = <before code> \inidef*
 %   \end{syntax}
 %
 %   Only for attributes of type |clist|. Set the \meta{code} that is excuted
@@ -1485,7 +2387,7 @@
 %
 % \begin{option}[added=2022-01-05, rEXP]{<attr>/item-after-code}
 %   \begin{syntax}
-%     <attr>/item-after-code = <code>
+%     \nopt{<attr>/item-after-code} = <after code> \inidef*
 %   \end{syntax}
 %
 %   Only for attributes of type |clist|. Set the \meta{code} that is excuted
@@ -1492,56 +2394,290 @@
 %   \enafter displaying the item of the comma list.
 % \end{option}
 %
-% \subsection{Use \cs{dbNewReviewPoints} to Define Review Points}
+% The style code execution order of comma list item is:
+% \begin{enumerate}[nolistsep]
+%   \item \opt{<attr>/item-before-code}
+%   \item \opt{<attr>/item-code} or \opt{<attr>/item-code*}
+%   \item \opt{<attr>/item-after-code}
+% \end{enumerate}
 %
+% \changes{1.3}{2022-01-09}{Update option}{\opt{<attr>/sep}}
+% \begin{option}[added=2022-01-05, updated=2022-01-08, rEXP]{<attr>/sep}
+%   \begin{syntax}
+%     \nopt{<attr>/sep} = <separator> \sepini\\
+%     \nopt{<attr>/sep} = \{ \\
+%     ~~\meta{separator between two}, \\
+%     ~~\meta{separator between more than two}, \\
+%     ~~\meta{separator between final two} \\
+%     \} \\
+%     \nopt{<attr>/sep} = \{ \\
+%     ~~\meta{separator before year}, \\
+%     ~~\meta{separator between year and month}, \\
+%     ~~\meta{separator between month and day}, \\
+%     ~~\meta{separator after day} \\
+%     \} \\
+%   \end{syntax}
+%
+%   Only for attributes of type |clist| or |date|. Set the separator between
+%   items. If the argument is an one-item comma list, all separators are set to
+%   \meta{separator} but \meta{separator before year} and \meta{separator after
+%   day} is set empty.
+% \end{option}
+%
+%   If the argument is a comma list of 3 items, it is used to set the separator
+%   between items of the comma list. Following documentation is quoted from
+%   \pkg{interface3}:
+%   \begin{quote}
+%     If the comma list has more than two items, the \meta{separator between
+%     more than two} is placed between each pair of items except the last, for
+%     which the \meta{separator between final two} is used. If the comma list
+%     has exactly two items, then they are placed in the input stream separated
+%     by the \meta{separator between two}. If the comma list has a single item,
+%     it is placed in the input stream, and a comma list with no items produces
+%     no output.
+%   \end{quote}
+%   For attributes of type |clist|, incorrect number (numbers exclude 1 and 3)
+%   of items of the argument will raise an error. Example \ref{en-clist-sep}
+%   shows how to use this option to customize the separators between comma
+%   list items.
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(clist-sep){Set Separator Between Items of Comma List}
+  \dbNewDatabase{clist-db}{label=clist}
+  \dbNewStyle{clist-base}{clist-db}{
+    before-code = {\dbIfEmptyF{\begin{enumerate}}},
+    after-code  = {\dbIfEmptyF{\end{enumerate}}},
+    item-code   = \item \dbuse{label},
+  }
+  \dbNewStyle[clist-base]{clist-style1}{clist-db}{
+    label/sep = {{,~}}
+  }
+  \dbNewStyle[clist-base]{clist-style2}{clist-db}{
+    label/sep = {{,~}, {,~}, ~and~}
+  }
+  \dbitemkv{clist-db}{label={a, b, c}}
+  \dbitemkv{clist-db}{label={1, 2, 3}}
+  \dbshow{clist-style1}{clist-db}
+  \dbshow{clist-style2}{clist-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+%   If the argument is a comma list of 4 items, it is used to set the separators
+%   of the date. For attributes of type |date|, incorrect number (numbers
+%   exclude 1 and 4) will raise an error. Example \ref{en-date-sep} shows how
+%   to customize the date separators.
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(date-sep){Set Date Separators}
+  \dbNewDatabase{date-db}{date=date}
+  \dbNewStyle{date-style1}{date-db}{
+    item-code = \dbuse{date}\quad,
+    date/sep  = -,
+  }
+  \dbNewStyle{date-style2}{date-db}{
+    item-code = \dbuse{date}\quad,
+    date/sep  = {\$, +, !, \$},
+  }
+  \dbitemkv{date-db}{date=2020/01/02}
+  \dbitemkv{date-db}{date=2022/07/12}
+  \dbshow{date-style1}{date-db}
+  \dbshow{date-style2}{date-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-14}{Add option}{\opt{<attr>/format-code}}
+% \begin{option}[added=2022-01-14, rEXP]{<attr>/format-code}
+%   \begin{syntax}
+%     \nopt{<attr>/format-code} = <format code> \inidef
+%   \end{syntax}
+%
+%   Use this option to get fine-grained control over date formatting. In
+%   \meta{format code}, |#1| represents for the \meta{year}, |#2| represents for
+%   the \meta{month} and |#3| represents for the \meta{day}. Example
+%   \ref{en-date-code} shows how to format the date with this option.
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(date-code){Date Formatting}
+  \dbNewDatabase{date-db}{date=date}
+  \dbNewStyle{date-style}{date-db}{
+    item-code        = \dbuse{date},
+    date/format-code = {日:#3\quad 月:#2\quad 年:#1}
+  }
+  \dbitemkv{date-db}{date=2022/01/01}
+  \dbshow{date-style}{date-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/zfill}}
+% \begin{option}[added=2022-01-08, EXP]{<attr>/zfill}
+%   \begin{syntax}
+%     \nopt{<attr>/zfill} = <\TTF> \inidef(true)[true]
+%   \end{syntax}
+%
+%   Only for attributes of type |date|. Control whether to fill zero on the left
+%   of the month or day. Example \ref{en-date-zfill} shows the differences.
+% \end{option}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(date-zfill){Control the Leading Zero of the Date}
+  \dbNewDatabase{date-db}{date=date}
+  \dbNewStyle {zfill-style}{date-db}{
+    item-code = \dbuse{date},
+  }
+  \dbNewStyle{nofill-style}{date-db}{
+    item-code  = \dbuse{date},
+    date/zfill = false,
+  }
+  \dbitemkv{date-db}{date=2022/01/01}
+  \dbshow {zfill-style}{date-db}
+  \dbshow{nofill-style}{date-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.4}{2022-01-13}{Add macro}{\cs{dbdatesep}}
+% \begin{function}[added=2022-01-13]{\dbdatesep}
+%   \begin{syntax}
+%     \cs{dbdatesep} \marg{separator}
+%   \end{syntax}
+%
+%   Set the separator for internal date parsing. The default value is |/|,
+%   i.e. the date must be store in the format of |yyyy/mm/dd|. Example
+%   \ref{en-inner-date-sep} shows how to store dates with two formats.
+%   However, the separators are not really stored but used to parse the year,
+%   month and day, which will be stored internally as three integers.
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(inner-date-sep){Set Date Parsing Format}
+  \dbNewDatabase{inner-date-db}{date=date}
+  \dbNewStyle{inner-date-style}{inner-date-db}{
+    item-code = \dbuse{date}\quad,
+  }
+  \dbitemkv{inner-date-db}{date=2020/01/20}
+  \dbdatesep{-}
+  \dbitemkv{inner-date-db}{date=2022-01-10}
+  \dbshow{inner-date-style}{inner-date-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \subsection{Data Filters}
+%
+% Filter is a combination of conditionals that is used to filter the data you
+% want to display.
+%
 % \begin{function}[added=2022-01-05]{\dbNewReviewPoints}
 %   \begin{syntax}
 %     \cs{dbNewReviewPoints} \marg{name} \marg{points}
 %   \end{syntax}
 %
-%   Define the new \meta{points} that is specially designed for reviewing
-%   something. \meta{points} is a list of integers. Suppose you record the date
-%   when you did not answer correctly and you plan to review every 2, 5 and 15
-%   days. The following code give what you want.
+%   Define \meta{points} to filter dates by intervals.  something. \meta{points}
+%   is a list of \meta{intexpr}. In example \ref{en-review-points}, a \meta{date
+%   anchor} and a list of \meta{points} is defined. During the filtering process,
+%   \meta{interval} is calculated by $\meta{interval} = \meta{date anchor} -
+%   \meta{date cmp}$, \meta{date cmp} is the \meta{date} of current item. Then
+%   each \meta{intexpr} in \meta{points} is compared with \meta{interval} to
+%   test if they are equal.
 % \end{function}
 %
-% \begin{verbatim}
-%   \dbNewReviewPoints{review-point}{2, 5, 15}            % define points
-%   \begin{dbFilters}
-%     \dbNewConditional{cond1}{date}{review-point|\Today} % define conditional
-%     \dbCombineConditionals{filter1}{cond1}              % define filter
-%   \end{dbFilters}
-%   \dbNewStyle{review-style}{ques}{filter=filter1}       % define style
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\DeleteShortVerb{\|}
+\dbdatesep{/}
+\begin{example*}(review-points){Filter with Review Points}
+  \dbNewDatabase{filter-db}{date=date}
+  \dbNewReviewPoints{review}{2, 5}
+  \dbNewRawFilter*{review-filter}{filter-db}{date}{review|2022/02/06}
+  \dbNewStyle{filter-style}{filter-db}{
+    item-code = \dbuse{date}\quad,
+    filter    = review-filter,
+  }
+  \dbitemkv{filter-db}{date=2022/01/30}
+  \dbitemkv{filter-db}{date=2022/02/01}
+  \dbitemkv{filter-db}{date=2022/02/04}
+  \dbshow{filter-style}{filter-db}
+\end{example*}
+\MakeShortVerb{\|}
+% \iffalse
+%</verb>
+% \fi
 %
-% \subsection{Define Filters inside \env{dbFilters} Environment}
-%
-% \begin{environment}[added=2022-01-05]{dbFilters}
+% \changes{1.5}{2022-01-16}{Update env}{add starred version of \env{dbFilters}}
+% \begin{environment}[added=2022-01-05, updated=2022-01-16]{dbFilters}
 %   \begin{syntax}
-%     |\begin{dbFilters}|\marg{database} \\
+%     |\begin|\{\env{dbFilters}\}   \marg{database} \\
 %     ~~\meta{code}
-%     |\end{dbFilters}| \\
+%     |\end|\{\env{dbFilters}\} \\
+%     |\begin|\{\env{dbFilters}\} * \marg{database} \\
+%     ~~\meta{code}
+%     |\end|\{\env{dbFilters}\} \\
 %   \end{syntax}
 %
 %   Filters are defined inside \env{dbFilters} environment, inside which,
 %   \cs{dbNewConditional} is defined to declare conditionals and
-%   \cs{dbCombineConditionals} is defined to combine conditionals. Filters are
-%   independent in different databases, which means the same name of filters is
-%   allowed in different databases.
+%   \cs{dbCombineConditionals} is defined to combine conditionals. Starred
+%   version will define a filter of the same name of conditional as soon as you
+%   define it. In example \ref{en-star-filter}, line 3 define the conditional
+%   and the filter named |greater| so that you can use it in option \opt{option}.
+%   Filters are independent in different databases, which means the same name of
+%   filters is allowed in different databases.
 % \end{environment}
 %
-% \begin{function}[added=2022-01-05, updated=2022-01-08]{\dbNewConditional, \dbNewConditional*}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(star-filter){Define Conditional and Filter at Same Time}
+  \dbNewDatabase{filter-db}{count=int}
+  \begin{dbFilters}*{filter-db}
+    \dbNewCond{greater}{count}{\dbval > 3}
+  \end{dbFilters}
+  \dbNewStyle{filter-style}{filter-db}{
+    filter    = greater,
+    item-code = \dbuse{count}\quad,
+  }
+  \dbitemkv{filter-db}{count=2}
+  \dbitemkv{filter-db}{count=5}
+  \dbshow{filter-style}{filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
+% \changes{1.5}{2022-01-15}{Add macros}{\cs{dbNewCond}, \cs{dbCombCond}}
+% \begin{function}[added=2022-01-05, updated=2022-01-16]{\dbNewConditional,
+% \dbNewCond, \dbNewConditional*, \dbNewCond*}
 %   \begin{syntax}
-%     \cs{dbNewConditional}  \marg{name}        \marg{attr} \marg{cond spec} \\
-%     \cs{dbNewConditional}* \marg{name}        \marg{attr} \marg{cond spec} \\[2pt]
-%     \cs{dbNewConditional}  \marg{name} \marg{int/fp attr} \marg{expr} \\
-%     \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{expr} \\
-%     \cs{dbNewConditional}  \marg{name} \marg{str/tl attr} \marg{regex expr} \\
-%     \cs{dbNewConditional}* \marg{name} \marg{str/tl attr} \marg{regex expr} \\
-%     \cs{dbNewConditional}  \marg{name}  \marg{clist attr} \marg{val list} \\
-%     \cs{dbNewConditional}* \marg{name}  \marg{clist attr} \marg{val list} \\
-%     \cs{dbNewConditional}  \marg{name}   \marg{date attr} \marg{expr}
-%     \cs{dbNewConditional}* \marg{name}   \marg{date attr} \{\meta{review points}\orbar\meta{date}\} \\
+%     \cs{dbNewConditional}  \marg{name}        \marg{attr} \marg{cond spec}  \oarg{filter info}
+%     \cs{dbNewConditional}* \marg{name}        \marg{attr} \marg{cond spec}  \oarg{filter info} \\[2pt]
+%     \cs{dbNewConditional}  \marg{name} \marg{int/fp attr} \marg{expr}       \oarg{filter info}
+%     \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{expr}       \oarg{filter info}
+%     \cs{dbNewConditional}  \marg{name} \marg{str/tl attr} \marg{regex expr} \oarg{filter info}
+%     \cs{dbNewConditional}* \marg{name} \marg{str/tl attr} \marg{regex expr} \oarg{filter info}
+%     \cs{dbNewConditional}  \marg{name}  \marg{clist attr} \marg{val list}   \oarg{filter info}
+%     \cs{dbNewConditional}* \marg{name}  \marg{clist attr} \marg{val list}   \oarg{filter info}
+%     \cs{dbNewConditional}  \marg{name}   \marg{date attr} \marg{date expr}  \oarg{filter info}
+%     \cs{dbNewConditional}* \marg{name}   \marg{date attr} \{\meta{review points}\orbar\meta{date}\} \oarg{filter info}
 %   \end{syntax}
 %
 %   Define the conditional named \meta{name} that binds to \meta{attr}. \cs{dbval}
@@ -1557,53 +2693,176 @@
 %   \end{note}
 %
 %   For attribute of type |str| and |tl|, unstarred form matches any part while
-%   starred form matches the whole part with the \meta{regex expr}.
+%   starred form matches the whole part with the \meta{regex expr}, which is
+%   shown in example \ref{en-filter-str}: filter |part| match |name|s that
+%   contain numbers and filter |all| match |name|s that is composed of digits.
 %
-% \begin{verbatim}
-%   \dbNewConditional {cond1}{str-attr}{abc}  % match abc, abcd, 1abc, =abc=, etc
-%   \dbNewConditional*{cond2}{str-attr}{abc} % only match abc
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(filter-str){Match Strings}
+  \dbNewDatabase{filter-db}{name=str}
+  \begin{dbFilters}*{filter-db}
+    \dbNewCond{part}{name}{\d+}
+    \dbNewCond*{all}{name}{\d+}
+  \end{dbFilters}
+  \dbNewStyle{part-style}{filter-db}{
+    before-code = Match part:~,
+    item-code   = \dbuse{name}\quad,
+    filter      = part,
+  }
+  \dbNewStyle{all-style}{filter-db}{
+    before-code = Match all:~,
+    item-code   = \dbuse{name}\quad,
+    filter      = all,
+  }
+  \dbitemkv{filter-db}{name=123}
+  \dbitemkv{filter-db}{name=int12}
+  \dbitemkv{filter-db}{name=variable}
+  \dbshow{part-style}{filter-db}
+  \dbshow {all-style}{filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
 %
 %   For attributes of type |clist|, the conditional defined by unstarred form is
 %   true if any item of \meta{val list} is in the comma list. While the
 %   conditional defined by starred form is true only if every item of \meta{val
-%   list} is in the comma list. As is showed below, for |cond1|, |a| is in
-%   |{a, b, d}| so |cond1| is true. While |c| is not in |{a, b, d}| so |cond2|
-%   is false.
+%   list} is in the comma list. In example \ref{en-filter-clist}, filter |or|
+%   match labels that contain hard \textbf{or} red, and filter |and| match
+%   labels that contain hard \textbf{and} red.
 %
-% \begin{verbatim}
-%   \dbNewConditional {cond1}{clist-attr}{a, b, c}  % {a, b, d} -> true
-%   \dbNewConditional*{cond2}{clist-attr}{a, b, c} % {a, b, d} -> false
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(filter-clist){Filter Lists}
+  \dbNewDatabase{filter-db}{label=clist}
+  \begin{dbFilters}*{filter-db}
+    \dbNewCond  {or}{label}{hard, red}
+    \dbNewCond*{and}{label}{hard, red}
+  \end{dbFilters}
+  \def\emph#1{\textit{\textbf{#1}}}
+  \dbNewStyle{base-style}{filter-db}{
+    before-code = {
+      \begin{minipage}[t]{.3\textwidth}
+        All items
+    },
+    after-code  = {\end{minipage}},
+    item-code   = \par\dbarabic.~\dbuse{label},
+  }
+  \dbNewStyle[base-style] {or-style}{filter-db}{
+    before-code = {
+      \begin{minipage}[t]{.3\textwidth}
+        Match \emph{any} of hard \emph{or} red
+    },
+    filter      = or,
+  }
+  \dbNewStyle[base-style]{and-style}{filter-db}{
+    before-code = {
+      \begin{minipage}[t]{.3\textwidth}
+        Match \emph{all} of hard \emph{and} red
+    },
+    filter      = and,
+  }
+  \dbitemkv{filter-db}{label={hard, red}}
+  \dbitemkv{filter-db}{label={hard, blue}}
+  \dbitemkv{filter-db}{label={easy, blue}}
+  \dbitemkv{filter-db}{label={easy, red}}
+  \dbitemkv{filter-db}{label={hard, red, flat}}
+  \dbshow {base-style}{filter-db}
+  \dbshow   {or-style}{filter-db}
+  \dbshow  {and-style}{filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
 %
 %   \changes{1.3}{2022-01-08}{Update logic}{swap definition of starred and
 %   unstarred conditionals of date}
 %   For attributes of type |date|, unstarred form replace each date with a
-%   integer representing for the days between \meta{date} and
-%   \textit{1971/01/01}, and the result is passed to \cs{int_compare:nTF}.
+%   integer representing for the days between \meta{date} and 1971/01/01, and
+%   the result is passed to \cs{int_compare:nTF}. Example \ref{en-filter-date}
+%   shows how to use the \meta{date expr} to filter the data.
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(filter-date){Filter with Date Expression}
+  \dbNewDatabase{filter-db}{date=date}
+  \dbNewRawFilter{date-filter}{filter-db}{date}{\dbval >= 2022/02/01}
+  \dbNewStyle{filter-style}{filter-db}{
+    item-code = \dbuse{date}\quad,
+    filter    = date-filter,
+  }
+  \dbitemkv{filter-db}{date=2022/01/30}
+  \dbitemkv{filter-db}{date=2022/02/01}
+  \dbitemkv{filter-db}{date=2022/02/04}
+  \dbshow{filter-style}{filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
 %   Starred form defines the conditional with review points defined by
-%   \cs{dbNewRdbNewReviewPoints} and \meta{date} is the date to be compared.
+%   \cs{dbNewReviewPoints} and \meta{date} is the date to be compared (see
+%   example \ref{en-review-points}).
 %
+% \changes{1.5}{2022-01-16}{Add macro}{\cs{dbNewRawFilter}}
+% \begin{function}[added=2022-01-16]{\dbNewRawFilter}
+%   \begin{syntax}
+%     \cs{dbNewRawFilter}  \marg{name} \marg{database} \marg{attr} \marg{cond spec} \oarg{filter info}
+%     \cs{dbNewRawFilter}* \marg{name} \marg{database} \marg{attr} \marg{cond spec} \oarg{filter info}
+%     \textnormal{\textit{Equal to}}
+%     |\begin|\{\env{dbFilters}\}*\phantom{\marg{name}}\marg{database}
+%     ~~\cs{dbNewCond}     \marg{name} \phantom{\marg{database}} \marg{attr} \marg{cond spec} \oarg{filter info}
+%     ~~\cs{dbNewCond}*    \marg{name} \phantom{\marg{database}} \marg{attr} \marg{cond spec} \oarg{filter info}
+%     |\end|\{\env{dbFilters}\}
+%   \end{syntax}
+%
+%   Use this command to quickly define a \meta{filter} that has the same name
+%   with the \meta{conditional}. Example \ref{en-new-raw-filter} is actually the
+%   same with example \ref{en-star-filter}, but it is more concise.
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(new-raw-filter){Define Conditional and Filter at Same Time}
+  \dbNewDatabase{filter-db}{count=int}
+  \dbNewRawFilter{greater}{filter-db}{count}{\dbval > 3}
+  \dbNewStyle{filter-style}{filter-db}{
+    filter    = greater,
+    item-code = \dbuse{count}\quad,
+  }
+  \dbitemkv{filter-db}{count=2}
+  \dbitemkv{filter-db}{count=5}
+  \dbshow{filter-style}{filter-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
 % \begin{function}[added=2022-01-05]{\dbCombineConditionals}
 %   \begin{syntax}
 %     \cs{dbCombineConditionals} \marg{name} \marg{cond combination} \oarg{info}
 %   \end{syntax}
 %
-%   Define the filter \meta{name}, which combine the conditionals and store the
-%   extra \meta{info} into \cs{dbFilterInfo}. So you can write something as\\
-%   \verb=\dbCombineConditionals{filter}{(cond1 && cond2) || !cond3}=.\\
-%   Supported operators are \verb=&&, ||, !=. You can set the option \opt{filter}
-%   to \meta{name} to apply the filter when you display the database.
+%   Define the filter \meta{name}, which combine the conditionals and store
+%   the extra \meta{info} into \cs{dbFilterInfo}.  Supported operators are
+%   \verb=&&, ||, !=. You can set the option \opt{filter} to \meta{name} to
+%   apply the filter when you display the database. See example
+%   \ref{en-filter}.
 % \end{function}
 %
-% \subsection{Store Data with \env{dbitem} Environment}
+% \subsection{Store and Use Data}
 %
 % \changes{1.4}{2022-01-13}{Update env}{dbitem}
 % \begin{environment}[added=2022-01-05, updated=2022-01-13]{dbitem}
 %   \begin{syntax}
-%     |\begin{dbitem}| \marg{database} \oarg{attr-val list}
+%     |\begin|\marg{\env{dbitem}} \marg{database} \oarg{attr-val list}
 %     ~~\meta{code} \\
-%     |\end{dbitem}|
+%     |\end|\marg{\env{dbitem}}
 %   \end{syntax}
 %
 %   The data are stored with \env{dbitem} environment in two ways. Short data
@@ -1612,15 +2871,37 @@
 %   \meta{attr} = \meta{val} is equal to \cs{dbsave}\marg{attr}\marg{val}, and
 %   \meta{attr} = \meta{val} is equal to \cs{dbsave*}\marg{attr}\marg{val},
 %   in which case, data will not be expanded in an |e| or |x|-type argument.
-%   An example code is showned below.
+%   Example \ref{en-dbitem} shows how to store data with \env{dbitem}.
 % \end{environment}
 %
-% \begin{verbatim}
-%   \begin{dbitem}[date=2022-01-01, info=test]
-%     \dbsave{question}{This is a test question.}
-%     \dbsave{answer}  {This is a test answer.}
-%   \end{dbitem}
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example*}(dbitem){Store Date}
+  \dbNewDatabase{ques-db}{date=date, ques=tl, ans=tl}
+  \dbNewStyle{ques-style}{ques-db}{
+    item-code       = {%
+      \par\dbuse{date}
+      \par\dbarabic.~\dbuse{ques}
+      \par\textbf{Answer:}~\dbuse{ans}
+    },
+    item-after-code = \medskip,
+  }
+  \begin{dbitem}{ques-db}[date=2022/01/01]
+    \dbsave{ques}{Distance from earth to moon?}
+    \dbsave{ans} {384,401 kilometers.}
+  \end{dbitem}
+  \begin{dbitem}{ques-db}[date=2022/01/02]
+    \dbsave{ques}{The number of English letters?}
+    \dbsave{ans} {26.}
+  \end{dbitem}
+  \dbshow{ques-style}{ques-db}
+\end{example*}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
 %
 % \changes{1.4}{2022-01-13}{Add macro}{\cs{dbitemkv}}
 % \begin{function}[added=2022-01-13]{\dbitemkv}
@@ -1653,7 +2934,8 @@
 %   \end{syntax}
 %
 %   Display the value of \meta{attr} of current record. \cs{dbuse} is
-%   \textbf{expandable} and can be only used inside the option \opt{item-code}.
+%   \textbf{expandable} and can be only used inside the option \opt{item-code},
+%   \opt{item-before-code}, \opt{item-after-code}.
 % \end{function}
 %
 % \subsection{Conditionals}
@@ -1661,22 +2943,72 @@
 % \begin{function}[added=2022-01-05, EXP]{\dbIfEmptyT, \dbIfEmptyF, \dbIfEmptyTF}
 %   \begin{syntax}
 %     \cs{dbIfEmptyTF} \marg{true code} \marg{false code} \\
-%     \cs{dbIfEmptyT} \marg{true code} \\
+%     \cs{dbIfEmptyT}  \marg{true code} \\
 %     \cs{dbIfEmptyF} \marg{false code}
 %   \end{syntax}
 %
-%   Test if the database is empty. The example below shows how to avoid an empty
-%   list environment.
+%   Test if the database is empty. Example \ref{en-empty-db} shows how to
+%   avoid an empty list environment.
 % \end{function}
 %
-% \begin{verbatim}
-%   \dbNewStyle{style-cond1}{database-test}{
-%     before-code = {\dbIfEmptyF{\begin{enumerate}}},
-%     after-code = {\dbIfEmptyF{\end{enumerate}}},
-%     item-code = {\item \dbuse{attr-test}}
-%   }
-% \end{verbatim}
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(empty-db){Avoid Empty List Environment}
+  \dbNewDatabase{test-db}{text=tl}
+  \dbNewRawFilter{alph}{test-db}{text}{\d}
+  \dbNewStyle{base-style}{test-db}{
+    before-code = \dbIfEmptyTF{Empty db}{\begin{enumerate}},
+    after-code  = \dbIfEmptyF{\end{enumerate}}\medskip,
+    item-code   = \item \dbuse{text},
+  }
+  \dbNewStyle[base-style]{empty-style}{test-db}{
+    raw-filter=!alph
+  }
+  \dbitemkv{test-db}{text={$1 + 1 = 2$.}}
+  \dbitemkv{test-db}{text={I have 2 pens.}}
+  \dbshow {base-style}{test-db}
+  \dbshow{empty-style}{test-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
 %
+% \changes{1.5}{2022-01-17}{Add macros}{\cs{dbIfLastT}, \cs{dbIfLastF},
+% \cs{dbIfLastTF}}
+% \begin{function}[added=2022-01-17, EXP]{\dbIfLastT, \dbIfLastF, \dbIfLastTF}
+%   \begin{syntax}
+%     \cs{dbIfLastTF} \marg{true code} \marg{false code}
+%     \cs{dbIfLastT}  \marg{true code}
+%     \cs{dbIfLastF} \marg{false code}
+%   \end{syntax}
+%
+%   Test if the current item is the last item to display. Example \ref{en-last}
+%   shows how to set the separator between items.
+% \end{function}
+%
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example*}(last){Separator between Items}
+  \dbNewDatabase{last-db}{text=tl}
+  \dbNewStyle{last-style}{last-db}{
+    item-code  = {%
+      \par\dbuse{text}\par%
+      \dbIfLastF{\textcolor{red}{\hrulefill separator\hrulefill}}%
+    },
+  }
+  \dbitemkv{last-db}{text=This is the first paragraph.}
+  \dbitemkv{last-db}{text=This is the second paragraph.}
+  \dbitemkv{last-db}{text=This is the last paragraph.}
+  \dbshow{last-style}{last-db}
+\end{example*}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
+%
 % \changes{1.2}{2022-01-08}{Remove macros}{\cs{dbItemIfEmpty(TF)}, \cs{dbClistItemIfEmpty(TF)}}
 %
 % \subsection{Expression Functions}
@@ -1687,26 +3019,50 @@
 %   \dbIntMin, \dbIntMod, \dbFpSign,
 % }
 %   \begin{syntax}
-%     \cs{dbIntAbs} \Arg{intexpr}
-%     \cs{dbIntSign} \Arg{intexpr}
-%     \cs{dbIntDivRound} \Arg{intexpr_1} \marg{intexpr_2}
-%     \cs{dbIntDivTruncate} \Arg{intexpr_1} \marg{intexpr_2}
-%     \cs{dbIntMax} \Arg{intexpr_1} \marg{intexpr_2}
-%     \cs{dbIntMin} \Arg{intexpr_1} \marg{intexpr_2}
-%     \cs{dbIntMod} \Arg{intexpr_1} \marg{intexpr_2}
-%     \cs{dbFpSign} \Arg{fpexpr}
+%     \cs{dbIntAbs}         \Arg{intexpr}
+%     \cs{dbIntSign}        \Arg{intexpr}
+%     \cs{dbIntDivRound}    \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{dbIntDivTruncate} \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{dbIntMax}         \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{dbIntMin}         \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{dbIntMod}         \Arg{intexpr_1} \Arg{intexpr_2}
+%     \cs{dbFpSign}         \Arg{fpexpr}
 %   \end{syntax}
-%   \cs{dbIntAbs} is identical to \cs{int_abs:n} \\
-%   \cs{dbIntSign} is identical to \cs{int_sign:n} \\
-%   \cs{dbIntDivRound} is identical to \cs{int_div_round:nn} \\
-%   \cs{dbIntDivTruncate} is identical to \cs{int_div_truncate:nn} \\
-%   \cs{dbIntMax} is identical to \cs{int_max:nn} \\
-%   \cs{dbIntMin} is identical to \cs{int_min:nn} \\
-%   \cs{dbIntMod} is identical to \cs{int_mod:nn} \\
-%   \cs{dbFpSign} is identical to \cs{fp_sign:n} \\
-%    Detailed documentation see \pkg{interface3} \\
+% \begin{tblr}{ll}
+%   \cs{dbIntAbs}         & is equal to \cs{int_abs:n} \\
+%   \cs{dbIntSign}        & is equal to \cs{int_sign:n} \\
+%   \cs{dbIntDivRound}    & is equal to \cs{int_div_round:nn} \\
+%   \cs{dbIntDivTruncate} & is equal to \cs{int_div_truncate:nn} \\
+%   \cs{dbIntMax}         & is equal to \cs{int_max:nn} \\
+%   \cs{dbIntMin}         & is equal to \cs{int_min:nn} \\
+%   \cs{dbIntMod}         & is equal to \cs{int_mod:nn} \\
+%   \cs{dbFpSign}         & is equal to \cs{fp_sign:n} \\
+% \end{tblr}
+%
+%   See detailed documentation of \pkg{interface3}. Example \ref{en-expr-db}
+%   shows how to filter multiples of 3.
 % \end{function}
 %
+% \iffalse
+%<*verb>
+% \fi
+\begin{example*}(expr-db){Filter Multiples of 3}
+  \dbNewDatabase{expr-db}{n=int}
+  \dbNewRawFilter{mod}{expr-db}{n}{\dbIntMod{\dbval}{3} = 0}
+  \dbNewStyle{expr-style}{expr-db}{
+    item-code = \dbuse{n}\quad,
+    filter    = mod,
+  }
+  \dbitemkv{expr-db}{n=2}
+  \dbitemkv{expr-db}{n=3}
+  \dbitemkv{expr-db}{n=6}
+  \dbitemkv{expr-db}{n=7}
+  \dbshow{expr-style}{expr-db}
+\end{example*}
+% \iffalse
+%</verb>
+% \fi
+%
 % \subsection{Special Macros}
 %
 % Some special macros are defined to expand to different contents according to context.
@@ -1721,209 +3077,61 @@
 %   \dbIndex, \dbarabic, \dbalph, \dbAlph, \dbroman, \dbRoman
 % }
 % \begin{tblr}{ll}
-%   \cs{dbval} & Attribute value, only according in \cs{dbNewConditional}. \\
-%   \cs{dbDatabase} & Database name. \\
+%   \cs{dbval}        & Attribute value, only accessible in \cs{dbNewConditional}. \\
+%   \cs{dbtoday}      & Date of today. \\
+%   \cs{dbDatabase}   & Database name. \\
 %   \cs{dbFilterName} & Filter name. \\
 %   \cs{dbFilterInfo} & Filter information. \\
-%   \cs{dbIndex} & Record index, identical to \cs{dbuse}|{id}| \\
-%   \cs{dbarabic} & Show the counter of query set as digits. \\
-%   \cs{dbalph} & Show the counter of query set as lowercase letters. \\
-%   \cs{dbAlph} & Show the counter of query set as uppercase letters. \\
-%   \cs{dbroman} & Show the counter of query set as lowercase roman numerals. \\
-%   \cs{dbroman} & Show the counter of query set as uppercase roman numerals. \\
-%   \end{tblr}
+%   \cs{dbIndex}      & Record index, identical to \cs{dbuse}\marg{id} \\
+%   \cs{dbarabic}     & Show the counter of query set as digits. \\
+%   \cs{dbalph}       & Show the counter of query set as lowercase letters. \\
+%   \cs{dbAlph}       & Show the counter of query set as uppercase letters. \\
+%   \cs{dbroman}      & Show the counter of query set as lowercase roman numerals. \\
+%   \cs{dbroman}      & Show the counter of query set as uppercase roman numerals. \\
+% \end{tblr}
+%
+%   \cs{dbtoday} show the current date with the separator defined by
+%   \cs{dbdatesep}. See example~\ref{en-special-cs}.
 % \end{function}
 %
-% \section{Example of Flaw Sweeper Template}
-% \label{sec:example}
+% \iffalse
+%<*verb>
+% \fi
+\MakePercentComment
+\begin{example*}(special-cs){Special Commands}
+  \dbNewDatabase{special-db}{name=str}
+  \dbNewRawFilter*{number}{special-db}{name}{\d+}[name that is a number]
+  \dbNewStyle{special-style}{special-db}{
+    before-code = {
+      Date: \dbtoday \\
+      Database: \dbDatabase
+      Filter: \dbFilterName \\
+      Filter info: \dbFilterInfo \par
+      \begin{tabular}{@{}lllllll}
+        Index & arabic & alph & Alph & roman & Roman & value \\
+    },
+    after-code  = \end{tabular},
+    item-code*  = {%
+      \dbIndex & \dbarabic & \dbalph & \dbAlph &
+      \dbroman & \dbRoman & \dbuse{name} \\
+    },
+    sort        = name,
+    filter      = number,
+  }
+  \dbitemkv{special-db}{name=test}
+  \dbitemkv{special-db}{name=12}
+  \dbitemkv{special-db}{name=int2}
+  \dbitemkv{special-db}{name=99}
+  \dbshow{special-style}{special-db}
+\end{example*}
+\MakePercentIgnore
+% \iffalse
+%</verb>
+% \fi
 %
 % \changes{1.1}{2022-01-07}{Update doc}{improve example}
+% \changes{1.5}{2022-01-17}{Remove doc}{Remove big example}
 %
-% \begin{verbatim}
-% \documentclass{article}
-% \usepackage{amsmath, physics}
-% \usepackage{geometry}
-% \usepackage{dbshow}
-% \usepackage{tikz}
-% \usepackage{tcolorbox}
-% \tcbuselibrary{skins}
-% \usetikzlibrary{shadings}
-% \usepackage[hidelinks]{hyperref}
-%
-% \geometry{
-%   margin=2cm
-% }
-%
-% % #1 link node #2 target node #3 text to show
-% \NewDocumentCommand \linktarget { m m m } {%
-%   \hyperlink{#1}{#3}%
-%   \raisebox{1em}{\hypertarget{#2}{}}%
-% }
-%
-% % question box
-% \tcbset{
-%   base/.style={
-%     empty,
-%     frame engine=path,
-%     colframe=yellow!10,
-%     coltitle=red!70,
-%     fonttitle=\bfseries\sffamily,
-%     sharp corners,
-%     left=4pt,
-%     right=4pt,
-%     drop fuzzy shadow,
-%     drop fuzzy shadow,
-%     borderline west={3pt}{-3pt}{red!80},
-%   }
-% }
-%
-% \newtcolorbox{mybox}[1]{%
-%   base, title = {#1}
-% }
-%
-% \dbNewReviewPoints{review}{1, 3, 7, 15, 30, 60}
-%
-% \dbNewDatabase{ques-book}{
-%   ques = tl,
-%   answer = tl,
-%   count = int|1,
-%   labels = clist,
-%   date = date,
-% }
-%
-% \begin{dbFilters}{ques-book}
-%   \dbNewConditional{hard}{labels}{hard}
-%   \dbNewConditional{bad}{count}{\dbval > 1}
-%   \dbNewConditional*{review}{date}{review|2022/01/07}
-%   \dbNewConditional{after}{date}{\dbval > 2022/01/02}
-% \end{dbFilters}
-%
-% % show all questions with hyperlink to answers
-% \dbNewStyle{ques}{ques-book}{
-%   before-code = {\section{Questions}},
-%   item-code = {
-%     \begin{mybox}{%
-%       \linktarget{answer_\dbIndex}{ques_\dbIndex}{%
-%         Question \dbarabic%
-%         \hspace{2em}\dbuse{date}%
-%         \hspace{2em}\dbuse{labels}%
-%         \hfill\dbuse{count}%
-%       }%
-%     }
-%       \dbuse{ques}%
-%     \end{mybox}
-%   },
-%   labels/sep = /,
-% }
-%
-% % show all questions and answers with hyperlink to questions
-% \dbNewStyle{answer}{ques-book}{
-%   before-code = {\section{Questions and Answers}},
-%   item-code = {
-%     \begin{mybox}{%
-%       \linktarget{ques_\dbIndex}{answer_\dbIndex}{%
-%         Question \dbarabic%
-%         \hspace{2em}\dbuse{date}%
-%         \hspace{2em}\dbuse{labels}%
-%         \hfill\dbuse{count}%
-%       }%
-%     }
-%       \dbuse{ques}\tcbsubtitle{Answer}\dbuse{answer}%
-%     \end{mybox}
-%   },
-%   labels/sep = /,
-% }
-%
-% % show all hard questions with hyperlink to answers
-% \dbNewStyle{hard}{ques-book}{
-%   before-code = {\section{Hard Questions}},
-%   item-code = {
-%     \begin{mybox}{%
-%       \hyperlink{answer_\dbIndex}{%
-%         Question \dbarabic%
-%         \hspace{2em}\dbuse{date}%
-%         \hspace{2em}\dbuse{labels}%
-%         \hfill\dbuse{count}%
-%       }%
-%     }
-%       \dbuse{ques}%
-%     \end{mybox}
-%   },
-%   raw-filter = hard,
-%   labels/sep = /,
-% }
-%
-% % show all hard questions that have been answered incorrectly for more than
-% % one time with hyperlink to answers
-% \dbNewStyle[hard]{bad}{ques-book}{
-%   before-code = {\section{Bad Questions}},
-%   raw-filter = {bad && hard},
-% }
-% % show all questions that plan to be reviewed on 2022/01/07 with hyperlink to
-% % answers
-% \dbNewStyle[hard]{review}{ques-book}{
-%   before-code = {\section{Questions to be Reviewed}},
-%   raw-filter = {review},
-% }
-% % show all questions that is record after 2022/01/02 with hyperlink to answers
-% \dbNewStyle[hard]{after}{ques-book}{
-%   before-code = {\section{Questions after 2022/01/02}},
-%   raw-filter = {after},
-% }
-%
-% \AtEndDocument{
-%   \dbshow{review}{ques-book}
-%   \dbshow{hard}{ques-book}
-%   \dbshow{bad}{ques-book}
-%   \dbshow{after}{ques-book}
-%   \dbshow{ques}{ques-book}
-%   \dbshow{answer}{ques-book}
-% }
-%
-% \begin{document}
-%
-% \begin{dbitem}{ques-book}[
-%   date=2022/01/01,
-%   labels={math, equation, easy},
-%   count=2
-%   ]
-%   \dbsave{ques}{%
-%     Solve the linear equation: $x + 16 = 31$.
-%   }
-%   \dbsave{answer}{%
-%     $x = 31 - 16 = 15$
-%   }
-% \end{dbitem}
-%
-% \begin{dbitem}{ques-book}[
-%   date=2022/01/01,
-%   labels={math, equation, hard},
-%   count=3
-%   ]
-%   \dbsave{ques}{%
-%     Solve the linear equation: $2y = 16$.
-%   }
-%   \dbsave{answer}{%
-%     $y = 16 / 2 = 8$
-%   }
-% \end{dbitem}
-%
-% \begin{dbitem}{ques-book}[
-%   date=2022/01/04,
-%   labels={math, integral, hard},
-%   count=1
-%   ]
-%   \dbsave{ques}{%
-%     Find the indefinite integral: $\int 2x \dd x$.
-%   }
-%   \dbsave{answer}{%
-%     $\int 2x \dd x = x^2$
-%   }
-% \end{dbitem}
-%
-% \end{document}
-% \end{verbatim}
-%
 % \end{documentation}
 %
 % \StopEventually{}
@@ -1962,6 +3170,7 @@
 %    \begin{macrocode}
 \cs_generate_variant:Nn \msg_warning:nnnn      { nnnx }
 \cs_generate_variant:Nn \keys_set:nn           { nv }
+\cs_generate_variant:Nn \tl_put_right:Nn       { Nv }
 \cs_generate_variant:Nn \clist_use:nn          { xx }
 \cs_generate_variant:Nn \clist_use:nnnn        { xxxx }
 \cs_generate_variant:Nn \clist_map_inline:nn   { Vn }
@@ -2014,6 +3223,8 @@
 }
 %    \end{macrocode}
 %
+% \changes{1.5}{2022-01-15}{Update check code}{transform arguments to string
+% before check}
 % \begin{macro}{\@@_check_database:n}
 % Check if the database is valid.
 % \begin{arguments}
@@ -2021,7 +3232,7 @@
 % \end{arguments}
 %    \begin{macrocode}
 \cs_new:Nn \@@_check_database:n {
-  \prop_if_exist:cF { g_@@_attr_type_prop_#1 }
+  \prop_if_exist:cF { g_@@_attr_type_prop_\tl_to_str:n {#1} }
     { \msg_fatal:nnn { dbshow } { non-existent-database } {#1} }
 }
 %    \end{macrocode}
@@ -2045,7 +3256,7 @@
 % \end{arguments}
 %    \begin{macrocode}
 \cs_new:Nn \@@_check_attr:nn {
-  \prop_if_in:cnF { g_@@_attr_type_prop_#1 } {#2}
+  \prop_if_in:cnF { g_@@_attr_type_prop_\tl_to_str:n {#1} } {#2}
     { \msg_fatal:nnnn { dbshow } { non-existent-attr } {#1} {#2} }
 }
 \cs_generate_variant:Nn \@@_check_attr:nn { nV }
@@ -2070,8 +3281,8 @@
 % \end{arguments}
 %    \begin{macrocode}
 \cs_new:Nn \@@_check_style:nn {
-  \tl_if_exist:cF { g_@@_style_opts_tl_#1_#2 }
-    { \msg_warning:nnnn { dbshow } { non-existent-style } {#1} {#2} }
+  \tl_if_exist:cF { g_@@_style_opts_tl_\tl_to_str:n {#1}_\tl_to_str:n {#2} }
+    { \msg_fatal:nnnn { dbshow } { non-existent-style } {#1} {#2} }
 }
 %    \end{macrocode}
 % \end{macro}
@@ -2094,7 +3305,7 @@
 % \end{arguments}
 %    \begin{macrocode}
 \cs_new:Nn \@@_check_cond:nnn {
-  \tl_if_exist:cF { g_@@_filter_attr_#1_#2 }
+  \tl_if_exist:cF { g_@@_filter_attr_\tl_to_str:n {#1}_\tl_to_str:n {#2} }
     { \msg_fatal:nnnn { dbshow } { non-existent-cond } {#1} {#2} }
 }
 %    \end{macrocode}
@@ -2118,7 +3329,8 @@
 % \end{arguments}
 %    \begin{macrocode}
 \cs_new:Nn \@@_check_filter:nn {
-  \seq_if_exist:cF { g_@@_filter_run_seq_#1_#2 } {
+  \seq_if_exist:cF
+  { g_@@_filter_run_seq_\tl_to_str:n {#1}_\tl_to_str:n {#2} } {
     \str_if_eq:eeF {#2} { -none- } {
       \msg_warning:nnnx { dbshow } { non-existent-filter } {#1} {#2}
     }
@@ -2163,7 +3375,7 @@
 }
 %    \end{macrocode}
 %
-% \begin{macro}{\@@_sep_error:nnn, \@@_sep_error:xxx}
+% \begin{macro}{\@@_sep_fatal:nnn, \@@_sep_fatal:xxx}
 % Check the value of \opt{<attr>/sep} is valid.
 % \begin{arguments}
 %   \item \meta{valid count}
@@ -2171,10 +3383,10 @@
 %   \item \meta{value}
 % \end{arguments}
 %    \begin{macrocode}
-\cs_new:Nn \@@_sep_error:nnn {
-  \msg_error:nnnnn { dbshow } { wrong-seperator } {#1} {#2} {#3}
+\cs_new:Nn \@@_sep_fatal:nnn {
+  \msg_fatal:nnnnn { dbshow } { wrong-seperator } {#1} {#2} {#3}
 }
-\cs_generate_variant:Nn \@@_sep_error:nnn { xxx }
+\cs_generate_variant:Nn \@@_sep_fatal:nnn { xxx }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -2190,9 +3402,11 @@
 %
 % \subsection{Create Database}
 %
+% \changes{1.5}{2022-01-15}{Fix bug}{can not use \cs{dbdatesep} midway}
 % \begin{macro}{\@@_process_default_value:w}
 % Create map from \meta{attr} to \meta{type} and map from \meta{attr} to
-% \meta{default value}.
+% \meta{default value}. Note that only one expansion is needed to get the
+% correct default value from \cs{l_@@_tmp_default}.
 % \begin{arguments}
 %   \item \meta{database}
 %   \item \meta{attr}
@@ -2204,7 +3418,7 @@
 #1\@@_sep#2\@@_sep#3|#4\@@_stop {
   \@@_check_type:n {#3}
   \prop_gput:cxx { g_@@_attr_type_prop_#1 } {#2} {#3}
-  \prop_gput:cxx { g_@@_default_map_#1 } {#2} {#4}
+  \prop_gput:cno { g_@@_default_map_#1 } {#2} {#4}
 }
 %    \end{macrocode}
 % \end{macro}
@@ -2617,7 +3831,7 @@
 % \begin{macro}{\@@_filter_tl:NNNnn, \@@_filter_tl:cccnn}
 % Filter token list with regex expression. It is the same with string.
 %    \begin{macrocode}
-\cs_set_eq:NN \@@_filter_tl:NNNnn \@@_filter_str:NNNnn
+\cs_gset_eq:NN \@@_filter_tl:NNNnn \@@_filter_str:NNNnn
 \cs_generate_variant:Nn \@@_filter_tl:NNNnn { cccnn }
 %    \end{macrocode}
 % \end{macro}
@@ -2662,8 +3876,11 @@
     \__dbdate_set:xx { tmp_day1 } { \l_@@_filter_tmp_tl }
     \__dbdate_set:xx { tmp_day2 } {#3}
     \__dbdate_sub:nnN { tmp_day1 } { tmp_day2 } \l_@@_filter_diff_int
-    \clist_if_in:NxTF \l_@@_filter_tmp_clist
-      { \int_use:N \l_@@_filter_diff_int } {#4} {#5}
+    #5
+    \clist_map_inline:Nn \l_@@_filter_tmp_clist {
+      \int_compare:nNnT { \l_@@_filter_diff_int } = {##1}
+        { #4 \clist_map_break: }
+    }
   } {
 %    \end{macrocode}
 % For unstarred \meta{conditional} which parses \meta{expr}. We first replace
@@ -2711,11 +3928,12 @@
 %   \item \meta{index}
 % \end{arguments}
 %    \begin{macrocode}
-\cs_set:Nn \@@_filter:nnn {
+\cs_new_protected:Nn \@@_filter:nnn {
   \tl_set_eq:Nc \l_@@_attr_tl { g_@@_filter_attr_tl_#1_#2 }
   \cs_set_eq:Nc \dbval { g_@@_data_#1_\l_@@_attr_tl _#3 }
+  \tl_set:Nx \l_@@_type_tl { \@@_get_type:nV {#1} \l_@@_attr_tl }
   \use:c
-    { @@_filter_\@@_get_type:nV {#1} \l_@@_attr_tl :cccnn }
+    { @@_filter_\l_@@_type_tl :cccnn }
     { g_@@_cond_star_bool_#1_#2 }
     { g_@@_filter_expr_tl_#1_#2 }
     { dbval }
@@ -2739,6 +3957,8 @@
 % \end{arguments}
 %    \begin{macrocode}
 \cs_new_protected:Nn \@@_new_conditional:nnnnn {
+  \@@_check_database:n {#1}
+  \@@_check_attr:nn {#1} {#3}
   \tl_gset:cn { g_@@_filter_attr_tl_#1_#2 } {#3}
   \tl_gset:cn { g_@@_filter_expr_tl_#1_#2 } {#4}
   \bool_if_exist:cF { g_@@_filter_bool_#1_#2 }
@@ -2757,7 +3977,10 @@
   \cs_gset:cn { g_@@_filter_hook_#1_#2:n } {
     \@@_filter:nnn {#1} {#2} {##1}
   }
-  \seq_gput_right:cn { g_@@_cond_seq_#1 } {#2}
+  \bool_if_exist:cF { g_@@_cond_exist_bool_#1_#2 }
+    { \bool_set_false:c { g_@@_cond_exist_bool_#1_#2 } }
+  \bool_if:cF { g_@@_cond_exist_bool_#1_#2 }
+    { \seq_gput_right:cn { g_@@_cond_seq_#1 } {#2} }
 }
 %    \end{macrocode}
 % \end{macro}
@@ -2778,7 +4001,7 @@
 \cs_new_protected:Nn \@@_combine_conditional:nnn {
   \tl_gset_eq:cN { g_@@_filter_bool_tl_#1_#2 } \c_true_bool
   \seq_gclear_new:c { g_@@_filter_run_seq_#1_#2 }
-  \regex_extract_all:nnN { \w+ } {#3} \l_@@_cond_seq
+  \regex_extract_all:nnN { [^!=&<>()\ ]+ } {#3} \l_@@_cond_seq
 %    \end{macrocode}
 % \begin{arguments}[2]
 %   \item \meta{conditional}
@@ -2786,13 +4009,18 @@
 %    \begin{macrocode}
   \seq_map_inline:Nn \l_@@_cond_seq {
     \seq_if_in:cnT { g_@@_cond_seq_#1 } {##1} {
-      \seq_gput_right:cn { g_@@_filter_run_seq_#1_#2 }
+      \seq_if_in:cnF { g_@@_filter_run_seq_#1_#2 }
         { g_@@_filter_hook_#1_##1:n }
+      {
+        \seq_gput_right:cn { g_@@_filter_run_seq_#1_#2 }
+          { g_@@_filter_hook_#1_##1:n }
+      }
     }
   }
   \tl_set:Nn \l_@@_cond_expr_tl {#3}
   \regex_replace_all:nnN
-    { \w+ } { \c{ g_@@_filter_bool_#1_\0 } }
+    { (\w|-|\d|\_)+ }
+    { \c{ g_@@_filter_bool_#1_\0 } }
     \l_@@_cond_expr_tl
   \tl_gset_eq:cN
     { g_@@_filter_bool_tl_#1_#2 } \l_@@_cond_expr_tl
@@ -2801,25 +4029,30 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{dbFilters, \dbNewConditional, \dbCombineConditionals}
+% \begin{macro}{dbFilters, \dbNewConditional, \dbNewCond,
+% \dbCombineConditionals, \dbCombCond}
 % Environment to define conditionals and filters.
 % \begin{arguments}
 %   \item \meta{database}
 % \end{arguments}
 %    \begin{macrocode}
-\NewDocumentEnvironment { dbFilters } { m } {
-  \seq_gclear_new:c { g_@@_cond_seq_#1 }
+\NewDocumentEnvironment { dbFilters } { s m } {
+  \seq_if_exist:cF { g_@@_cond_seq_#2 }
+    { \seq_new:c { g_@@_cond_seq_#2 } }
 %    \end{macrocode}
 % \begin{arguments}[2]
 %   \item \meta{star}
-%   \item \meta{conditional}
+%   \item \meta{filter/conditional}
 %   \item \meta{attr}
 %   \item \meta{expr}
+%   \item \meta{filter info}
 % \end{arguments}
 %    \begin{macrocode}
-  \DeclareDocumentCommand { \dbNewConditional } { s m m m } {
-    \@@_new_conditional:nnnnn
-      {#1} {##2} {##3} {##4} {##1}
+  \DeclareDocumentCommand { \dbNewConditional } { s m m m O{} } {
+    \@@_new_conditional:nnnnn {#2} {##2} {##3} {##4} {##1}
+    \IfValueT {#1} {
+      \dbCombCond{##2}{##2}[##5]
+    }
   }
 %    \end{macrocode}
 % \begin{arguments}[2]
@@ -2829,13 +4062,36 @@
 % \end{arguments}
 %    \begin{macrocode}
   \DeclareDocumentCommand { \dbCombineConditionals } { m m O{} } {
-    \tl_gset:cn { g_@@_filter_info_tl_#1_##1 } {##3}
-    \@@_combine_conditional:nnn {#1} {##1} {##2}
+    \tl_gset:cn { g_@@_filter_info_tl_#2_##1 } {##3}
+    \@@_combine_conditional:nnn {#2} {##1} {##2}
   }
+  \cs_set_eq:NN \dbNewCond  \dbNewConditional
+  \cs_set_eq:NN \dbCombCond \dbCombineConditionals
 } {}
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\dbNewRawFilter, \dbNewRawFilter*}
+% Define filter with single conditional.
+% \begin{arguments}
+%   \item \meta{star}
+%   \item \meta{filter and conditional name}
+%   \item \meta{database}
+%   \item \meta{attr}
+%   \item \meta{expr}
+%   \item \meta{filter info}
+% \end{arguments}
+%    \begin{macrocode}
+\DeclareDocumentCommand { \dbNewRawFilter } { s m m m m O{} } {
+  \seq_if_exist:cF { g_@@_cond_seq_#3 }
+    { \seq_new:c { g_@@_cond_seq_#3 } }
+  \@@_new_conditional:nnnnn {#3} {#2} {#4} {#5} {#1}
+  \tl_gset:cn { g_@@_filter_info_tl_#3_#2 } {#6}
+  \@@_combine_conditional:nnn {#3} {#2} {#2}
+}
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\dbNewReviewPoints}
 % User interface to define \meta{review points}.
 % \begin{arguments}
@@ -2853,26 +4109,19 @@
 % \dbIntMax, \dbIntMin, \dbIntMod, \dbFpSign}
 % Function aliases to support more operations of integer and floating points.
 %    \begin{macrocode}
-\cs_set_eq:NN \dbIntAbs         \int_abs:n
-\cs_set_eq:NN \dbIntSign        \int_sign:n
-\cs_set_eq:NN \dbIntDivRound    \int_div_round:nn
-\cs_set_eq:NN \dbIntDivTruncate \int_div_truncate:nn
-\cs_set_eq:NN \dbIntMax         \int_max:nn
-\cs_set_eq:NN \dbIntMin         \int_min:nn
-\cs_set_eq:NN \dbIntMod         \int_mod:nn
-\cs_set_eq:NN \dbFpSign         \fp_sign:n
+\cs_gset_eq:NN \dbIntAbs         \int_abs:n
+\cs_gset_eq:NN \dbIntSign        \int_sign:n
+\cs_gset_eq:NN \dbIntDivRound    \int_div_round:nn
+\cs_gset_eq:NN \dbIntDivTruncate \int_div_truncate:nn
+\cs_gset_eq:NN \dbIntMax         \int_max:nn
+\cs_gset_eq:NN \dbIntMin         \int_min:nn
+\cs_gset_eq:NN \dbIntMod         \int_mod:nn
+\cs_gset_eq:NN \dbFpSign         \fp_sign:n
 %    \end{macrocode}
 % \end{macro}
 %
 % \subsection{Style and Options}
 %
-% \begin{macro}{\@@_identity:n}
-% Does nothing and keep things unchanged.
-%    \begin{macrocode}
-\cs_new:Nn \@@_identity:n {#1}
-%    \end{macrocode}
-% \end{macro}
-%
 % \begin{macro}{\@@_new_attr_style:nnn}
 % Define style keys for each attribute.
 % \begin{arguments}
@@ -2892,6 +4141,15 @@
       g_@@_style_attr_after_tl_#1_#2_#3
     },
     after-code       .initial:n    = ,
+    code             .code:n       = {
+      \bool_gset_false:c { g_@@_style_attr_exp_bool_#1_#2_#3 }
+      \cs_gset:cn { @@_style_attr_code_#1_#2_#3:n } {##1}
+    },
+    code             .initial:n    = {##1},
+    code*            .code:n       = {
+      \bool_gset_true:c  { g_@@_style_attr_exp_bool_#1_#2_#3 }
+      \cs_gset:cn { @@_style_attr_code_#1_#2_#3:n } {##1}
+    },
 %    \end{macrocode}
 % For comma list and date.
 %    \begin{macrocode}
@@ -2909,18 +4167,28 @@
       g_@@_style_attr_item_after_tl_#1_#2_#3
     },
     item-after-code  .initial:n    = ,
+    item-code        .code:n       = {
+      \bool_gset_false:c { g_@@_style_clist_item_exp_bool_#1_#2_#3 }
+      \cs_gset:cn { @@_style_clist_item_code_#1_#2_#3:n } {##1}
+    },
+    item-code        .initial:n    = {##1},
+    item-code*       .code:n       = {
+      \bool_gset_true:c  { g_@@_style_clist_item_exp_bool_#1_#2_#3 }
+      \cs_gset:cn { @@_style_clist_item_code_#1_#2_#3:n } {##1}
+    },
 %    \end{macrocode}
 % Only for date.
 %    \begin{macrocode}
     zfill            .bool_gset:c  = {
-      g_@@_style_attr_zfill_bool_#1_#2_#3
+      g_@@_style_date_zfill_bool_#1_#2_#3
     },
     zfill            .initial:n    = true,
     zfill            .default:n    = true,
-    wrapper          .tl_gset:c    = {
-      g_@@_style_attr_wrapper_#1_#2_#3
+    format-code      .code:n       = {
+      \cs_gset:cn { @@_style_date_format_code_#1_#2_#3:nnn } {##1}
+      \cs_generate_variant:cn
+        { @@_style_date_format_code_#1_#2_#3:nnn } { xxx }
     },
-    wrapper          .initial:n    = { \@@_identity:n },
   }
   \str_case_e:nn { \@@_get_type:nn {#2} {#3} } {
     { clist }
@@ -2947,21 +4215,28 @@
       \str_set:Nx \l_@@_raw_filter_str
         { -raw\int_use:N \g_@@_raw_filter_int - }
       \tl_gset:cV { g_@@_filter_#1_#2 } \l_@@_raw_filter_str
-      \@@_combine_conditional:nnn {#2}  \l_@@_raw_filter_str {##1}
+      \@@_combine_conditional:nVn {#2}  \l_@@_raw_filter_str {##1}
     },
-    filter             .tl_gset:c    = { g_@@_filter_#1_#2 },
-    filter             .initial:n    = -none-,
-    sort               .clist_gset:c = { g_@@_sort_clist_#1_#2 },
-    before-code        .tl_gset:c    = { g_@@_style_before_tl_#1_#2 },
-    before-code        .initial:n    = ,
-    item-code          .tl_gset:c    = { g_@@_style_database_item_tl_#1_#2 },
-    item-code          .initial:n    = ,
-    after-code         .tl_gset:c    = { g_@@_style_after_tl_#1_#2 },
-    after-code         .initial:n    = ,
-    record-before-code .tl_gset:c    = { g_@@_style_record_before_tl_#1_#2 },
-    record-before-code .initial:n    = ,
-    record-after-code  .tl_gset:c    = { g_@@_style_record_after_tl_#1_#2 },
-    record-after-code  .initial:n    = ,
+    filter           .tl_gset:c    = { g_@@_filter_#1_#2 },
+    filter           .initial:n    = -none-,
+    sort             .clist_gset:c = { g_@@_sort_clist_#1_#2 },
+    before-code      .tl_gset:c    = { g_@@_style_before_tl_#1_#2 },
+    before-code      .initial:n    = ,
+    after-code       .tl_gset:c    = { g_@@_style_after_tl_#1_#2 },
+    after-code       .initial:n    = ,
+    item-before-code .tl_gset:c    = { g_@@_style_item_before_tl_#1_#2 },
+    item-before-code .initial:n    = ,
+    item-after-code  .tl_gset:c    = { g_@@_style_item_after_tl_#1_#2 },
+    item-after-code  .initial:n    = ,
+    item-code        .code:n       = {
+      \bool_gset_false:c { g_@@_style_item_exp_bool_#1_#2 }
+      \tl_gset:cn { g_@@_style_item_tl_#1_#2 } {##1}
+    },
+    item-code        .initial:n    = ,
+    item-code*       .code:n       = {
+      \bool_gset_true:c { g_@@_style_item_exp_bool_#1_#2 }
+      \tl_gset:cn { g_@@_style_item_tl_#1_#2 } {##1}
+    },
   }
   \prop_map_inline:cn { g_@@_attr_type_prop_#2 }
     { \@@_new_attr_style:nnn {#1} {#2} {##1} }
@@ -2969,6 +4244,8 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \changes{1.5}{2022-01-15}{Add check}{check if database is valid in
+% \cs{dbNewStyle}}
 % \begin{macro}{\dbNewStyle}
 % Set style options based on \meta{base style}.
 % \begin{arguments}
@@ -2979,6 +4256,7 @@
 % \end{arguments}
 %    \begin{macrocode}
 \NewDocumentCommand { \dbNewStyle } { o m m +m } {
+  \@@_check_database:n {#3}
   \tl_gset:cn { g_@@_style_opts_tl_#2_#3 } { #4, }
   \IfValueT {#1} {
     \tl_clear_new:N \l_@@_style_tmp_tl
@@ -3070,7 +4348,7 @@
         { \@@_get_type:nV {#1} \l_@@_sort_attr_str }
       \clist_if_in:nVF
       { str, int, date, fp } { \l_@@_sort_type_tl } {
-        \msg_error:nnx { dbshow } { unsupported-sort-type }
+        \msg_fatal:nnx { dbshow } { unsupported-sort-type }
           { \l_@@_sort_type_tl }
       }
       \str_if_eq:eeT { \l_@@_sort_type_tl } { date }
@@ -3110,21 +4388,25 @@
 %
 % \subsection{Display Data}
 %
-% \begin{macro}{\@@_clist_wrapper:NNn}
+% \begin{macro}{\@@_clist_wrapper:NNNNn}
 % Wrap the clist item with \meta{before code} and \meta{after code}.
 % \begin{arguments}
 %   \item \meta{before code tl}
 %   \item \meta{after code tl}
+%   \item \meta{item code cs}
+%   \item \meta{exp boolean var}
 %   \item \meta{item}
 % \end{arguments}
 %    \begin{macrocode}
-\cs_new:Nn \@@_clist_wrapper:NNn {
-  \exp_not:n { { #1#3#2 }, }
+\cs_new:Nn \@@_clist_wrapper:NNNNn {
+  \bool_if:NTF #4
+    { \exp_not:n { { #1\exp_args:Nx#3{#5}#2 }, } }
+    { \exp_not:n { { #1#3{#5}#2 }, } }
 }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\@@_clist_use:NNNN, \@@_clist_use:cccc}
+% \begin{macro}{\@@_clist_use:NNNNNN, \@@_clist_use:cccccc}
 % Display a comma list.
 % \begin{arguments}
 %   \item \meta{data clist}
@@ -3131,30 +4413,32 @@
 %   \item \meta{separator clist}
 %   \item \meta{before code tl}
 %   \item \meta{after code tl}
+%   \item \meta{item code cs}
+%   \item \meta{exp boolean var}
 % \end{arguments}
 %    \begin{macrocode}
-\cs_new:Nn \@@_clist_use:NNNN {
+\cs_new:Nn \@@_clist_use:NNNNNN {
   \int_case:nnF { \clist_count:N #2 } {
     { 1 } {
       \clist_use:xx
-        { \clist_map_tokens:Nn #1 { \@@_clist_wrapper:NNn #3 #4 } }
+        { \clist_map_tokens:Nn #1 { \@@_clist_wrapper:NNNNn #3#4#5#6 } }
         { \clist_item:Nn #2 { 1 } }
     }
     { 3 } {
       \clist_use:xxxx
-        { \clist_map_tokens:Nn #1 { \@@_clist_wrapper:NNn #3 #4 } }
+        { \clist_map_tokens:Nn #1 { \@@_clist_wrapper:NNNNn #3#4#5#6 } }
         { \clist_item:Nn #2 { 1 } }
         { \clist_item:Nn #2 { 2 } }
         { \clist_item:Nn #2 { 3 } }
     }
   } {
-    \@@_sep_error:xxx
+    \@@_sep_fatal:xxx
       { 1~or~3 }
       { \clist_count:N #2 }
       { \clist_use:Nn #2 { ,~ } }
   }
 }
-\cs_generate_variant:Nn \@@_clist_use:NNNN { cccc }
+\cs_generate_variant:Nn \@@_clist_use:NNNNNN { cccccc }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -3186,7 +4470,7 @@
         { \clist_item:Nn #2 { 4 } }
     }
   } {
-    \@@_sep_error:xxx
+    \@@_sep_fatal:xxx
       { 1~or~4 }
       { \clist_count:N #2 }
       { \clist_use:Nn #2 { ,~ } }
@@ -3196,8 +4480,9 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\@@_use_data:nnnn}
-% Display Data.
+% \begin{macro}{\@@_use_data:nnnn, \@@_use_data_raw:nnnn}
+% Display Data. \cs{@@_use_data:nnnn} wrap the \meta{attr} data and
+% \cs{@@_use_data_raw:nnnn} display the underlying data.
 % \begin{arguments}
 %   \item \meta{database}
 %   \item \meta{attr}
@@ -3205,26 +4490,40 @@
 %   \item \meta{style}
 % \end{arguments}
 %    \begin{macrocode}
-% #1 database #2 attr #3 index #4 style
 \cs_new:Nn \@@_use_data:nnnn {
+  \bool_if:cTF { g_@@_style_attr_exp_bool_#4_#1_#2 } {
+    \protected at edef\@dbshow at tmp{\@@_use_data_raw:nnnn {#1} {#2} {#3} {#4}}
+    \exp_args:Nno
+    \use:c { @@_style_attr_code_#4_#1_#2:n } { \@dbshow at tmp }
+  } {
+    \use:c { @@_style_attr_code_#4_#1_#2:n }
+    { \@@_use_data_raw:nnnn {#1} {#2} {#3} {#4} }
+  }
+}
+\cs_new:Nn \@@_use_data_raw:nnnn {
   \str_case_e:nn
   { \prop_item:cn { g_@@_attr_type_prop_#1 } {#2} } {
     { str }   { \str_use:c { g_@@_data_#1_#2_#3 } }
-    { tl }    { \tl_use:c { g_@@_data_#1_#2_#3 } }
+    { tl }    { \tl_use:c  { g_@@_data_#1_#2_#3 } }
     { int }   { \int_use:c { g_@@_data_#1_#2_#3 } }
-    { fp }    { \fp_use:c { g_@@_data_#1_#2_#3 } }
+    { fp }    { \fp_use:c  { g_@@_data_#1_#2_#3 } }
     { clist } {
-      \@@_clist_use:cccc { g_@@_data_#1_#2_#3 }
+      \@@_clist_use:cccccc { g_@@_data_#1_#2_#3 }
         { g_@@_style_attr_sep_#4_#1_#2 }
         { g_@@_style_attr_item_before_tl_#4_#1_#2 }
-        { g_@@_style_attr_item_after_tl_#4_#1_#2 }
+        { g_@@_style_attr_item_after_ tl_#4_#1_#2 }
+        {   @@_style_clist_item_code_    #4_#1_#2:n }
+        { g_@@_style_clist_item_exp_bool_#4_#1_#2 }
     }
     { date }  {
-      \exp_args:Nnx
-      \tl_use:c { g_@@_style_attr_wrapper_#4_#1_#2 } {
+      \cs_if_exist_use:cTF { @@_style_date_format_code_#4_#1_#2:xxx } {
+        { \__dbdate_get_year:n  { g_@@_data_#1_#2_#3 } }
+        { \__dbdate_get_month:n { g_@@_data_#1_#2_#3 } }
+        { \__dbdate_get_day:n   { g_@@_data_#1_#2_#3 } }
+      } {
         \@@_date_use:ncc { g_@@_data_#1_#2_#3 }
           { g_@@_style_attr_sep_#4_#1_#2 }
-          { g_@@_style_attr_zfill_bool_#4_#1_#2 }
+          { g_@@_style_date_zfill_bool_#4_#1_#2 }
       }
     }
   }
@@ -3247,7 +4546,7 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}{\@@_show_filter:nn}
+% \begin{macro}{\@@_show_filter:nnN}
 % Filter records by executing the hook function in the running sequence and
 % then testing the result boolean.
 % \begin{arguments}
@@ -3289,15 +4588,35 @@
 % \end{arguments}
 %    \begin{macrocode}
 \cs_new_protected:Nn \@@_show_set_counter:N {
-  \tl_set:Nx \dbalph   { \int_to_alph:n {#1} }
-  \tl_set:Nx \dbAlph   { \int_to_Alph:n {#1} }
+  \tl_set:Nx \dbalph   { \int_to_alph:n   {#1} }
+  \tl_set:Nx \dbAlph   { \int_to_Alph:n   {#1} }
   \tl_set:Nx \dbarabic { \int_to_arabic:n {#1} }
-  \tl_set:Nx \dbRoman  { \int_to_Roman:n {#1} }
-  \tl_set:Nx \dbroman  { \int_to_roman:n {#1} }
+  \tl_set:Nx \dbRoman  { \int_to_Roman:n  {#1} }
+  \tl_set:Nx \dbroman  { \int_to_roman:n  {#1} }
 }
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\@@_show_set_if_last:NN, \dbIfLastT, \dbIfLastF, \dbIfLastTF}
+% Define conditional to check if the current item is the last item.
+% \begin{arguments}
+%   \item \meta{current index}
+%   \item \meta{count}
+% \end{arguments}
+%    \begin{macrocode}
+\cs_new_protected:Nn \@@_show_set_if_last:NN {
+  \prg_set_conditional:Nnn \@@_show_if_last: { T, F, TF } {
+    \int_compare:nNnTF {#1} = {#2}
+      { \prg_return_true: }
+      { \prg_return_false: }
+  }
+  \cs_set_eq:NN \dbIfLastT  \@@_show_if_last:T
+  \cs_set_eq:NN \dbIfLastF  \@@_show_if_last:F
+  \cs_set_eq:NN \dbIfLastTF \@@_show_if_last:TF
+}
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\@@_show_item:nn, \dbIndex, \dbuse}
 % Display single record.
 % \begin{arguments}
@@ -3308,6 +4627,9 @@
 %    \begin{macrocode}
 \cs_new_protected:Nn \@@_show_item:nnN {
   \int_zero_new:N \l_@@_show_int
+  \int_zero_new:N \l_@@_show_count_int
+  \int_set:Nn \l_@@_show_count_int { \clist_count:N #3 }
+  \tl_clear_new:N \l_@@_item_tl
 %    \end{macrocode}
 % \begin{arguments}[2]
 %   \item \meta{index}
@@ -3315,7 +4637,8 @@
 %    \begin{macrocode}
   \clist_map_inline:Nn #3 {
     \int_incr:N \l_@@_show_int
-    \@@_show_set_counter:N \l_@@_show_int
+    \@@_show_set_if_last:NN \l_@@_show_int \l_@@_show_count_int
+    \@@_show_set_counter:N  \l_@@_show_int
     \tl_set:Nn \dbIndex {##1}
 %    \end{macrocode}
 % \begin{arguments}[3]
@@ -3326,12 +4649,21 @@
       \@@_check_attr:nn {#2} {####1}
       \tl_use:c { g_@@_style_attr_before_tl_#1_#2_####1 }
       \@@_use_data:nnnn {#2} {####1} {##1} {#1}
-      \tl_use:c { g_@@_style_attr_after_tl_#1_#2_####1 }
+      \tl_use:c { g_@@_style_attr_after_ tl_#1_#2_####1 }
     }
-    \tl_use:c { g_@@_style_record_before_tl_#1_#2 }
-    \tl_use:c { g_@@_style_database_item_tl_#1_#2 }
-    \tl_use:c { g_@@_style_record_after_tl_#1_#2 }
+    \bool_if:cTF { g_@@_style_item_exp_bool_#1_#2 } {
+      \protected at edef\@dbshow at tmp{\tl_use:c { g_@@_style_item_before_tl_#1_#2 }}
+      \tl_put_right:No \l_@@_item_tl { \@dbshow at tmp }
+      \protected at edef\@dbshow at tmp{\tl_use:c { g_@@_style_item_       tl_#1_#2 }}
+      \tl_put_right:No \l_@@_item_tl { \@dbshow at tmp }
+      \protected at edef\@dbshow at tmp{\tl_use:c { g_@@_style_item_after_ tl_#1_#2 }}
+    } {
+      \tl_use:c { g_@@_style_item_before_tl_#1_#2 }
+      \tl_use:c { g_@@_style_item_       tl_#1_#2 }
+      \tl_use:c { g_@@_style_item_after_ tl_#1_#2 }
+    }
   }
+  \l_@@_item_tl
 }
 %    \end{macrocode}
 % \end{macro}
@@ -3355,8 +4687,14 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \changes{1.5}{2022-01-15}{Fix bug}{\cs{dbIfEmptyF} undefined}
 % \begin{macro}{\@@_show:nnn, \@@_show:nnv}
 % First filter records and sort them if needed and display at last.
+% \begin{arguments}
+%   \item \meta{style}
+%   \item \meta{database}
+%   \item \meta{filter}
+% \end{arguments}
 %    \begin{macrocode}
 \cs_new_protected:Nn \@@_show:nnn {
   \@@_show_set_macro:nn {#2} {#3}
@@ -3364,6 +4702,7 @@
   \@@_show_filter:nnN {#2} {#3} \l_@@_show_index_clist
   \clist_if_empty:cF { g_@@_sort_clist_#1_#2 }
     { \@@_sort:nNn {#2} \l_@@_show_index_clist {#1} }
+  \@@_show_set_cond:N \l_@@_show_index_clist
   \tl_use:c { g_@@_style_before_tl_#1_#2 }
   \@@_show_item:nnN {#1} {#2} \l_@@_show_index_clist
   \tl_use:c { g_@@_style_after_tl_#1_#2 }
@@ -3381,8 +4720,9 @@
 %    \begin{macrocode}
 \NewDocumentCommand { \dbshow } { m m } {
   \@@_check_database:n {#2}
-  \@@_check_filter:nv {#2} { g_@@_filter_#1_#2 }
-  \@@_show:nnv {#1} {#2} { g_@@_filter_#1_#2 }
+  \@@_check_style:nn   {#1} {#2}
+  \@@_check_filter:nv  {#2} { g_@@_filter_#1_#2 }
+  \@@_show:nnv {#1}    {#2} { g_@@_filter_#1_#2 }
 }
 %    \end{macrocode}
 % \end{macro}
@@ -3393,6 +4733,38 @@
 %<@@=dbdate>
 %    \end{macrocode}
 %
+% \begin{arguments}
+%   \item \meta{date}
+%   \item \meta{date sep}
+% \end{arguments}
+%    \begin{macrocode}
+\msg_new:nnn { dbshow } { wrong-date-sep } {
+  can~not~parse~the~date~'#1'~with~the~global~date~separator~'#2'~
+  \msg_line_context:.~Please~set~the~correct~date~separator~with~
+  \dbdatesep.
+}
+%    \end{macrocode}
+%
+% \begin{macro}{\@@_check_date_sep:nn, \@@_check_date_sep:Vn}
+% Check if the global date separator is valid.
+% \begin{arguments}
+%   \item \meta{date}
+%   \item \meta{date sep}
+% \end{arguments}
+%    \begin{macrocode}
+\cs_new:Nn \@@_check_date_sep:nn {
+  \int_zero_new:N \l_@@_sep_int
+  \tl_map_inline:nn {#1} {
+    \tl_if_eq:nnT {#2} {##1} { \int_incr:N \l_@@_sep_int }
+    \int_compare:nNnT { \l_@@_sep_int } > { 2 } { \tl_map_break: }
+  }
+  \int_compare:nNnF { \l_@@_sep_int } = { 2 }
+    { \msg_fatal:nnnn { dbshow } { wrong-date-sep } {#1} {#2} }
+}
+\cs_generate_variant:Nn \@@_check_date_sep:nn { nV }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}[pTF]{\@@_if_leap:n}
 % Check if the year is leap.
 % \begin{arguments}
@@ -3563,6 +4935,28 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}{\@@_get_year:n, \@@_get_year:x, \@@_get_month:n,
+% \@@_get_month:x, \@@_get_day:n, \@@_get_day:x}
+% Extract year, month or day from \meta{date var}.
+% \begin{arguments}
+%   \item \meta{date var}
+% \end{arguments}
+%    \begin{macrocode}
+\cs_new:Nn \@@_get_year:n {
+  \int_use:c { @@_year_#1 }
+}
+\cs_new:Nn \@@_get_month:n {
+  \int_use:c { @@_month_#1 }
+}
+\cs_new:Nn \@@_get_day:n {
+  \int_use:c { @@_day_#1 }
+}
+\cs_generate_variant:Nn \@@_get_year:n  { x }
+\cs_generate_variant:Nn \@@_get_month:n { x }
+\cs_generate_variant:Nn \@@_get_day:n   { x }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\@@_set:nnnn, \@@_gset:nnnn}
 % Set the value of \meta{date var}.
 % \begin{arguments}
@@ -3626,10 +5020,12 @@
 % \end{arguments}
 %    \begin{macrocode}
 \cs_new_protected:Nn \@@_set:nn {
+  \@@_check_date_sep:nV {#2} \g_@@_sep_tl
   \@@_set:w #1\@@_sep#2\@@_stop
 }
 \cs_generate_variant:Nn \@@_set:nn { xx }
 \cs_new_protected:Nn \@@_gset:nn {
+  \@@_check_date_sep:nV {#2} \g_@@_sep_tl
   \@@_gset:w #1\@@_sep#2\@@_stop
 }
 \cs_generate_variant:Nn \@@_gset:nn { xx }

Modified: trunk/Master/texmf-dist/tex/latex/dbshow/dbshow.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/dbshow/dbshow.sty	2022-01-17 20:56:07 UTC (rev 61633)
+++ trunk/Master/texmf-dist/tex/latex/dbshow/dbshow.sty	2022-01-17 20:56:22 UTC (rev 61634)
@@ -31,15 +31,16 @@
 %%     --------------------------------------------------------------------------
 %% 
 \NeedsTeXFormat{LaTeX2e}
-\GetIdInfo$Id: dbshow.dtx 461d9bb 2022-01-14 02:50:24 +0800 Changkai Li <lichangkai225 at qq.com> $
+\GetIdInfo$Id: dbshow.dtx 1a507c4 2022-01-17 22:53:24 +0800 Changkai Li <lichangkai225 at qq.com> $
   {Database to store and display data}
 \ProvidesExplPackage{\ExplFileName}
-  {\ExplFileDate}{1.4}{\ExplFileDescription}
+  {\ExplFileDate}{1.5}{\ExplFileDescription}
 \__kernel_dependency_version_check:nn { 2021-11-07 } { l3prop }
 \__kernel_dependency_version_check:nn { 2021-05-17 } { l3str }
 \__kernel_dependency_version_check:nn { 2021-05-10 } { l3clist }
 \cs_generate_variant:Nn \msg_warning:nnnn      { nnnx }
 \cs_generate_variant:Nn \keys_set:nn           { nv }
+\cs_generate_variant:Nn \tl_put_right:Nn       { Nv }
 \cs_generate_variant:Nn \clist_use:nn          { xx }
 \cs_generate_variant:Nn \clist_use:nnnn        { xxxx }
 \cs_generate_variant:Nn \clist_map_inline:nn   { Vn }
@@ -65,7 +66,7 @@
   Database~'#1'~does~not~exist~\msg_line_context:.
 }
 \cs_new:Nn \__dbshow_check_database:n {
-  \prop_if_exist:cF { g__dbshow_attr_type_prop_#1 }
+  \prop_if_exist:cF { g__dbshow_attr_type_prop_\tl_to_str:n {#1} }
     { \msg_fatal:nnn { dbshow } { non-existent-database } {#1} }
 }
 \msg_new:nnn { dbshow } { non-existent-attr } {
@@ -72,7 +73,7 @@
   Attribute~'#2'~of~database~'#1'~does~not~exist~\msg_line_context:.
 }
 \cs_new:Nn \__dbshow_check_attr:nn {
-  \prop_if_in:cnF { g__dbshow_attr_type_prop_#1 } {#2}
+  \prop_if_in:cnF { g__dbshow_attr_type_prop_\tl_to_str:n {#1} } {#2}
     { \msg_fatal:nnnn { dbshow } { non-existent-attr } {#1} {#2} }
 }
 \cs_generate_variant:Nn \__dbshow_check_attr:nn { nV }
@@ -80,14 +81,14 @@
   Style~'#1'~of~database~'#2'~does~not~exist~\msg_line_context:.
 }
 \cs_new:Nn \__dbshow_check_style:nn {
-  \tl_if_exist:cF { g__dbshow_style_opts_tl_#1_#2 }
-    { \msg_warning:nnnn { dbshow } { non-existent-style } {#1} {#2} }
+  \tl_if_exist:cF { g__dbshow_style_opts_tl_\tl_to_str:n {#1}_\tl_to_str:n {#2} }
+    { \msg_fatal:nnnn { dbshow } { non-existent-style } {#1} {#2} }
 }
 \msg_new:nnn { dbshow } { non-existent-cond } {
   Conditional~'#2'~of~database~'#1'~does~not~exist~\msg_line_context:.
 }
 \cs_new:Nn \__dbshow_check_cond:nnn {
-  \tl_if_exist:cF { g__dbshow_filter_attr_#1_#2 }
+  \tl_if_exist:cF { g__dbshow_filter_attr_\tl_to_str:n {#1}_\tl_to_str:n {#2} }
     { \msg_fatal:nnnn { dbshow } { non-existent-cond } {#1} {#2} }
 }
 \msg_new:nnn { dbshow } { non-existent-filter } {
@@ -94,7 +95,8 @@
   Filter~'#2'~of~database~'#1'~does~not~exist~and~is~ignored~\msg_line_context:.
 }
 \cs_new:Nn \__dbshow_check_filter:nn {
-  \seq_if_exist:cF { g__dbshow_filter_run_seq_#1_#2 } {
+  \seq_if_exist:cF
+  { g__dbshow_filter_run_seq_\tl_to_str:n {#1}_\tl_to_str:n {#2} } {
     \str_if_eq:eeF {#2} { -none- } {
       \msg_warning:nnnx { dbshow } { non-existent-filter } {#1} {#2}
     }
@@ -113,10 +115,10 @@
   option~'sep'~should~contain~#1~items~but~only~#2~items~was~given,~
   sep~=~\{#3\}~\msg_line_context:.
 }
-\cs_new:Nn \__dbshow_sep_error:nnn {
-  \msg_error:nnnnn { dbshow } { wrong-seperator } {#1} {#2} {#3}
+\cs_new:Nn \__dbshow_sep_fatal:nnn {
+  \msg_fatal:nnnnn { dbshow } { wrong-seperator } {#1} {#2} {#3}
 }
-\cs_generate_variant:Nn \__dbshow_sep_error:nnn { xxx }
+\cs_generate_variant:Nn \__dbshow_sep_fatal:nnn { xxx }
 \msg_new:nnn { dbshow } { unsupported-sort-type } {
   unsupported~sort~type:~'#1'~\msg_line_context:.~The~type~should~be~one~of~
   \{str,~date,~int,~fp\}.
@@ -125,7 +127,7 @@
 #1\__dbshow_sep#2\__dbshow_sep#3|#4\__dbshow_stop {
   \__dbshow_check_type:n {#3}
   \prop_gput:cxx { g__dbshow_attr_type_prop_#1 } {#2} {#3}
-  \prop_gput:cxx { g__dbshow_default_map_#1 } {#2} {#4}
+  \prop_gput:cno { g__dbshow_default_map_#1 } {#2} {#4}
 }
 \cs_new_protected:Nn \__dbshow_process_attr_type_prop:n {
   \prop_gclear_new:c { g__dbshow_default_map_#1 }
@@ -266,7 +268,7 @@
   \regex_match:VVTF #2 #3 {#4} {#5}
 }
 \cs_generate_variant:Nn \__dbshow_filter_str:NNNnn { cccnn }
-\cs_set_eq:NN \__dbshow_filter_tl:NNNnn \__dbshow_filter_str:NNNnn
+\cs_gset_eq:NN \__dbshow_filter_tl:NNNnn \__dbshow_filter_str:NNNnn
 \cs_generate_variant:Nn \__dbshow_filter_tl:NNNnn { cccnn }
 \cs_new_protected:Npn \__dbshow_parse_date_cond:NNw #1#2#3|#4\__dbshow_stop {
   \clist_set_eq:Nc #1 { g__review_points_#3 }
@@ -282,8 +284,11 @@
     \__dbdate_set:xx { tmp_day1 } { \l__dbshow_filter_tmp_tl }
     \__dbdate_set:xx { tmp_day2 } {#3}
     \__dbdate_sub:nnN { tmp_day1 } { tmp_day2 } \l__dbshow_filter_diff_int
-    \clist_if_in:NxTF \l__dbshow_filter_tmp_clist
-      { \int_use:N \l__dbshow_filter_diff_int } {#4} {#5}
+    #5
+    \clist_map_inline:Nn \l__dbshow_filter_tmp_clist {
+      \int_compare:nNnT { \l__dbshow_filter_diff_int } = {##1}
+        { #4 \clist_map_break: }
+    }
   } {
     \int_zero_new:N \l__dbshow_filter_tmpa_int
     \int_zero_new:N \l__dbshow_filter_tmpb_int
@@ -313,11 +318,12 @@
   }
 }
 \cs_generate_variant:Nn \__dbshow_filter_date:NNNnn { cccnn }
-\cs_set:Nn \__dbshow_filter:nnn {
+\cs_new_protected:Nn \__dbshow_filter:nnn {
   \tl_set_eq:Nc \l__dbshow_attr_tl { g__dbshow_filter_attr_tl_#1_#2 }
   \cs_set_eq:Nc \dbval { g__dbshow_data_#1_\l__dbshow_attr_tl _#3 }
+  \tl_set:Nx \l__dbshow_type_tl { \__dbshow_get_type:nV {#1} \l__dbshow_attr_tl }
   \use:c
-    { __dbshow_filter_\__dbshow_get_type:nV {#1} \l__dbshow_attr_tl :cccnn }
+    { __dbshow_filter_\l__dbshow_type_tl :cccnn }
     { g__dbshow_cond_star_bool_#1_#2 }
     { g__dbshow_filter_expr_tl_#1_#2 }
     { dbval }
@@ -325,6 +331,8 @@
     { \bool_gset_false:c { g__dbshow_filter_bool_#1_#2 } }
 }
 \cs_new_protected:Nn \__dbshow_new_conditional:nnnnn {
+  \__dbshow_check_database:n {#1}
+  \__dbshow_check_attr:nn {#1} {#3}
   \tl_gset:cn { g__dbshow_filter_attr_tl_#1_#2 } {#3}
   \tl_gset:cn { g__dbshow_filter_expr_tl_#1_#2 } {#4}
   \bool_if_exist:cF { g__dbshow_filter_bool_#1_#2 }
@@ -337,49 +345,68 @@
   \cs_gset:cn { g__dbshow_filter_hook_#1_#2:n } {
     \__dbshow_filter:nnn {#1} {#2} {##1}
   }
-  \seq_gput_right:cn { g__dbshow_cond_seq_#1 } {#2}
+  \bool_if_exist:cF { g__dbshow_cond_exist_bool_#1_#2 }
+    { \bool_set_false:c { g__dbshow_cond_exist_bool_#1_#2 } }
+  \bool_if:cF { g__dbshow_cond_exist_bool_#1_#2 }
+    { \seq_gput_right:cn { g__dbshow_cond_seq_#1 } {#2} }
 }
 \cs_new_protected:Nn \__dbshow_combine_conditional:nnn {
   \tl_gset_eq:cN { g__dbshow_filter_bool_tl_#1_#2 } \c_true_bool
   \seq_gclear_new:c { g__dbshow_filter_run_seq_#1_#2 }
-  \regex_extract_all:nnN { \w+ } {#3} \l__dbshow_cond_seq
+  \regex_extract_all:nnN { [^!=&<>()\ ]+ } {#3} \l__dbshow_cond_seq
   \seq_map_inline:Nn \l__dbshow_cond_seq {
     \seq_if_in:cnT { g__dbshow_cond_seq_#1 } {##1} {
-      \seq_gput_right:cn { g__dbshow_filter_run_seq_#1_#2 }
+      \seq_if_in:cnF { g__dbshow_filter_run_seq_#1_#2 }
         { g__dbshow_filter_hook_#1_##1:n }
+      {
+        \seq_gput_right:cn { g__dbshow_filter_run_seq_#1_#2 }
+          { g__dbshow_filter_hook_#1_##1:n }
+      }
     }
   }
   \tl_set:Nn \l__dbshow_cond_expr_tl {#3}
   \regex_replace_all:nnN
-    { \w+ } { \c{ g__dbshow_filter_bool_#1_\0 } }
+    { (\w|-|\d|\_)+ }
+    { \c{ g__dbshow_filter_bool_#1_\0 } }
     \l__dbshow_cond_expr_tl
   \tl_gset_eq:cN
     { g__dbshow_filter_bool_tl_#1_#2 } \l__dbshow_cond_expr_tl
 }
 \cs_generate_variant:Nn \__dbshow_combine_conditional:nnn { nVn }
-\NewDocumentEnvironment { dbFilters } { m } {
-  \seq_gclear_new:c { g__dbshow_cond_seq_#1 }
-  \DeclareDocumentCommand { \dbNewConditional } { s m m m } {
-    \__dbshow_new_conditional:nnnnn
-      {#1} {##2} {##3} {##4} {##1}
+\NewDocumentEnvironment { dbFilters } { s m } {
+  \seq_if_exist:cF { g__dbshow_cond_seq_#2 }
+    { \seq_new:c { g__dbshow_cond_seq_#2 } }
+  \DeclareDocumentCommand { \dbNewConditional } { s m m m O{} } {
+    \__dbshow_new_conditional:nnnnn {#2} {##2} {##3} {##4} {##1}
+    \IfValueT {#1} {
+      \dbCombCond{##2}{##2}[##5]
+    }
   }
   \DeclareDocumentCommand { \dbCombineConditionals } { m m O{} } {
-    \tl_gset:cn { g__dbshow_filter_info_tl_#1_##1 } {##3}
-    \__dbshow_combine_conditional:nnn {#1} {##1} {##2}
+    \tl_gset:cn { g__dbshow_filter_info_tl_#2_##1 } {##3}
+    \__dbshow_combine_conditional:nnn {#2} {##1} {##2}
   }
+  \cs_set_eq:NN \dbNewCond  \dbNewConditional
+  \cs_set_eq:NN \dbCombCond \dbCombineConditionals
 } {}
+\DeclareDocumentCommand { \dbNewRawFilter } { s m m m m O{} } {
+  \seq_if_exist:cF { g__dbshow_cond_seq_#3 }
+    { \seq_new:c { g__dbshow_cond_seq_#3 } }
+  \__dbshow_new_conditional:nnnnn {#3} {#2} {#4} {#5} {#1}
+  \tl_gset:cn { g__dbshow_filter_info_tl_#3_#2 } {#6}
+  \__dbshow_combine_conditional:nnn {#3} {#2} {#2}
+}
 \NewDocumentCommand { \dbNewReviewPoints } { m m } {
   \clist_set:cn { g__review_points_#1 } {#2}
 }
-\cs_set_eq:NN \dbIntAbs         \int_abs:n
-\cs_set_eq:NN \dbIntSign        \int_sign:n
-\cs_set_eq:NN \dbIntDivRound    \int_div_round:nn
-\cs_set_eq:NN \dbIntDivTruncate \int_div_truncate:nn
-\cs_set_eq:NN \dbIntMax         \int_max:nn
-\cs_set_eq:NN \dbIntMin         \int_min:nn
-\cs_set_eq:NN \dbIntMod         \int_mod:nn
-\cs_set_eq:NN \dbFpSign         \fp_sign:n
-\cs_new:Nn \__dbshow_identity:n {#1}
+\cs_gset_eq:NN \dbIntAbs         \int_abs:n
+\cs_gset_eq:NN \dbIntSign        \int_sign:n
+\cs_gset_eq:NN \dbIntDivRound    \int_div_round:nn
+\cs_gset_eq:NN \dbIntDivTruncate \int_div_truncate:nn
+\cs_gset_eq:NN \dbIntMax         \int_max:nn
+\cs_gset_eq:NN \dbIntMin         \int_min:nn
+\cs_gset_eq:NN \dbIntMod         \int_mod:nn
+\cs_gset_eq:NN \dbFpSign         \fp_sign:n
 \cs_new_protected:Nn \__dbshow_new_attr_style:nnn {
   \__dbshow_check_attr:nn {#2} {#3}
   \keys_define:nn { dbshow/style/#1/#3 } {
@@ -391,6 +418,15 @@
       g__dbshow_style_attr_after_tl_#1_#2_#3
     },
     after-code       .initial:n    = ,
+    code             .code:n       = {
+      \bool_gset_false:c { g__dbshow_style_attr_exp_bool_#1_#2_#3 }
+      \cs_gset:cn { __dbshow_style_attr_code_#1_#2_#3:n } {##1}
+    },
+    code             .initial:n    = {##1},
+    code*            .code:n       = {
+      \bool_gset_true:c  { g__dbshow_style_attr_exp_bool_#1_#2_#3 }
+      \cs_gset:cn { __dbshow_style_attr_code_#1_#2_#3:n } {##1}
+    },
     sep              .clist_gset:c = {
       g__dbshow_style_attr_sep_#1_#2_#3
     },
@@ -402,15 +438,25 @@
       g__dbshow_style_attr_item_after_tl_#1_#2_#3
     },
     item-after-code  .initial:n    = ,
+    item-code        .code:n       = {
+      \bool_gset_false:c { g__dbshow_style_clist_item_exp_bool_#1_#2_#3 }
+      \cs_gset:cn { __dbshow_style_clist_item_code_#1_#2_#3:n } {##1}
+    },
+    item-code        .initial:n    = {##1},
+    item-code*       .code:n       = {
+      \bool_gset_true:c  { g__dbshow_style_clist_item_exp_bool_#1_#2_#3 }
+      \cs_gset:cn { __dbshow_style_clist_item_code_#1_#2_#3:n } {##1}
+    },
     zfill            .bool_gset:c  = {
-      g__dbshow_style_attr_zfill_bool_#1_#2_#3
+      g__dbshow_style_date_zfill_bool_#1_#2_#3
     },
     zfill            .initial:n    = true,
     zfill            .default:n    = true,
-    wrapper          .tl_gset:c    = {
-      g__dbshow_style_attr_wrapper_#1_#2_#3
+    format-code      .code:n       = {
+      \cs_gset:cn { __dbshow_style_date_format_code_#1_#2_#3:nnn } {##1}
+      \cs_generate_variant:cn
+        { __dbshow_style_date_format_code_#1_#2_#3:nnn } { xxx }
     },
-    wrapper          .initial:n    = { \__dbshow_identity:n },
   }
   \str_case_e:nn { \__dbshow_get_type:nn {#2} {#3} } {
     { clist }
@@ -427,26 +473,34 @@
       \str_set:Nx \l__dbshow_raw_filter_str
         { -raw\int_use:N \g__dbshow_raw_filter_int - }
       \tl_gset:cV { g__dbshow_filter_#1_#2 } \l__dbshow_raw_filter_str
-      \__dbshow_combine_conditional:nnn {#2}  \l__dbshow_raw_filter_str {##1}
+      \__dbshow_combine_conditional:nVn {#2}  \l__dbshow_raw_filter_str {##1}
     },
-    filter             .tl_gset:c    = { g__dbshow_filter_#1_#2 },
-    filter             .initial:n    = -none-,
-    sort               .clist_gset:c = { g__dbshow_sort_clist_#1_#2 },
-    before-code        .tl_gset:c    = { g__dbshow_style_before_tl_#1_#2 },
-    before-code        .initial:n    = ,
-    item-code          .tl_gset:c    = { g__dbshow_style_database_item_tl_#1_#2 },
-    item-code          .initial:n    = ,
-    after-code         .tl_gset:c    = { g__dbshow_style_after_tl_#1_#2 },
-    after-code         .initial:n    = ,
-    record-before-code .tl_gset:c    = { g__dbshow_style_record_before_tl_#1_#2 },
-    record-before-code .initial:n    = ,
-    record-after-code  .tl_gset:c    = { g__dbshow_style_record_after_tl_#1_#2 },
-    record-after-code  .initial:n    = ,
+    filter           .tl_gset:c    = { g__dbshow_filter_#1_#2 },
+    filter           .initial:n    = -none-,
+    sort             .clist_gset:c = { g__dbshow_sort_clist_#1_#2 },
+    before-code      .tl_gset:c    = { g__dbshow_style_before_tl_#1_#2 },
+    before-code      .initial:n    = ,
+    after-code       .tl_gset:c    = { g__dbshow_style_after_tl_#1_#2 },
+    after-code       .initial:n    = ,
+    item-before-code .tl_gset:c    = { g__dbshow_style_item_before_tl_#1_#2 },
+    item-before-code .initial:n    = ,
+    item-after-code  .tl_gset:c    = { g__dbshow_style_item_after_tl_#1_#2 },
+    item-after-code  .initial:n    = ,
+    item-code        .code:n       = {
+      \bool_gset_false:c { g__dbshow_style_item_exp_bool_#1_#2 }
+      \tl_gset:cn { g__dbshow_style_item_tl_#1_#2 } {##1}
+    },
+    item-code        .initial:n    = ,
+    item-code*       .code:n       = {
+      \bool_gset_true:c { g__dbshow_style_item_exp_bool_#1_#2 }
+      \tl_gset:cn { g__dbshow_style_item_tl_#1_#2 } {##1}
+    },
   }
   \prop_map_inline:cn { g__dbshow_attr_type_prop_#2 }
     { \__dbshow_new_attr_style:nnn {#1} {#2} {##1} }
 }
 \NewDocumentCommand { \dbNewStyle } { o m m +m } {
+  \__dbshow_check_database:n {#3}
   \tl_gset:cn { g__dbshow_style_opts_tl_#2_#3 } { #4, }
   \IfValueT {#1} {
     \tl_clear_new:N \l__dbshow_style_tmp_tl
@@ -497,7 +551,7 @@
         { \__dbshow_get_type:nV {#1} \l__dbshow_sort_attr_str }
       \clist_if_in:nVF
       { str, int, date, fp } { \l__dbshow_sort_type_tl } {
-        \msg_error:nnx { dbshow } { unsupported-sort-type }
+        \msg_fatal:nnx { dbshow } { unsupported-sort-type }
           { \l__dbshow_sort_type_tl }
       }
       \str_if_eq:eeT { \l__dbshow_sort_type_tl } { date }
@@ -526,31 +580,33 @@
     \__dbshow_sort_single:
   }
 }
-\cs_new:Nn \__dbshow_clist_wrapper:NNn {
-  \exp_not:n { { #1#3#2 }, }
+\cs_new:Nn \__dbshow_clist_wrapper:NNNNn {
+  \bool_if:NTF #4
+    { \exp_not:n { { #1\exp_args:Nx#3{#5}#2 }, } }
+    { \exp_not:n { { #1#3{#5}#2 }, } }
 }
-\cs_new:Nn \__dbshow_clist_use:NNNN {
+\cs_new:Nn \__dbshow_clist_use:NNNNNN {
   \int_case:nnF { \clist_count:N #2 } {
     { 1 } {
       \clist_use:xx
-        { \clist_map_tokens:Nn #1 { \__dbshow_clist_wrapper:NNn #3 #4 } }
+        { \clist_map_tokens:Nn #1 { \__dbshow_clist_wrapper:NNNNn #3#4#5#6 } }
         { \clist_item:Nn #2 { 1 } }
     }
     { 3 } {
       \clist_use:xxxx
-        { \clist_map_tokens:Nn #1 { \__dbshow_clist_wrapper:NNn #3 #4 } }
+        { \clist_map_tokens:Nn #1 { \__dbshow_clist_wrapper:NNNNn #3#4#5#6 } }
         { \clist_item:Nn #2 { 1 } }
         { \clist_item:Nn #2 { 2 } }
         { \clist_item:Nn #2 { 3 } }
     }
   } {
-    \__dbshow_sep_error:xxx
+    \__dbshow_sep_fatal:xxx
       { 1~or~3 }
       { \clist_count:N #2 }
       { \clist_use:Nn #2 { ,~ } }
   }
 }
-\cs_generate_variant:Nn \__dbshow_clist_use:NNNN { cccc }
+\cs_generate_variant:Nn \__dbshow_clist_use:NNNNNN { cccccc }
 \cs_new:Nn \__dbshow_date_use:nNN {
   \int_case:nnF { \clist_count:N #2 } {
     { 1 } {
@@ -571,7 +627,7 @@
         { \clist_item:Nn #2 { 4 } }
     }
   } {
-    \__dbshow_sep_error:xxx
+    \__dbshow_sep_fatal:xxx
       { 1~or~4 }
       { \clist_count:N #2 }
       { \clist_use:Nn #2 { ,~ } }
@@ -579,24 +635,39 @@
 }
 \cs_generate_variant:Nn \__dbshow_date_use:nNN { ncc }
 \cs_new:Nn \__dbshow_use_data:nnnn {
+  \bool_if:cTF { g__dbshow_style_attr_exp_bool_#4_#1_#2 } {
+    \protected at edef\@dbshow at tmp{\__dbshow_use_data_raw:nnnn {#1} {#2} {#3} {#4}}
+    \exp_args:Nno
+    \use:c { __dbshow_style_attr_code_#4_#1_#2:n } { \@dbshow at tmp }
+  } {
+    \use:c { __dbshow_style_attr_code_#4_#1_#2:n }
+    { \__dbshow_use_data_raw:nnnn {#1} {#2} {#3} {#4} }
+  }
+}
+\cs_new:Nn \__dbshow_use_data_raw:nnnn {
   \str_case_e:nn
   { \prop_item:cn { g__dbshow_attr_type_prop_#1 } {#2} } {
     { str }   { \str_use:c { g__dbshow_data_#1_#2_#3 } }
-    { tl }    { \tl_use:c { g__dbshow_data_#1_#2_#3 } }
+    { tl }    { \tl_use:c  { g__dbshow_data_#1_#2_#3 } }
     { int }   { \int_use:c { g__dbshow_data_#1_#2_#3 } }
-    { fp }    { \fp_use:c { g__dbshow_data_#1_#2_#3 } }
+    { fp }    { \fp_use:c  { g__dbshow_data_#1_#2_#3 } }
     { clist } {
-      \__dbshow_clist_use:cccc { g__dbshow_data_#1_#2_#3 }
+      \__dbshow_clist_use:cccccc { g__dbshow_data_#1_#2_#3 }
         { g__dbshow_style_attr_sep_#4_#1_#2 }
         { g__dbshow_style_attr_item_before_tl_#4_#1_#2 }
-        { g__dbshow_style_attr_item_after_tl_#4_#1_#2 }
+        { g__dbshow_style_attr_item_after_ tl_#4_#1_#2 }
+        {   __dbshow_style_clist_item_code_    #4_#1_#2:n }
+        { g__dbshow_style_clist_item_exp_bool_#4_#1_#2 }
     }
     { date }  {
-      \exp_args:Nnx
-      \tl_use:c { g__dbshow_style_attr_wrapper_#4_#1_#2 } {
+      \cs_if_exist_use:cTF { __dbshow_style_date_format_code_#4_#1_#2:xxx } {
+        { \__dbdate_get_year:n  { g__dbshow_data_#1_#2_#3 } }
+        { \__dbdate_get_month:n { g__dbshow_data_#1_#2_#3 } }
+        { \__dbdate_get_day:n   { g__dbshow_data_#1_#2_#3 } }
+      } {
         \__dbshow_date_use:ncc { g__dbshow_data_#1_#2_#3 }
           { g__dbshow_style_attr_sep_#4_#1_#2 }
-          { g__dbshow_style_attr_zfill_bool_#4_#1_#2 }
+          { g__dbshow_style_date_zfill_bool_#4_#1_#2 }
       }
     }
   }
@@ -619,28 +690,51 @@
   }
 }
 \cs_new_protected:Nn \__dbshow_show_set_counter:N {
-  \tl_set:Nx \dbalph   { \int_to_alph:n {#1} }
-  \tl_set:Nx \dbAlph   { \int_to_Alph:n {#1} }
+  \tl_set:Nx \dbalph   { \int_to_alph:n   {#1} }
+  \tl_set:Nx \dbAlph   { \int_to_Alph:n   {#1} }
   \tl_set:Nx \dbarabic { \int_to_arabic:n {#1} }
-  \tl_set:Nx \dbRoman  { \int_to_Roman:n {#1} }
-  \tl_set:Nx \dbroman  { \int_to_roman:n {#1} }
+  \tl_set:Nx \dbRoman  { \int_to_Roman:n  {#1} }
+  \tl_set:Nx \dbroman  { \int_to_roman:n  {#1} }
 }
+\cs_new_protected:Nn \__dbshow_show_set_if_last:NN {
+  \prg_set_conditional:Nnn \__dbshow_show_if_last: { T, F, TF } {
+    \int_compare:nNnTF {#1} = {#2}
+      { \prg_return_true: }
+      { \prg_return_false: }
+  }
+  \cs_set_eq:NN \dbIfLastT  \__dbshow_show_if_last:T
+  \cs_set_eq:NN \dbIfLastF  \__dbshow_show_if_last:F
+  \cs_set_eq:NN \dbIfLastTF \__dbshow_show_if_last:TF
+}
 \cs_new_protected:Nn \__dbshow_show_item:nnN {
   \int_zero_new:N \l__dbshow_show_int
+  \int_zero_new:N \l__dbshow_show_count_int
+  \int_set:Nn \l__dbshow_show_count_int { \clist_count:N #3 }
+  \tl_clear_new:N \l__dbshow_item_tl
   \clist_map_inline:Nn #3 {
     \int_incr:N \l__dbshow_show_int
-    \__dbshow_show_set_counter:N \l__dbshow_show_int
+    \__dbshow_show_set_if_last:NN \l__dbshow_show_int \l__dbshow_show_count_int
+    \__dbshow_show_set_counter:N  \l__dbshow_show_int
     \tl_set:Nn \dbIndex {##1}
     \cs_set:Npn \dbuse ####1 {
       \__dbshow_check_attr:nn {#2} {####1}
       \tl_use:c { g__dbshow_style_attr_before_tl_#1_#2_####1 }
       \__dbshow_use_data:nnnn {#2} {####1} {##1} {#1}
-      \tl_use:c { g__dbshow_style_attr_after_tl_#1_#2_####1 }
+      \tl_use:c { g__dbshow_style_attr_after_ tl_#1_#2_####1 }
     }
-    \tl_use:c { g__dbshow_style_record_before_tl_#1_#2 }
-    \tl_use:c { g__dbshow_style_database_item_tl_#1_#2 }
-    \tl_use:c { g__dbshow_style_record_after_tl_#1_#2 }
+    \bool_if:cTF { g__dbshow_style_item_exp_bool_#1_#2 } {
+      \protected at edef\@dbshow at tmp{\tl_use:c { g__dbshow_style_item_before_tl_#1_#2 }}
+      \tl_put_right:No \l__dbshow_item_tl { \@dbshow at tmp }
+      \protected at edef\@dbshow at tmp{\tl_use:c { g__dbshow_style_item_       tl_#1_#2 }}
+      \tl_put_right:No \l__dbshow_item_tl { \@dbshow at tmp }
+      \protected at edef\@dbshow at tmp{\tl_use:c { g__dbshow_style_item_after_ tl_#1_#2 }}
+    } {
+      \tl_use:c { g__dbshow_style_item_before_tl_#1_#2 }
+      \tl_use:c { g__dbshow_style_item_       tl_#1_#2 }
+      \tl_use:c { g__dbshow_style_item_after_ tl_#1_#2 }
+    }
   }
+  \l__dbshow_item_tl
 }
 \cs_new_protected:Nn \__dbshow_show_set_cond:N {
   \prg_set_conditional:Nnn \__dbshow_if_empty: { T, F, TF } {
@@ -658,6 +752,7 @@
   \__dbshow_show_filter:nnN {#2} {#3} \l__dbshow_show_index_clist
   \clist_if_empty:cF { g__dbshow_sort_clist_#1_#2 }
     { \__dbshow_sort:nNn {#2} \l__dbshow_show_index_clist {#1} }
+  \__dbshow_show_set_cond:N \l__dbshow_show_index_clist
   \tl_use:c { g__dbshow_style_before_tl_#1_#2 }
   \__dbshow_show_item:nnN {#1} {#2} \l__dbshow_show_index_clist
   \tl_use:c { g__dbshow_style_after_tl_#1_#2 }
@@ -665,9 +760,25 @@
 \cs_generate_variant:Nn \__dbshow_show:nnn { nnv }
 \NewDocumentCommand { \dbshow } { m m } {
   \__dbshow_check_database:n {#2}
-  \__dbshow_check_filter:nv {#2} { g__dbshow_filter_#1_#2 }
-  \__dbshow_show:nnv {#1} {#2} { g__dbshow_filter_#1_#2 }
+  \__dbshow_check_style:nn   {#1} {#2}
+  \__dbshow_check_filter:nv  {#2} { g__dbshow_filter_#1_#2 }
+  \__dbshow_show:nnv {#1}    {#2} { g__dbshow_filter_#1_#2 }
 }
+\msg_new:nnn { dbshow } { wrong-date-sep } {
+  can~not~parse~the~date~'#1'~with~the~global~date~separator~'#2'~
+  \msg_line_context:.~Please~set~the~correct~date~separator~with~
+  \dbdatesep.
+}
+\cs_new:Nn \__dbdate_check_date_sep:nn {
+  \int_zero_new:N \l__dbdate_sep_int
+  \tl_map_inline:nn {#1} {
+    \tl_if_eq:nnT {#2} {##1} { \int_incr:N \l__dbdate_sep_int }
+    \int_compare:nNnT { \l__dbdate_sep_int } > { 2 } { \tl_map_break: }
+  }
+  \int_compare:nNnF { \l__dbdate_sep_int } = { 2 }
+    { \msg_fatal:nnnn { dbshow } { wrong-date-sep } {#1} {#2} }
+}
+\cs_generate_variant:Nn \__dbdate_check_date_sep:nn { nV }
 \prg_new_conditional:Nnn \__dbdate_if_leap:n { T, F, TF, p } {
   \bool_if:nTF {
     \int_compare_p:nNn { \int_mod:nn {#1} { 400 } } = { 0 } ||
@@ -752,6 +863,18 @@
   \__dbdate_ginit:n {#1}
 }
 \cs_generate_variant:Nn \__dbdate_gclear_new:n { x }
+\cs_new:Nn \__dbdate_get_year:n {
+  \int_use:c { __dbdate_year_#1 }
+}
+\cs_new:Nn \__dbdate_get_month:n {
+  \int_use:c { __dbdate_month_#1 }
+}
+\cs_new:Nn \__dbdate_get_day:n {
+  \int_use:c { __dbdate_day_#1 }
+}
+\cs_generate_variant:Nn \__dbdate_get_year:n  { x }
+\cs_generate_variant:Nn \__dbdate_get_month:n { x }
+\cs_generate_variant:Nn \__dbdate_get_day:n   { x }
 \cs_new_protected:Nn \__dbdate_set:nnnn {
   \int_set:cn { __dbdate_year_#1 }  {#2}
   \int_set:cn { __dbdate_month_#1 } {#3}
@@ -778,10 +901,12 @@
 \cs_gset_eq:NN \dbdatesep \__dbdate_set_sep:n
 \dbdatesep{/}
 \cs_new_protected:Nn \__dbdate_set:nn {
+  \__dbdate_check_date_sep:nV {#2} \g__dbdate_sep_tl
   \__dbdate_set:w #1\__dbdate_sep#2\__dbdate_stop
 }
 \cs_generate_variant:Nn \__dbdate_set:nn { xx }
 \cs_new_protected:Nn \__dbdate_gset:nn {
+  \__dbdate_check_date_sep:nV {#2} \g__dbdate_sep_tl
   \__dbdate_gset:w #1\__dbdate_sep#2\__dbdate_stop
 }
 \cs_generate_variant:Nn \__dbdate_gset:nn { xx }



More information about the tex-live-commits mailing list.