module Music.Theory.DB.Common where import Data.List {- base -} import Data.Maybe {- base -} import Safe {- safe -} import qualified Music.Theory.List as T {- base -} import qualified Music.Theory.Maybe as T {- base -} -- * Type type Entry k v = (k,v) type Record k v = [Entry k v] type DB k v = [Record k v] type Key = String type Value = String type Entry' = Entry Key Value type Record' = Record Key Value type DB' = DB Key Value -- * Record -- | The sequence of keys at 'Record'. record_key_seq :: Record k v -> [k] record_key_seq = map fst -- | 'True' if 'Key' is present in 'Entity'. record_has_key :: Eq k => k -> Record k v -> Bool record_has_key k = elem k . record_key_seq -- | 'T.histogram' of 'record_key_seq'. record_key_histogram :: Ord k => Record k v -> [(k,Int)] record_key_histogram = T.histogram . record_key_seq -- | Duplicate keys predicate. record_has_duplicate_keys :: Ord k => Record k v -> Bool record_has_duplicate_keys = any (> 0) . map snd . record_key_histogram -- | Find all associations for key using given equality function. record_lookup_by :: (k -> k -> Bool) -> k -> Record k v -> [v] record_lookup_by f k = map snd . filter (f k . fst) -- | 'record_lookup_by' of '=='. record_lookup :: Eq k => k -> Record k v -> [v] record_lookup = record_lookup_by (==) -- | /n/th element of 'record_lookup'. record_lookup_at :: Eq k => (k,Int) -> Record k v -> Maybe v record_lookup_at (c,n) = flip atMay n . record_lookup c -- | Variant of 'record_lookup' requiring a unique key. 'Nothing' indicates -- there is no entry, it is an 'error' if duplicate keys are present. record_lookup_uniq :: Eq k => k -> Record k v -> Maybe v record_lookup_uniq k r = case record_lookup k r of [] -> Nothing [v] -> Just v _ -> error "record_lookup_uniq: non uniq" -- | 'True' if key exists and is unique. record_has_key_uniq :: Eq k => k -> Record k v -> Bool record_has_key_uniq k = isJust . record_lookup_uniq k -- | Error variant. record_lookup_uniq_err :: Eq k => k -> Record k v -> v record_lookup_uniq_err k = T.from_just "record_lookup_uniq: none" . record_lookup_uniq k -- | Default value variant. record_lookup_uniq_def :: Eq k => v -> k -> Record k v -> v record_lookup_uniq_def v k = fromMaybe v . record_lookup_uniq k -- | Remove all associations for key using given equality function. record_delete_by :: (k -> k -> Bool) -> k -> Record k v -> Record k v record_delete_by f k = filter (not . f k . fst) -- | 'record_delete_by' of '=='. record_delete :: Eq k => k -> Record k v -> Record k v record_delete = record_delete_by (==) -- * DB -- | Preserves order of occurence. db_key_set :: Ord k => DB k v -> [k] db_key_set = nub . map fst . concat db_lookup_by :: (k -> k -> Bool) -> (v -> v -> Bool) -> k -> v -> DB k v -> [Record k v] db_lookup_by k_cmp v_cmp k v = let f = any (v_cmp v) . record_lookup_by k_cmp k in filter f db_lookup :: (Eq k,Eq v) => k -> v -> DB k v -> [Record k v] db_lookup = db_lookup_by (==) (==) db_has_duplicate_keys :: Ord k => DB k v -> Bool db_has_duplicate_keys = any id . map record_has_duplicate_keys db_key_histogram :: Ord k => DB k v -> [(k,Int)] db_key_histogram db = let h = concatMap record_key_histogram db f k = (k,maximum (record_lookup k h)) in map f (db_key_set db) db_to_table :: Ord k => (Maybe v -> e) -> DB k v -> ([k],[[e]]) db_to_table f db = let kh = db_key_histogram db hdr = concatMap (\(k,n) -> replicate n k) kh ix = concatMap (\(k,n) -> zip (repeat k) [0 .. n - 1]) kh in (hdr,map (\r -> map (\i -> f (record_lookup_at i r)) ix) db) -- * Collating duplicate keys. record_collate' :: Eq k => (k,[v]) -> Record k v -> Record k [v] record_collate' (k,v) r = case r of [] -> [(k,reverse v)] (k',v'):r' -> if k == k' then record_collate' (k,v' : v) r' else (k,reverse v) : record_collate' (k',[v']) r' -- | Collate adjacent entries of existing sequence with equal key. record_collate :: Eq k => Record k v -> Record k [v] record_collate r = case r of [] -> error "record_collate: nil" (k,v):r' -> record_collate' (k,[v]) r' record_uncollate :: Record k [v] -> Record k v record_uncollate = concatMap (\(k,v) -> zip (repeat k) v)