sql-interactive-modeで完了するための会社のバックエンドはありますか?


9

私はを使用sql-interactive-modeしていますが、SQLキーワードを完成させるCompanyバックエンドと、できれば使用するデータベースの列/テーブル名も必要です。

完了を探しているとき、驚いたことに、SQLのバックエンドはまだありませんでした。このスニペットを見つけましたが、正しく機能しませんでした。

まだ存在していない可能性があり、SQLの独自のバックエンドを作成する場合があります。しかし、最も一般的な言語の1つに対応するCompanyバックエンドがないとは思えません。


キーワードの完成は、dictのようなバックエンドの1つで十分に単純でなければなりません。特に複数のデータベースで機能させたい場合は、データベース固有のデータははるかに困難です...
wasamasa

iキーワードの完成が十分に簡単である場合、会社にSQLバックエンドがまだない理由がわかりますか?後者については同意しますが、難しいと思いますが、バッファーに列の内容がある場合は、おそらくそれで完了しcompany-dabbrevますか?
ReneFroger

これは単にへの新しいエントリなcompany-keywords.elので、気軽に投稿してください!そして、はい、dabbrevバックエンドはそれ(およびバッファ内のその他すべて)をキャッチします...
wasamasa

回答:


4

同様の問題があり、独自のバックエンドを作成することにしました。既存のバックエンドの1つ(C ++?)がテンプレートとして使用され、辞書のように動作する新しいバックエンドを作成するように変更しました。

私のセットアップでは、SQLiバッファーは、接続されているデータベースと一致するように自動的に名前が付けられます。*DB:DBASE1DM*。バックエンドには、スキーマ、テーブル、列を含む各データベースのalistが含まれています。何かを完成させたいときは、バッファの名前を使用して、そのデータベースの候補の正しいリストを取得します。

(defun ry/company-sql-upper-lower (&rest lst)
  (nconc (sort (mapcar 'upcase lst) 'string<) lst))

(defvar ry/company-sql-alist
  `(("DBASE1"               ;; Database name w/o environment suffix.
     "DBASE1DM" "DBASE1UM"  ;; Database name with environment suffix.
     "SCHEMA1" "SCHEMA2"
     "TABLE1" "TABLE2"
     "COLUMN1" "COLUMN2")
    ("DBASE2"
     "DBASE2DM" "DBASE2UM"
     "SCHEMA1" "SCHEMA2"
     "TABLE1" "TABLE2"
     "COLUMN1" "COLUMN2"))
    "Alist mapping sql-mode to candidates.")

(defun ry/company-sql (command &optional arg &rest ignored)
  "`company-mode' back-end for SQL mode based on database name."
  (interactive (list 'interactive))
  (cl-case command
    (interactive (company-begin-backend 'ry/company-sql))
    (prefix (and (assoc (substring (buffer-name (current-buffer)) 4 -3) ry/company-sql-alist)
                 (not (company-in-string-or-comment))
                 (or (company-grab-symbol) 'stop)))
    (candidates
     (let ((completion-ignore-case t)
           (symbols (cdr (assoc (substring (buffer-name (current-buffer)) 4 -3) ry/company-sql-alist))))       
       (all-completions arg (if (consp symbols)
                                symbols
                              (cdr (assoc symbols company-sql-alist))))))
    (sorted t)))

これには、スマートコンプリーションではなく、新しいデータベースを含めたり、既存のデータベースを変更したりするのが手動のプロセスであるという欠点があります。いくつかのクエリを使用してデータを収集でき、バックエンドに必要な形式にデータをマッサージすることはそれほど難しくありません。

以下の関数は、データベースへの接続を処理し、接続されているデータベースと一致するようにバッファーの名前を変更します。

(defun ry/sql-open-database (database username password)
  "Open a SQLI process and name the SQL statement window with the name provided."
  (interactive (list
                (read-string "Database: ")
                (read-string "Username: ")
                (read-passwd "Password: ")))
  (let ((u-dbname (upcase database)))
    (setq sql-set-product "db2")

    (sql-db2 u-dbname)
    (sql-rename-buffer u-dbname)
    (setq sql-buffer (current-buffer))
    (sql-send-string (concat "CONNECT TO " database " USER " username " USING " password ";"))

    (other-window 1)
    (switch-to-buffer (concat "*DB:" u-dbname "*"))
    (sql-mode)
    (sql-set-product "db2")
    (setq sql-buffer (concat "*SQL: " u-dbname "*"))))

お返事ありがとうございます。しかし、あなたの機能を試すときにいくつかの困難がありました。で会社に追加し(add-to-list 'company-backends 'ry/company-sql) (add-to-list 'company-backends 'ry/company-sql-alist)M-x sql-mysql後、単語を試した後、次のエラーが発生しました:Company: An error occurred in auto-begin Args out of range: "*SQL*", 4, -3。このエラーメッセージはどのように解釈できますか?
ReneFroger

回答を更新して、データベースへの接続に使用する関数を含めました。バッファーに関連するデータベースと一致するようにバッファー名を変更します。バッファ名が短すぎるため、部分文字列が失敗しています。サブストリングは*DB:、データベース名を取得するためにバッファ名から環境サフィックスを削除するために使用され、補完の正しいリストが使用されます。関数は、補完のバッファ名がの形式であることを前提としてい*DB:ACCOUNTSDM*ます。サブストリングはACCOUNTSバッファー名からプルします。
Jonakand

お返事をありがとうございます。Lispを学ぶ必要があるのは明らかです。なぜなら、のmysql代わりにそれをどのように変更できるかを理解できなかったからですdb2。しかし、あなたの貢献は本当に感謝しているので、私はあなたの返事を検証しました。それをありがとう。
ReneFroger

たぶん、この回答はEmacsに貢献するはずです。
stardiviner 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.