Implement a new “snake_case” quoting rule.

In passing, add the identifiers case option to SQLite support, which makes
it easier to test here, and add a table named "TableName" to our local test
database.

Fix #631.
This commit is contained in:
Dimitri Fontaine 2017-09-13 22:55:10 +02:00
parent d2d4be2ed0
commit dbadab9e9e
10 changed files with 38 additions and 28 deletions

View File

@ -66,7 +66,7 @@
;; PostgreSQL related utils
(:file "read-sql-files")
(:file "queries")
(:file "quoting")
(:file "quoting" :depends-on ("utils"))
(:file "catalog" :depends-on ("quoting"))
(:file "alter-table" :depends-on ("catalog"))

View File

@ -35,7 +35,8 @@
(:export #:apply-identifier-case
#:build-identifier
#:quoted-p
#:ensure-unquoted))
#:ensure-unquoted
#:camelCase-to-colname))
(defpackage #:pgloader.catalog
(:use #:cl #:pgloader.params #:pgloader.quoting)

View File

@ -125,6 +125,7 @@
(def-keyword-rule "keys")
(def-keyword-rule "downcase")
(def-keyword-rule "quote")
(def-keyword-rule "snake_case")
(def-keyword-rule "identifiers")
(def-keyword-rule "including")
(def-keyword-rule "excluding")

View File

@ -160,7 +160,10 @@
(defrule option-on-error-stop (and kw-on kw-error kw-stop)
(:constant (cons :on-error-stop t)))
(defrule option-identifiers-case (and (or kw-downcase kw-quote) kw-identifiers)
(defrule option-identifiers-case (and (or kw-snake_case
kw-downcase
kw-quote)
kw-identifiers)
(:lambda (id-case)
(bind (((action _) id-case))
(cons :identifier-case action))))

View File

@ -31,7 +31,8 @@ load database
option-index-names
option-reset-sequences
option-foreign-keys
option-encoding))
option-encoding
option-identifiers-case))
(defrule sqlite-options (and kw-with
(and sqlite-option (* (and comma sqlite-option))))
@ -100,6 +101,7 @@ load database
(*cast-rules* ',casts)
,@(pgsql-connection-bindings pg-db-conn gucs)
,@(batch-control-bindings options)
,@(identifier-case-binding options)
(source-db (with-stats-collection ("fetch" :section :pre)
(expand (fetch-file ,sqlite-db-conn))))
(source

View File

@ -40,8 +40,8 @@
;; in other cases follow user directive
(t *identifier-case*))))
(ecase *identifier-case*
(:snake_case (camelCase-to-colname identifier))
(:downcase lowercase-identifier)
(:quote (format nil "~s"
(cl-ppcre:regex-replace-all "\"" identifier "\"\"")))
@ -68,3 +68,23 @@
(string part)
(t (princ-to-string part))))
:when more? :collect sep))))
;;;
;;; Camel Case converter
;;;
(defun camelCase-to-colname (string)
"Transform input STRING into a suitable column name.
lahmanID lahman_id
playerID player_id
birthYear birth_year"
(coerce
(loop
:for first := t :then nil
:for char :across string
:for previous-upper-p := nil :then char-upper-p
:for char-upper-p := (and (alpha-char-p char)
(eq char (char-upcase char)))
:for new-word := (and (not first) char-upper-p (not previous-upper-p))
:when (and new-word (not (char= char #\_))) :collect #\_
:collect (char-downcase char))
'string))

View File

@ -23,6 +23,7 @@
;; needed in create index specific kernels
(*pgsql-reserved-keywords* . ',*pgsql-reserved-keywords*)
(*preserve-index-names* . ,*preserve-index-names*)
(*identifier-case* . ,*identifier-case*)
;; bindings updates for libs
;; CFFI is used by the SQLite lib

View File

@ -3,25 +3,6 @@
;;;
(in-package :pgloader.utils)
;;;
;;; Camel Case converter
;;;
(defun camelCase-to-colname (string)
"Transform input STRING into a suitable column name.
lahmanID lahman_id
playerID player_id
birthYear birth_year"
(coerce
(loop
for first = t then nil
for char across string
for previous-upper-p = nil then char-upper-p
for char-upper-p = (eq char (char-upcase char))
for new-word = (and (not first) char-upper-p (not previous-upper-p))
when (and new-word (not (char= char #\_))) collect #\_
collect (char-downcase char))
'string))
;;;
;;; Unquote SQLite default values, might be useful elsewhere
;;;

View File

@ -3,6 +3,7 @@ load database
into postgresql:///pgloader
-- with include drop, create tables, create indexes, reset sequences
with snake_case identifiers
before load do
$$ drop schema if exists sqlite cascade; $$,

Binary file not shown.