UPSERTとは
データが存在するかどうかをチェックし、存在すれば更新、存在しなければ挿入を行うという処理は、よく行われます。
リレーショナルデータベース(RDBMS)上のSQL言語では、こうした処理を一文で行うためのコマンドを俗にUPSERTと呼び、長年にわたって実装や標準化が望まれていました。UPSERTは結局、SQL:2003にてMERGE文という形で標準化され、Oracle DatabaseやMicrosoft SQL Server、IBM DB2などの主要なRDBMS製品で実装されるようになっています。
Emacs Lisp連想リストのUPSERT
UPSERTは、Emacsで連想リストを扱う場合でも使いたい場合があります。例えば、フレームの形状を設定する連想リストdefault-frame-alistでEmacsのフレームの幅を100に設定する場合です。
default-frame-alist
でwidth
がすでに設定されている場合はwidth
の値を100
に更新し、設定されていない場合は(width . 100)
をdefault-frame-alist
に挿入するという処理になります。しかし、こうした処理をいちいちinit.el
などの初期化ファイルに記述していったのでは、面倒ですし、初期化ファイルのメンテナンスもたいへんになります。そこで作ったのがEmacs Lispで連想リストのUPSERTを実現する次の関数update-or-add-alist
です。
(defun update-or-add-alist (alist-var key value)
"If KEY in ALIST, update VALUE of the KEY.
Unless, cons cell (KEY . VALUE) is added."
(let (acell (alst (symbol-value alist-var)))
(if (setq acell (assoc key alst))
(unless (equal (cdr acell) value)
(setcdr acell value))
(set alist-var (push (cons key value) alst)))
alst))
この関数を定義したあと、default-frame-alist
でフレームの幅を100に設定するには、次のようにします。
(update-or-add-alist 'default-frame-alist 'width 100)
よければ、お試しください
おまけ
実は、こういう関数はすでに標準で存在しているはずなのに…といろいろ調べたのですがついに見つけられず、自分で実装したという経緯があります。心当たりの方がいれば、教えてください^^