Apakah ada backend perusahaan untuk penyelesaian dalam sql-interactive-mode?

9

Saya menggunakan sql-interactive-mode, dan saya membutuhkan backend Perusahaan yang akan menyelesaikan kata kunci SQL, dan lebih disukai, juga nama kolom / tabel dari database yang digunakan.

Ketika mencari-cari penyelesaian, mengejutkan saya, belum ada backend untuk SQL. Saya menemukan cuplikan ini , tetapi itu tidak berfungsi dengan baik.

Mungkin belum ada, dan saya mungkin membuat backend sendiri untuk SQL. Tetapi saya merasa sulit untuk percaya bahwa tidak ada backend Perusahaan untuk salah satu bahasa yang paling umum.

ReneFroger
sumber
Menyelesaikan kata kunci harus cukup sederhana dengan salah satu backend seperti dict. Data khusus basis data jauh lebih sulit, terutama jika Anda menginginkannya bekerja untuk lebih dari satu basis data ...
wasamasa
Jika menyelesaikan kata kunci akan cukup sederhana, apakah Anda tahu mengapa belum ada SQL-backend untuk Perusahaan? Dan saya setuju dengan Anda tentang yang terakhir, itu akan sulit, tetapi ketika Anda memiliki konten kolom di buffer Anda, itu akan selesai dengan company-dabbrevsaya kira?
ReneFroger
Itu hanya akan menjadi entri baru company-keywords.el, jadi silakan berkontribusi! Dan ya, backend dabbrev akan menangkap itu (dan segala sesuatu di buffer Anda) ...
wasamasa

Jawaban:

4

Saya memiliki masalah yang sama dan memutuskan untuk membuat backend saya sendiri. Salah satu backend yang ada (C ++?) Digunakan sebagai templat dan saya memodifikasinya untuk membuat back end baru yang berperilaku seperti kamus.

Dalam pengaturan saya, buffer SQLi secara otomatis dinamai sesuai dengan database yang sedang terhubung, misalnya. *DB:DBASE1DM*. Backend berisi daftar untuk setiap database dengan skema, tabel, dan kolom. Ketika saya ingin menyelesaikan sesuatu, nama buffer digunakan untuk mendapatkan daftar kandidat yang tepat untuk database itu.

(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)))

Ini memiliki kelemahan bahwa itu bukan penyelesaian yang cerdas dan termasuk database baru atau membuat modifikasi ke database yang ada adalah proses manual. Beberapa pertanyaan dapat digunakan untuk mengumpulkan data dan kemudian tidak terlalu sulit untuk memijatnya ke dalam format yang diperlukan untuk backend.

Fungsi di bawah ini menangani koneksi ke database dan mengubah nama buffer agar sesuai dengan database yang terhubung.

(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 "*"))))
Jonakand
sumber
terima kasih atas balasan Anda, itu sangat dihargai! Namun, saya mengalami beberapa kesulitan ketika mencoba fungsi Anda. Setelah menambah perusahaan dengan (add-to-list 'company-backends 'ry/company-sql) (add-to-list 'company-backends 'ry/company-sql-alist), saya mendapat error berikut dalam M-x sql-mysqlsetelah mencoba kata: Company: An error occurred in auto-begin Args out of range: "*SQL*", 4, -3. Bagaimana saya bisa menafsirkan pesan kesalahan ini?
ReneFroger
Saya telah memperbarui jawaban untuk menyertakan fungsi yang saya gunakan untuk terhubung ke database. Ini menangani perubahan nama buffer agar sesuai dengan database yang terkait dengan buffer. Nama buffer Anda terlalu pendek sehingga substring gagal. Substring digunakan untuk menghapus *DB:sufiks lingkungan dan dari nama buffer untuk mendapatkan nama database sehingga daftar penyelesaian yang benar digunakan. Fungsi ini mengasumsikan bahwa nama buffer untuk penyelesaian akan berada dalam formulir *DB:ACCOUNTSDM*. Substring akan menarik ACCOUNTSdari nama buffer.
Jonakand
Terima kasih untuk balasan Anda. Saya jelas perlu belajar Lisp, karena saya tidak tahu bagaimana saya bisa memodifikasi untuk mysqlbukan db2. Tetapi kontribusi Anda sangat dihargai, jadi saya memvalidasi balasan Anda. Terima kasih untuk itu.
ReneFroger
Mungkin jawaban ini harus berkontribusi untuk Emacs.
stardiviner