The Power of Pick/D3 Multivalue Databases in Modern Clojure
PickDict brings authentic Pick/D3-style multivalue database functionality to Clojure applications. Store complex, related data elegantly using multivalue fields, leverage powerful computed expressions, and build sophisticated data applications with concise, maintainable code.
"PickDict transforms how we handle complex data relationships in Clojure" - Developer Community
Get PickDict running in your project in under 5 minutes:
;; project.clj
[org.clojars.hector/pickdict "0.1.0"]
(require '[pickdict.core :as pick])
;; Configure database (SQLite for simplicity)
(def db {:dbtype "sqlite" :dbname "myapp.db"})
;; 2. Create a table with multivalue fields
(pick/create-file! db "PRODUCT"
{:id "INTEGER PRIMARY KEY AUTOINCREMENT"
:name "TEXT NOT NULL"
:price "REAL"
:categories "TEXT" ;; Will store: "electronics]gaming]accessories"
:stock_levels "TEXT"}) ;; Will store: "50]25]10"
;; The dictionary table is automatically created as "PRODUCT_DICT"
;; 3. Dictionary fields are created automatically - you can add computed fields
(pick/define-dictionary-field db "PRODUCT_DICT" "TOTAL_STOCK" "C" "" "SUM:STOCK_LEVELS" "Total Stock")
;; Create a product with multivalue data
(pick/create-record! db "PRODUCT"
{:name "Gaming Headset"
:price 199.99
:categories "electronics]gaming]audio"
:stock_levels "100]50]25"})
;; Query with automatic interpretation
(pick/find-all db "PRODUCT")
;; Returns:
;; [{:PRODUCT_NAME "Gaming Headset"
;; :PRICE 199.99
;; :CATEGORIES ["electronics" "gaming" "audio"]
;; :TOTAL_STOCK 175}]
That's it! You now have a working multivalue database system.
Traditional relational databases force you to create complex joins and multiple tables for related data. Pick/D3's multivalue approach lets you store related data naturally:
Traditional SQL:
-- Multiple tables for product categories
CREATE TABLE products (id, name, price);
CREATE TABLE categories (id, name);
CREATE TABLE product_categories (product_id, category_id);
PickDict:
;; One field stores multiple categories
{:name "Gaming Headset"
:categories "electronics]gaming]audio"} ;; โ ["electronics" "gaming" "audio"]
This approach is particularly powerful for:
```clojure
;; project.clj
[org.clojars.hector/pickdict "0.1.1"]
;; deps.edn
{:deps {org.clojars.hector/pickdict {:mvn/version "0.1.1"}}}
### Manual Installation
```bash
git clone https://github.com/hectorqlucero/pickdict.git
cd pickdict
lein install
Let's build a complete e-commerce system to demonstrate PickDict's capabilities:
(require '[pickdict.core :as pick])
(def db {:dbtype "sqlite" :dbname "ecommerce.db"})
;; Create customer table
(pick/create-file! db "CUSTOMER"
{:id "INTEGER PRIMARY KEY AUTOINCREMENT"
:first_name "TEXT NOT NULL"
:last_name "TEXT NOT NULL"
:email "TEXT"
:phone_numbers "TEXT" ;; Multivalue: home]work]mobile
:addresses "TEXT"}) ;; Multivalue: home]billing]shipping
;; Create product table
(pick/create-file! db "PRODUCT"
{:id "INTEGER PRIMARY KEY AUTOINCREMENT"
:name "TEXT NOT NULL"
:description "TEXT"
:price "REAL"
:categories "TEXT" ;; Multivalue: electronics]gaming]audio
:tags "TEXT" ;; Multivalue: bestseller]featured]new
:stock_levels "TEXT"}) ;; Multivalue: warehouse1]warehouse2]store
;; Create order table
(pick/create-file! db "ORDER"
{:id "INTEGER PRIMARY KEY AUTOINCREMENT"
:customer_id "INTEGER"
:product_ids "TEXT" ;; Multivalue: product_id1]product_id2
:quantities "TEXT" ;; Multivalue: qty1]qty2
:unit_prices "TEXT" ;; Multivalue: price1]price2
:order_date "TEXT"
:status "TEXT"})
;; Customer dictionary (automatically created by create-file!)
(pick/define-dictionary-field db "CUSTOMER_DICT" "CUSTOMER_ID" "A" "0" "" "Customer ID")
(pick/define-dictionary-field db "CUSTOMER_DICT" "FULL_NAME" "C" "" "(str FIRST_NAME \" \" LAST_NAME)" "Full Name")
(pick/define-dictionary-field db "CUSTOMER_DICT" "EMAIL" "A" "3" "" "Email Address")
(pick/define-dictionary-field db "CUSTOMER_DICT" "PRIMARY_PHONE" "A" "4" "" "Primary Phone")
(pick/define-dictionary-field db "CUSTOMER_DICT" "PHONE_NUMBERS" "A" "4" "" "All Phone Numbers")
;; Product dictionary (automatically created by create-file!)
(pick/define-dictionary-field db "PRODUCT_DICT" "PRODUCT_ID" "A" "0" "" "Product ID")
(pick/define-dictionary-field db "PRODUCT_DICT" "PRODUCT_NAME" "A" "1" "" "Product Name")
(pick/define-dictionary-field db "PRODUCT_DICT" "PRICE" "A" "3" "" "Unit Price")
(pick/define-dictionary-field db "PRODUCT_DICT" "CATEGORIES" "A" "4" "" "Categories")
(pick/define-dictionary-field db "PRODUCT_DICT" "TAGS" "A" "5" "" "Tags")
(pick/define-dictionary-field db "PRODUCT_DICT" "TOTAL_STOCK" "C" "" "SUM:STOCK_LEVELS" "Total Stock")
(pick/define-dictionary-field db "PRODUCT_DICT" "INVENTORY_VALUE" "C" "" "(* PRICE TOTAL_STOCK)" "Inventory Value")
(pick/define-dictionary-field db "PRODUCT_DICT" "IS_LOW_STOCK" "C" "" "(if (< TOTAL_STOCK 10) 1 0)" "Low Stock Flag")
;; Order dictionary (automatically created by create-file!)
(pick/define-dictionary-field db "ORDER_DICT" "ORDER_ID" "A" "0" "" "Order ID")
(pick/define-dictionary-field db "ORDER_DICT" "CUSTOMER_NAME" "T" "1" "TCUSTOMER;FULL_NAME" "Customer Name")
(pick/define-dictionary-field db "ORDER_DICT" "PRODUCT_NAMES" "T" "2" "TPRODUCT;PRODUCT_NAME" "Product Names")
(pick/define-dictionary-field db "ORDER_DICT" "QUANTITIES" "A" "3" "" "Quantities")
(pick/define-dictionary-field db "ORDER_DICT" "UNIT_PRICES" "A" "4" "" "Unit Prices")
(pick/define-dictionary-field db "ORDER_DICT" "LINE_TOTALS" "C" "" "MULTIPLY:QUANTITIES,UNIT_PRICES" "Line Totals")
(pick/define-dictionary-field db "ORDER_DICT" "SUBTOTAL" "C" "" "SUM:LINE_TOTALS" "Subtotal")
(pick/define-dictionary-field db "ORDER_DICT" "TAX" "C" "" "(* SUBTOTAL 0.08)" "Tax (8%)")
(pick/define-dictionary-field db "ORDER_DICT" "TOTAL" "C" "" "(+ SUBTOTAL TAX)" "Order Total")
(pick/define-dictionary-field db "ORDER_DICT" "STATUS" "A" "6" "" "Order Status")
;; Create customers
(pick/create-record! db "CUSTOMER"
{:first_name "John"
:last_name "Doe"
:email "john.doe@email.com"
:phone_numbers "555-0101]555-0102]555-0103"
:addresses "123 Main St]456 Oak Ave]789 Pine Rd"})
(pick/create-record! db "CUSTOMER"
{:first_name "Jane"
:last_name "Smith"
:email "jane.smith@email.com"
:phone_numbers "555-0201]555-0202"
:addresses "321 Elm St]654 Maple Dr"})
;; Create products
(pick/create-record! db "PRODUCT"
{:name "Wireless Gaming Headset"
:description "High-quality gaming audio"
:price 199.99
:categories "electronics]gaming]audio"
:tags "bestseller]featured]premium"
:stock_levels "50]25]10"})
(pick/create-record! db "PRODUCT"
{:name "Mechanical Keyboard"
:description "RGB backlit mechanical keyboard"
:price 149.99
:categories "electronics]gaming]computer"
:tags "featured]ergonomic"
:stock_levels "30]15]5"})
;; Create orders
(pick/create-record! db "ORDER"
{:customer_id 1
:product_ids "1]2"
:quantities "2]1"
:unit_prices "199.99]149.99"
:order_date "2025-01-15"
:status "completed"})
(pick/create-record! db "ORDER"
{:customer_id 2
:product_ids "1"
:quantities "1"
:unit_prices "199.99"
:order_date "2025-01-16"
:status "pending"})
;; Get all customers
(def customers (pick/find-all db "CUSTOMER"))
(doseq [customer customers]
(println (str "Customer: " (:FULL_NAME customer)))
(println (str " Email: " (:EMAIL customer)))
(println (str " Phones: " (:PHONE_NUMBERS customer)))
(println))
;; Get all products with computed fields
(def products (pick/find-all db "PRODUCT"))
(doseq [product products]
(println (str "Product: " (:PRODUCT_NAME product)))
(println (str " Price: $" (:PRICE product)))
(println (str " Categories: " (:CATEGORIES product)))
(println (str " Total Stock: " (:TOTAL_STOCK product)))
(println (str " Inventory Value: $" (:INVENTORY_VALUE product)))
(println (str " Low Stock: " (if (= (:IS_LOW_STOCK product) 1) "YES" "NO")))
(println))
;; Get all orders with full interpretation
(def orders (pick/find-all db "ORDER"))
(doseq [order orders]
(println (str "Order #" (:ORDER_ID order)))
(println (str " Customer: " (:CUSTOMER_NAME order)))
(println (str " Products: " (:PRODUCT_NAMES order)))
(println (str " Quantities: " (:QUANTITIES order)))
(println (str " Line Totals: " (:LINE_TOTALS order)))
(println (str " Subtotal: $" (:SUBTOTAL order)))
(println (str " Tax: $" (:TAX order)))
(println (str " Total: $" (:TOTAL order)))
(println (str " Status: " (:STATUS order)))
(println))
;; Update customer information
(pick/update-record! db "CUSTOMER" 1
{:phone_numbers "555-0101]555-0102]555-0104"
:email "john.doe@newemail.com"})
;; Update product stock
(pick/update-record! db "PRODUCT" 1
{:stock_levels "45]20]8"})
;; Update order status
(pick/update-record! db "ORDER" 2
{:status "shipped"})
;; Find products with low stock
(def low-stock-products
(filter #(= (:IS_LOW_STOCK %) 1) (pick/find-all db "PRODUCT")))
;; Find orders by customer
(def customer-orders
(filter #(= (:CUSTOMER_NAME %) "John Doe") (pick/find-all db "ORDER")))
;; Calculate total inventory value
(def total-inventory-value
(reduce + (map :INVENTORY_VALUE (pick/find-all db "PRODUCT"))))
;; Find featured products
(def featured-products
(filter #(some #{"featured"} (:TAGS %)) (pick/find-all db "PRODUCT")))
This example demonstrates:
PickDict uses the ]
delimiter to store multiple values in a single field:
;; Database stores: "electronics]gaming]audio"
;; PickDict returns: ["electronics" "gaming" "audio"]
Multivalue fields are automatically parsed into vectors when retrieved through dictionary operations.
Each table has one dictionary that defines multiple interpretations of the data:
PRODUCT_DICT โ PRODUCT table interpretations
CUSTOMER_DICT โ CUSTOMER table interpretations
ORDER_DICT โ ORDER table interpretations
(create-file! db table-name schema) ;; Create table
(drop-table! db table-name) ;; Drop table
(create-record! db table-name data) ;; Insert record
(find-all db table-name) ;; Get all records
(find-by-id db table-name id) ;; Get record by ID
(update-record! db table-name id data) ;; Update record
(delete-record! db table-name id) ;; Delete record
(create-file! db table-name schema) ;; Create table + dictionary automatically
(define-dictionary-field db dict-name field-name type pos expr desc)
(define-dictionary-field db "PRODUCT_DICT" "NAME" "A" "1" "" "Product Name")
(define-dictionary-field db "ORDER_DICT" "CUSTOMER_NAME" "T" "1" "TCUSTOMER;name" "Customer Name")
(define-dictionary-field db "PRODUCT_DICT" "TOTAL_STOCK" "C" "" "SUM:STOCK_LEVELS" "Total Stock")
(define-dictionary-field db "INVOICE_DICT" "TAX" "C" "" "(* SUBTOTAL 0.08)" "Tax Amount")
PickDict supports both legacy operations and full Clojure expressions:
;; Legacy operations
"SUM:STOCK_LEVELS" ;; Sum multivalue field
"MULTIPLY:QTY,PRICE" ;; Element-wise multiplication
;; Clojure expressions
"(* QUANTITY PRICE)" ;; Full arithmetic
"(if (> TOTAL 100) "High" "Low")" ;; Conditionals
"(clojure.string/upper-case NAME)" ;; String operations
(try
(pick/create-record! db "PRODUCT" product-data)
(catch Exception e
(log/error "Failed to create product:" (.getMessage e))))
;; Rich product data with categories, tags, and specifications
{:name "Gaming Laptop"
:categories "electronics]gaming]computer"
:tags "bestseller]featured]premium"
:specifications "16GB RAM]512GB SSD]RTX 3060"
:images "front.jpg]side.jpg]back.jpg"}
;; Multiple contact methods and addresses
{:name "John Doe"
:phone_numbers "home:555-0101]work:555-0102]mobile:555-0103"
:addresses "home:123 Main St]billing:456 Oak Ave]shipping:789 Pine Rd"}
;; Complex order calculations
{:quantities "2]1]5"
:unit_prices "99.99]49.99]19.99"
:line_totals "199.98]49.99]99.95" ;; Computed
:subtotal "349.92" ;; Computed
:tax "27.99" ;; Computed
:total "377.91"} ;; Computed
We welcome contributions! Please:
lein test
Copyright ยฉ 2025 Hector
Distributed under the Eclipse Public License 2.0.
PickDict - Elegant multivalue databases for Clojure applications.
Pick/D3 is a powerful multivalue database system that revolutionized data management in the 1970s. Unlike traditional relational databases, Pick/D3 allows:
PickDict brings this proven architecture to Clojure, enabling developers to build sophisticated data applications with elegant, concise code.
โจ Authentic Pick/D3 Architecture - True multivalue database implementation with one dictionary per table
๐ข Multivalue Fields - Store arrays of related data in single fields using configurable delimiters, automatically parsed into vectors on retrieval
๐งฎ Advanced Expression Engine - Full Clojure expressions with automatic variable binding
๐ Relationship Support - Built-in translation fields for cross-table lookups
โก High Performance - Optimized SQL backend with connection pooling
๐ Legacy Compatibility - Supports traditional MULTIPLY/SUM operations
๐ก๏ธ Type Safety - Comprehensive error handling and validation
๐ SQLite Backend - Persistent storage with clojure.java.jdbc
๐งช Comprehensive Testing - Full test suite with automatic multivalue parsing validation
PickDict is available on Clojars. Add this to your project.clj
:
[org.clojars.hector/pickdict "0.1.1"]
For local development or if you need the latest changes:
git clone https://github.com/hectorqlucero/pickdict.git
cd pickdict
lein install
PickDict requires the following runtime dependencies:
Get started with PickDict in minutes:
(require '[pickdict.core :as pick])
;; 1. Configure database connection
(def db {:dbtype "sqlite" :dbname "inventory.db"})
;; 2. Create table with multivalue fields (dictionary created automatically)
(pick/create-file! db "PRODUCT"
{:id "INTEGER PRIMARY KEY AUTOINCREMENT"
:name "TEXT NOT NULL"
:price "REAL"
:categories "TEXT" ;; Multivalue: "electronics]popular]new"
:stock_levels "TEXT"}) ;; Multivalue: "10]5]20"
;; Dictionary fields are created automatically (Pick/D3 style):
;; - NAME (maps to name column)
;; - PRICE (maps to price column)
;; - CATEGORIES (maps to categories column)
;; - STOCK_LEVELS (maps to stock_levels column)
;; 4. Create and query data
(pick/create-record! db "PRODUCT"
{:name "Wireless Headphones"
:price 99.99
:categories "electronics]audio]wireless"
:stock_levels "50]30]20"})
;; 5. Query with automatic interpretation
(pick/find-all db "PRODUCT")
;; Returns: {:PRODUCT_NAME "Wireless Headphones"
;; :PRICE 99.99
;; :CATEGORIES ["electronics" "audio" "wireless"]
;; :STOCK_LEVELS ["50" "30" "20"]}
PickDict uses the ]
character as a delimiter to store multiple values in a single database field:
;; Database field contains: "electronics]audio]wireless"
;; PickDict interprets as: ["electronics" "audio" "wireless"]
A dictionary defines how to interpret data from a table. Each table has exactly one dictionary containing multiple field definitions:
;; One dictionary per table (Pick/D3 standard)
PRODUCT_DICT โ Defines how to interpret PRODUCT table data
CUSTOMER_DICT โ Defines how to interpret CUSTOMER table data
PickDict supports three fundamental field types:
(create-file! db table-name schema)
Creates a new table with the specified schema and automatically creates a dictionary with Attribute fields for each column (Pick/D3 style).
Parameters:
db
: Database connection maptable-name
: String name of the table to createschema
: Map of column names to SQL typesAutomatic Dictionary Creation:
{TABLE_NAME}_DICT
Example:
(pick/create-file! db "PRODUCT"
{:id "INTEGER PRIMARY KEY AUTOINCREMENT"
:name "TEXT NOT NULL"
:price "REAL"
:categories "TEXT"})
;; Automatically creates dictionary fields: NAME, PRICE, CATEGORIES
(drop-table! db table-name)
Drops a table and its associated dictionary.
Parameters:
db
: Database connection maptable-name
: String name of the table to dropNote: Dictionaries are created automatically when you call create-file!
. You only need to define dictionary fields.
(define-dictionary-field db dict-name field-name field-type position expression description)
Defines a new field in a dictionary.
Parameters:
db
: Database connection mapdict-name
: String name of the dictionaryfield-name
: String name of the fieldfield-type
: "A" (Attribute), "T" (Translate), or "C" (Computed)position
: Column position (for Attribute fields) or empty stringexpression
: Expression string (for Translate/Computed fields)description
: Human-readable descriptionExamples:
;; Attribute field
(pick/define-dictionary-field db "PRODUCT_DICT" "NAME" "A" "1" "" "Product Name")
;; Translate field
(pick/define-dictionary-field db "PRODUCT_DICT" "SUPPLIER_NAME" "T" "1" "TSUPPLIER;name" "Supplier Name")
;; Computed field
(pick/define-dictionary-field db "PRODUCT_DICT" "TOTAL_VALUE" "C" "" "(* PRICE QUANTITY)" "Total Value")
(create-record! db table-name data)
Creates a new record in the specified table.
Parameters:
db
: Database connection maptable-name
: String name of the tabledata
: Map of column names to values(find-all db table-name)
Retrieves all records from a table with dictionary interpretation.
Returns: Sequence of maps with interpreted field values. Multivalue fields are automatically parsed into vectors.
(find-by-id db table-name id)
Retrieves a single record by ID with dictionary interpretation.
Returns: Map with interpreted field values or nil
if not found. Multivalue fields are automatically parsed into vectors.
(update-record! db table-name id data)
Updates an existing record.
Parameters:
db
: Database connection maptable-name
: String name of the tableid
: Record ID to updatedata
: Map of column names to new values(delete-record! db table-name id)
Deletes a record by ID.
(read-all-records db table-name)
Retrieves all records without dictionary interpretation (raw data).
Returns: Sequence of maps with raw database values
;; Create a customer
(pick/create-record! db "CUSTOMER"
{:name "John Doe"
:email "john@example.com"
:phone "555-0123"})
;; Create a product with multivalue fields
(pick/create-record! db "PRODUCT"
{:name "Gaming Laptop"
:price 1299.99
:categories "electronics]gaming]laptop"
:specifications "16GB RAM]512GB SSD]RTX 3060"})
;; Get all products with dictionary interpretation
(def products (pick/find-all db "PRODUCT"))
;; Get specific product by ID
(def product (pick/find-by-id db "PRODUCT" 1))
;; Get raw data (for debugging or admin purposes)
(def raw-data (pick/read-all-records db "PRODUCT"))
;; Update product price
(pick/update-record! db "PRODUCT" 1
{:price 1199.99
:categories "electronics]gaming]laptop]discount"})
;; Update customer information
(pick/update-record! db "CUSTOMER" 1
{:phone "555-0124"
:email "john.doe@newemail.com"})
;; Delete a product
(pick/delete-record! db "PRODUCT" 1)
;; Delete a customer
(pick/delete-record! db "CUSTOMER" 1)
A
)Direct mapping to table columns by position. Use for simple field access:
;; Map to first column (name)
(define-dictionary-field db "CUSTOMER_DICT" "CUSTOMER_NAME" "A" "1" "" "Customer Name")
;; Map to second column (email)
(define-dictionary-field db "CUSTOMER_DICT" "EMAIL" "A" "2" "" "Email Address")
;; Map to third column (phone)
(define-dictionary-field db "CUSTOMER_DICT" "PHONE" "A" "3" "" "Phone Number")
T
)Lookup values from related tables using the format T{table};{field}
:
;; Lookup customer name from CUSTOMER table
(define-dictionary-field db "ORDER_DICT" "CUSTOMER_NAME" "T" "1" "TCUSTOMER;name" "Customer Name")
;; Lookup product names from PRODUCT table
(define-dictionary-field db "ORDER_DICT" "PRODUCT_NAMES" "T" "2" "TPRODUCT;name" "Product Names")
;; Lookup supplier contact from SUPPLIER table
(define-dictionary-field db "PRODUCT_DICT" "SUPPLIER_EMAIL" "T" "1" "TSUPPLIER;email" "Supplier Email")
C
)Perform calculations using Clojure expressions or legacy operations:
;; Full Clojure expressions
(define-dictionary-field db "INVOICE_DICT" "SUBTOTAL" "C" "" "(+ 99.99 49.99 29.99)" "Subtotal")
(define-dictionary-field db "INVOICE_DICT" "TAX" "C" "" "(* SUBTOTAL 0.08)" "Tax (8%)")
(define-dictionary-field db "INVOICE_DICT" "TOTAL" "C" "" "(+ SUBTOTAL TAX)" "Total Amount")
;; Legacy operations (still supported)
(define-dictionary-field db "PRODUCT_DICT" "TOTAL_STOCK" "C" "" "SUM:STOCK_LEVELS" "Total Stock")
(define-dictionary-field db "PRODUCT_DICT" "LINE_TOTALS" "C" "" "MULTIPLY:QUANTITIES,PRICES" "Line Totals")
Expressions automatically bind variables from other dictionary fields:
;; Define base fields first
(define-dictionary-field db "INVOICE_DICT" "QUANTITY" "A" "1" "" "Quantity")
(define-dictionary-field db "INVOICE_DICT" "PRICE" "A" "2" "" "Unit Price")
;; Computed field can reference previous fields
(define-dictionary-field db "INVOICE_DICT" "LINE_TOTAL" "C" "" "(* QUANTITY PRICE)" "Line Total")
(define-dictionary-field db "INVOICE_DICT" "DISCOUNTED_TOTAL" "C" "" "(* LINE_TOTAL 0.9)" "90% Discount")
For multivalue fields, expressions are evaluated element-wise:
;; If quantities = "2]1]5" and prices = "10]20]30"
(define-dictionary-field db "INVOICE_DICT" "LINE_TOTALS" "C" "" "MULTIPLY:QUANTITIES,PRICES" "Line Totals")
;; Result: "20]20]150"
(define-dictionary-field db "INVOICE_DICT" "SUBTOTAL" "C" "" "SUM:LINE_TOTALS" "Subtotal")
;; Result: "190"
;; Conditional logic
(define-dictionary-field db "PRODUCT_DICT" "STOCK_STATUS" "C" ""
"(if (> TOTAL_STOCK 100) \"In Stock\" \"Low Stock\")" "Stock Status")
;; String manipulation
(define-dictionary-field db "CUSTOMER_DICT" "INITIALS" "C" ""
"(str (first (clojure.string/upper-case (subs FIRST_NAME 0 1)))
(first (clojure.string/upper-case (subs LAST_NAME 0 1))))" "Initials")
;; Date calculations
(define-dictionary-field db "ORDER_DICT" "DAYS_AGO" "C" ""
"(/ (- (System/currentTimeMillis) (.getTime (java.text.SimpleDateFormat. \"yyyy-MM-dd\") (.parse ORDER_DATE))) (* 24 60 60 1000))" "Days Since Order")
CUSTOMER_NAME
);; Always wrap database operations in try-catch
(try
(pick/create-record! db "PRODUCT" product-data)
(catch Exception e
(log/error "Failed to create product:" (.getMessage e))
(throw e)))
;; Validate data before operations
(defn create-product! [db product]
{:pre [(string? (:name product))
(number? (:price product))
(pos? (:price product))]}
(pick/create-record! db "PRODUCT" product))
For production use, configure your database connection appropriately:
;; Development
(def db {:dbtype "sqlite" :dbname "app.db"})
;; Production (with connection pooling)
(def db {:dbtype "postgresql"
:dbname "production_db"
:host "localhost"
:port 5432
:user "app_user"
:password "secure_password"
:maximum-pool-size 10})
-- Add indexes for better query performance
CREATE INDEX idx_product_name ON PRODUCT(name);
CREATE INDEX idx_customer_email ON CUSTOMER(email);
CREATE INDEX idx_order_date ON ORDER(order_date);
"Table doesn't exist" errors:
create-file!
before using the table"Dictionary field not found" errors:
create-file!
to create both table and dictionary"Expression evaluation failed" errors:
read-all-records
to inspect raw dataMultivalue parsing issues:
]
character only;; Inspect raw data without dictionary interpretation
(def raw-records (pick/read-all-records db "PRODUCT"))
(doseq [record raw-records]
(println "Raw record:" record))
;; Test expressions in REPL
(def test-data {:QUANTITY 5 :PRICE 10.99})
;; Test expression: (* QUANTITY PRICE)
(eval `(let [~'QUANTITY ~(:QUANTITY test-data)
~'PRICE ~(:PRICE test-data)]
(* QUANTITY PRICE)))
doc/example_usage.clj
lein test
to verify functionalitylein repl
for interactive debuggingSee doc/example_usage.clj
for a comprehensive example including:
Run the complete example:
(load-file "doc/example_usage.clj")
(example-usage/run-complete-crud-demo)
;; Product table with rich multivalue data
(pick/create-file! db "PRODUCT"
{:id "INTEGER PRIMARY KEY AUTOINCREMENT"
:name "TEXT NOT NULL"
:price "REAL"
:categories "TEXT"
:tags "TEXT"
:specifications "TEXT"
:images "TEXT"})
;; Dictionary with business logic (automatically created by create-file!)
(pick/define-dictionary-field db "PRODUCT_DICT" "PRODUCT_NAME" "A" "1" "" "Product Name")
(pick/define-dictionary-field db "PRODUCT_DICT" "CATEGORIES" "A" "2" "" "Categories")
(pick/define-dictionary-field db "PRODUCT_DICT" "TAGS" "A" "3" "" "Tags")
(pick/define-dictionary-field db "PRODUCT_DICT" "IS_FEATURED" "C" "" "(some #(= % \"featured\") TAGS)" "Is Featured")
(pick/define-dictionary-field db "PRODUCT_DICT" "CATEGORY_COUNT" "C" "" "(count CATEGORIES)" "Category Count")
;; Invoice table with complex calculations
(pick/create-file! db "INVOICE"
{:id "INTEGER PRIMARY KEY AUTOINCREMENT"
:customer_id "INTEGER"
:line_items "TEXT" ;; JSON-like multivalue structure
:tax_rate "REAL"
:discount_percent "REAL"})
;; Advanced financial calculations (automatically created by create-file!)
(pick/define-dictionary-field db "INVOICE_DICT" "CUSTOMER_NAME" "T" "1" "TCUSTOMER;name" "Customer Name")
(pick/define-dictionary-field db "INVOICE_DICT" "SUBTOTAL" "C" "" "(reduce + LINE_ITEM_TOTALS)" "Subtotal")
(pick/define-dictionary-field db "INVOICE_DICT" "TAX_AMOUNT" "C" "" "(* SUBTOTAL (/ TAX_RATE 100))" "Tax Amount")
(pick/define-dictionary-field db "INVOICE_DICT" "DISCOUNT_AMOUNT" "C" "" "(* SUBTOTAL (/ DISCOUNT_PERCENT 100))" "Discount Amount")
(pick/define-dictionary-field db "INVOICE_DICT" "TOTAL" "C" "" "(- (+ SUBTOTAL TAX_AMOUNT) DISCOUNT_AMOUNT)" "Final Total")
# Run all tests
lein test
# Run specific test namespace
lein test pickdict.core-test
# Run tests with coverage
lein cloverage
# Start REPL
lein repl
# Run tests on file changes
lein test-refresh
# Check for outdated dependencies
lein ancient
# Generate documentation
lein codox
# Build JAR
lein jar
# Install locally
lein install
# Run linter
lein eastwood
# Check test coverage
lein cloverage
# Run all quality checks
lein do test, eastwood, cloverage
We welcome contributions to PickDict! Please see our Contributing Guide for details.
git clone https://github.com/yourusername/pickdict.git
git checkout -b feature/your-feature
lein test
Copyright ยฉ 2025 Hector
Distributed under the Eclipse Public License 2.0.
This project is not affiliated with Rocket Software or other Pick/D3 vendors. "Pick" and "D3" are trademarks of Rocket Software, Inc.
PickDict - Bringing the power of multivalue databases to modern Clojure applications.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
Ctrl+k | Jump to recent docs |
โ | Move to previous article |
โ | Move to next article |
Ctrl+/ | Jump to the search field |