Merge pull request #279 from status-im/feature/database-migration-#262

Database migrations #262

Former-commit-id: 4303570ebc
This commit is contained in:
Roman Volosovskyi 2016-10-04 18:33:11 +03:00 committed by GitHub
commit 9ad614422c
66 changed files with 1285 additions and 962 deletions

View File

@ -1,5 +1,5 @@
(ns status-im.accounts.handlers
(:require [status-im.models.accounts :as accounts-model]
(:require [status-im.data-store.accounts :as accounts-store]
[re-frame.core :refer [register-handler after dispatch dispatch-sync debug]]
[taoensso.timbre :as log]
[status-im.protocol.core :as protocol]
@ -19,7 +19,7 @@
(defn save-account [_ [_ account]]
(accounts-model/save-accounts [account] true))
(accounts-store/save account true))
(register-handler
:add-account
@ -54,9 +54,9 @@
password
#(account-created % password)))))
(defn save-account-to-realm!
(defn save-account!
[{:keys [current-account-id accounts]} _]
(accounts-model/save-accounts [(get accounts current-account-id)] true))
(accounts-store/save (get accounts current-account-id) true))
(defn send-account-update
[{:keys [current-account-id current-public-key web3 accounts]} _]
@ -79,7 +79,7 @@
account (-> (get accounts current-account-id)
(merge data))]
(assoc-in db [:accounts current-account-id] account)))
((after save-account-to-realm!))
((after save-account!))
((after send-account-update))))
(register-handler
@ -103,7 +103,7 @@
(register-handler :set-current-account set-current-account)
(defn load-accounts! [db _]
(let [accounts (->> (accounts-model/get-accounts)
(let [accounts (->> (accounts-store/get-all)
(map (fn [{:keys [address] :as account}]
[address account]))
(into {}))]

View File

@ -4,7 +4,7 @@
[taoensso.timbre :as log]
[status-im.utils.types :refer [json->clj]]
[status-im.db :refer [default-view]]
[status-im.persistence.realm.core :as realm]
[status-im.data-store.core :as data-store]
[status-im.components.status :as status]
[status-im.constants :refer [console-chat-id]]))
@ -29,24 +29,24 @@
(dispatch [:navigate-to default-view]))))
(register-handler
:change-realm-account
:change-account
(u/side-effect!
(fn [db [_ address new-account? callback]]
(realm/change-account-realm address new-account?
#(callback % address new-account?)))))
(data-store/change-account address new-account?
#(callback % address new-account?)))))
(defn on-account-changed
[error address new-account?]
(if (nil? error)
(initialize-account address new-account?)
(log/debug "Error changing acount realm: " error)))
(log/debug "Error changing acount: " error)))
(defn logged-in
[db address]
(let [is-login-screen? (= (:view-id db) :login)
new-account? (not is-login-screen?)]
(log/debug "Logged in: ")
(dispatch [:change-realm-account address new-account? on-account-changed])))
(dispatch [:change-account address new-account? on-account-changed])))
(register-handler
:login-account

View File

@ -1,7 +1,6 @@
(ns status-im.accounts.recover.validations
(:require [cljs.spec :as s]
[cljsjs.web3]
[status-im.persistence.realm.core :as realm]))
[cljsjs.web3]))
(s/def ::not-empty-string (s/and string? not-empty))
(s/def ::passphrase ::not-empty-string)

View File

@ -26,7 +26,7 @@
[status-im.group-settings.screen :refer [group-settings]]
[status-im.profile.screen :refer [profile my-profile]]
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
status-im.persistence.realm.core
status-im.data-store.core
[taoensso.timbre :as log]
[status-im.components.status :as status]))

View File

@ -6,10 +6,10 @@
[status-im.components.styles :refer [default-chat-color]]
[status-im.chat.suggestions :as suggestions]
[status-im.protocol.core :as protocol]
[status-im.models.chats :as chats]
[status-im.models.contacts :as contacts]
[status-im.models.messages :as messages]
[status-im.models.pending-messages :as pending-messages]
[status-im.data-store.chats :as chats]
[status-im.data-store.contacts :as contacts]
[status-im.data-store.messages :as messages]
[status-im.data-store.pending-messages :as pending-messages]
[status-im.constants :refer [text-content-type
content-type-command
content-type-command-request
@ -18,7 +18,6 @@
[status-im.chat.sign-up :as sign-up-service]
[status-im.navigation.handlers :as nav]
[status-im.utils.handlers :refer [register-handler] :as u]
[status-im.persistence.realm.core :as r]
[status-im.handlers.server :as server]
[status-im.utils.phone-number :refer [format-phone-number
valid-mobile-number?]]
@ -61,7 +60,7 @@
db
(let [messages-path [:chats current-chat-id :messages]
messages (get-in db messages-path)
new-messages (messages/get-messages current-chat-id (count messages))
new-messages (messages/get-by-chat-id current-chat-id (count messages))
all-loaded? (> default-number-of-messages (count new-messages))]
(-> db
(assoc :loading-allowed false)
@ -179,8 +178,8 @@
(if (chats console-chat-id)
db
(do
(chats/create-chat new-chat)
(contacts/save-contacts [sign-up-service/console-contact])
(chats/save new-chat)
(contacts/save-all [sign-up-service/console-contact])
(sign-up-service/intro)
(when existing-account?
(sign-up-service/start-signup))
@ -228,7 +227,7 @@
(defn load-messages!
([db] (load-messages! db nil))
([{:keys [current-chat-id] :as db} _]
(assoc db :messages (messages/get-messages current-chat-id))))
(assoc db :messages (messages/get-by-chat-id current-chat-id))))
(defn init-chat
([db] (init-chat db nil))
@ -261,7 +260,7 @@
(defn load-chats!
[db _]
(assoc db :loaded-chats (chats/chats-list)))
(assoc db :loaded-chats (chats/get-all)))
;TODO: check if its new account / signup status / create console chat
(register-handler :initialize-chats
@ -304,7 +303,7 @@
(defn save-new-chat!
[{:keys [new-chat]} _]
(chats/create-chat new-chat))
(chats/save new-chat))
(defn open-chat!
[_ [_ chat-id _ navigation-type]]
@ -341,7 +340,7 @@
; todo do we really need this message?
(defn leaving-message!
[{:keys [current-chat-id]} _]
(messages/save-message
(messages/save
current-chat-id
{:from "system"
:message-id (random/id)
@ -351,24 +350,15 @@
(defn delete-messages!
[{:keys [current-chat-id]} [_ chat-id]]
(let [id (or chat-id current-chat-id)]
(r/write :account
(fn []
(r/delete :account
(r/get-by-field :account :message :chat-id id))))))
(messages/delete-by-chat-id id)))
(defn delete-chat!
[_ [_ chat-id]]
(r/write :account
(fn [] :account
(when-let [chat (->> (r/get-by-field :account :chat :chat-id chat-id)
(r/single))]
(doto chat
(aset "is-active" false)
(aset "removed-at" (.getTime (js/Date.))))))))
(chats/delete chat-id))
(defn remove-pending-messages!
[_ [_ chat-id]]
(pending-messages/remove-all-by-chat chat-id))
(pending-messages/delete-all-by-chat-id chat-id))
(register-handler :leave-group-chat
;; todo oreder of operations tbd
@ -435,8 +425,8 @@
:message-id message-id}}))))
(register-handler :send-seen!
[(after (fn [_ [_ {:keys [message-id]}]]
(messages/update-message! {:message-id message-id
:message-status :seen})))
(messages/update {:message-id message-id
:message-status :seen})))
(after (fn [_ [_ {:keys [chat-id]}]]
(dispatch [:remove-unviewed-messages chat-id])))]
(u/side-effect! send-seen!))
@ -457,7 +447,7 @@
(defn update-chat!
[_ [_ chat]]
(chats/update-chat chat))
(chats/save chat))
(register-handler :update-chat!
(-> (fn [db [_ {:keys [chat-id] :as chat}]]

View File

@ -1,12 +1,12 @@
(ns status-im.chat.handlers.receive-message
(:require [status-im.utils.handlers :refer [register-handler] :as u]
[re-frame.core :refer [enrich after debug dispatch path]]
[status-im.models.messages :as messages]
[status-im.data-store.messages :as messages]
[status-im.chat.utils :as cu]
[status-im.commands.utils :refer [generate-hiccup]]
[status-im.constants :refer [content-type-command-request]]
[cljs.reader :refer [read-string]]
[status-im.models.chats :as c]))
[status-im.data-store.chats :as chats]))
(defn check-preview [{:keys [content] :as message}]
(if-let [preview (:preview content)]
@ -17,7 +17,7 @@
message))
(defn store-message [{chat-id :chat-id :as message}]
(messages/save-message chat-id (dissoc message :rendered-preview :new?)))
(messages/save chat-id (dissoc message :rendered-preview :new?)))
(defn get-current-identity
[{:keys [current-account-id accounts]}]
@ -25,11 +25,11 @@
(defn receive-message
[db [_ {:keys [from group-id chat-id message-id] :as message}]]
(let [same-message (messages/get-message message-id)
(let [same-message (messages/get-by-id message-id)
current-identity (get-current-identity db)
chat-id' (or group-id chat-id from)
exists? (c/chat-exists? chat-id')
active? (c/is-active? chat-id')]
exists? (chats/exists? chat-id')
active? (chats/is-active? chat-id')]
(when (and (not same-message)
(not= from current-identity)
(or (not exists?) active?))

View File

@ -1,13 +1,12 @@
(ns status-im.chat.handlers.requests
(:require [re-frame.core :refer [after dispatch enrich]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.models.requests :as requests]
[status-im.utils.handlers :refer [register-handler] :as u]
[status-im.persistence.realm.core :as realm]))
[status-im.data-store.requests :as requests]
[status-im.utils.handlers :refer [register-handler] :as u]))
(defn store-request!
[{:keys [new-request] :as db}]
(requests/save-request new-request))
(requests/save new-request))
(defn add-request
[db [_ chat-id {:keys [message-id content]}]]
@ -23,23 +22,14 @@
(defn load-requests!
[{:keys [current-chat-id] :as db} [_ chat-id]]
(let [chat-id' (or chat-id current-chat-id)
requests (-> ;; todo maybe limit is needed
(realm/get-by-fields :account :request :and [[:chat-id chat-id']
[:status "open"]])
(realm/sorted :added :desc)
(realm/realm-collection->list))
;; todo maybe limit is needed
requests (requests/get-open-by-chat-id chat-id')
requests' (map #(update % :type keyword) requests)]
(assoc-in db [:chats chat-id' :requests] requests')))
(defn mark-request-as-answered!
[_ [_ chat-id message-id]]
(realm/write :account
(fn []
(-> (realm/get-by-fields :account :request :and [[:chat-id chat-id]
[:message-id message-id]])
(realm/single)
(.-status)
(set! "answered")))))
(requests/mark-as-answered chat-id message-id))
(register-handler :add-request
(after store-request!)

View File

@ -1,7 +1,7 @@
(ns status-im.chat.handlers.send-message
(:require [status-im.utils.handlers :refer [register-handler] :as u]
[clojure.string :as s]
[status-im.models.messages :as messages]
[status-im.data-store.messages :as messages]
[status-im.components.status :as status]
[status-im.utils.random :as random]
[status-im.utils.datetime :as time]
@ -97,7 +97,7 @@
(register-handler ::save-command!
(u/side-effect!
(fn [{:keys [current-public-key]} [_ {:keys [command chat-id]}]]
(messages/save-message
(messages/save
chat-id
(dissoc command :rendered-preview :to-message :has-handler)))))
@ -154,7 +154,7 @@
(dispatch [::send-message! params])))
(u/side-effect!
(fn [_ [_ {:keys [chat-id message]}]]
(messages/save-message chat-id message))))
(messages/save chat-id message))))
(register-handler ::send-message!
(u/side-effect!

View File

@ -1,12 +1,7 @@
(ns status-im.chat.handlers.unviewed-messages
(:require [re-frame.core :refer [after enrich path dispatch]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.persistence.realm.core :as realm]))
(defn delivered-messages []
(-> (realm/get-by-fields :account :message :and {:outgoing false
:message-status nil})
(realm/realm-collection->list)))
[status-im.data-store.messages :as messages]))
(defn set-unviewed-messages [db]
(let [messages (->> (::raw-unviewed-messages db)
@ -20,7 +15,7 @@
(dissoc ::raw-unviewed-messages))))
(defn load-messages! [db]
(let [messages (delivered-messages)]
(let [messages (messages/get-unviewed)]
(assoc db ::raw-unviewed-messages messages)))
(register-handler ::set-unviewed-messages set-unviewed-messages)
@ -39,4 +34,4 @@
(register-handler :remove-unviewed-messages
(path :unviewed-messages)
(fn [db [_ chat-id]]
(dissoc db chat-id)))
(dissoc db chat-id)))

View File

@ -44,4 +44,4 @@
{:margin-top 10.5
:margin-left 12
:width 15
:height 15})
:height 15})

View File

@ -3,7 +3,7 @@
(:require [re-frame.core :refer [register-sub dispatch subscribe path]]
[status-im.utils.platform :refer [ios?]]
[status-im.models.commands :as commands]
[status-im.models.chats :as chats]
[status-im.data-store.chats :as chats]
[status-im.constants :refer [response-suggesstion-resize-duration]]
[status-im.chat.constants :as c]
[status-im.chat.views.plain-message :as plain-message]
@ -50,7 +50,7 @@
(register-sub :get-chat-by-id
(fn [_ [_ chat-id]]
(reaction (chats/chat-by-id chat-id))))
(reaction (chats/get-by-id chat-id))))
(register-sub :get-responses
(fn [db _]

View File

@ -13,7 +13,6 @@
[status-im.chat.views.request-message :refer [message-content-command-request]]
[status-im.chat.styles.message :as st]
[status-im.chat.styles.command-pill :as pill-st]
[status-im.models.chats :refer [chat-by-id]]
[status-im.models.commands :refer [parse-command-message-content
parse-command-request]]
[status-im.resources :as res]

View File

@ -4,7 +4,7 @@
[status-im.utils.handlers :as u]
[status-im.utils.utils :refer [http-get show-popup]]
[clojure.string :as s]
[status-im.persistence.realm.core :as realm]
[status-im.data-store.commands :as commands]
[status-im.components.status :as status]
[status-im.utils.types :refer [json->clj]]
[status-im.commands.utils :refer [reg-handler]]
@ -16,8 +16,7 @@
[_ [identity]]
(dispatch [::fetch-commands! identity])
;; todo uncomment
#_(if-let [{:keys [file]} (realm/get-one-by-field :account :command
:chat-id identity)]
#_(if-let [{:keys [file]} (commands/get-by-chat-id identity)]
(dispatch [::parse-commands! identity file])
(dispatch [::fetch-commands! identity])))
@ -85,7 +84,7 @@
(defn save-commands-js!
[_ [id file]]
(realm/create-object :account :command {:chat-id id :file file}))
(commands/save {:chat-id id :file file}))
(defn loading-failed!
[db [id reason details]]

View File

@ -1,7 +1,7 @@
(ns status-im.contacts.handlers
(:require [re-frame.core :refer [after dispatch]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.models.contacts :as contacts]
[status-im.data-store.contacts :as contacts]
[status-im.utils.crypt :refer [encrypt]]
[clojure.string :as s]
[status-im.protocol.core :as protocol]
@ -30,7 +30,7 @@
(defn save-contact
[_ [_ contact]]
(contacts/save-contacts [contact]))
(contacts/save contact))
(defn watch-contact
[{:keys [web3]} [_ {:keys [whisper-identity public-key private-key]}]]
@ -64,7 +64,7 @@
((after save-contact))))
(defn load-contacts! [db _]
(let [contacts (->> (contacts/get-contacts)
(let [contacts (->> (contacts/get-all)
(map (fn [{:keys [whisper-identity] :as contact}]
[whisper-identity contact]))
(into {}))]
@ -136,7 +136,7 @@
(u/side-effect! get-identities-by-contacts!))
(defn save-contacts! [{:keys [new-contacts]} _]
(contacts/save-contacts new-contacts))
(contacts/save-all new-contacts))
(defn update-pending-status [old-contacts {:keys [whisper-identity pending] :as contact}]
(let [{old-pending :pending
@ -169,7 +169,7 @@
(register-handler :add-new-contact
(u/side-effect!
(fn [_ [_ {:keys [whisper-identity] :as contact}]]
(when-not (contacts/get-contact whisper-identity)
(when-not (contacts/get-by-id whisper-identity)
(dispatch [::prepare-contact contact])))))
(register-handler ::prepare-contact

View File

@ -1,13 +1,13 @@
(ns status-im.contacts.validations
(:require [cljs.spec :as s]
[cljsjs.web3]
[status-im.persistence.realm.core :as realm]))
[status-im.data-store.contacts :as contacts]))
(defn is-address? [s]
(.isAddress js/Web3.prototype s))
(defn unique-identity? [identity]
(not (realm/exists? :account :contact {:whisper-identity identity})))
(not (contacts/exists? identity)))
(defn valid-length? [identity]
(let [length (count identity)]

View File

@ -0,0 +1,14 @@
(ns status-im.data-store.accounts
(:require [status-im.data-store.realm.accounts :as data-store]))
(defn get-all []
(data-store/get-all-as-list))
(defn get-by-address [address]
(data-store/get-by-address address))
(defn save [account update?]
(data-store/save account update?))
(defn save-all [accounts update?]
(data-store/save-all accounts update?))

View File

@ -0,0 +1,73 @@
(ns status-im.data-store.chats
(:require [status-im.data-store.realm.chats :as data-store]
[re-frame.core :refer [dispatch]])
(:refer-clojure :exclude [exists?]))
(defn- normalize-contacts
[chats]
(map #(update % :contacts vals) chats))
(defn get-all
[]
(-> (data-store/get-all-active)
normalize-contacts))
(defn get-by-id
[id]
(data-store/get-by-id id))
(defn exists?
[chat-id]
(data-store/exists? chat-id))
(defn save
[{:keys [last-message-id chat-id] :as chat}]
(let [chat (assoc chat :last-message-id (or last-message-id ""))]
(data-store/save chat (data-store/exists? chat-id))))
(defn delete
[chat-id]
(data-store/delete chat-id))
(defn get-contacts
[chat-id]
(data-store/get-contacts chat-id))
(defn has-contact?
[chat-id identity]
(data-store/has-contact? chat-id identity))
(defn add-contacts
[chat-id identities]
(data-store/add-contacts chat-id identities)
; TODO: move this somewhere else
; TODO: temp. Update chat in db atom
(dispatch [:initialize-chats]))
(defn remove-contacts
[chat-id identities]
(data-store/remove-contacts chat-id identities))
(defn save-property
[chat-id property-name value]
(data-store/save-property chat-id property-name value))
(defn get-property
[chat-id property-name]
(data-store/get-property chat-id property-name))
(defn is-active?
[chat-id]
(get-property chat-id :is-active))
(defn removed-at
[chat-id]
(get-property chat-id :removed-at))
(defn get-active-group-chats
[]
(data-store/get-active-group-chats))
(defn set-active
[chat-id active?]
(save-property chat-id :is-active active?))

View File

@ -0,0 +1,10 @@
(ns status-im.data-store.commands
(:require [status-im.data-store.realm.commands :as data-store]))
(defn get-by-chat-id
[chat-id]
(data-store/get-by-chat-id chat-id))
(defn save
[command]
(data-store/save command))

View File

@ -0,0 +1,28 @@
(ns status-im.data-store.contacts
(:require [status-im.data-store.realm.contacts :as data-store])
(:refer-clojure :exclude [exists?]))
(defn get-all
[]
(data-store/get-all-as-list))
(defn get-by-id
[whisper-identity]
(data-store/get-by-id whisper-identity))
(defn save
[{:keys [whisper-identity pending] :as contact}]
(let [{pending-db :pending
:as contact-db} (data-store/get-by-id whisper-identity)
contact (assoc contact :pending (boolean (if contact-db
(and pending-db pending)
pending)))]
(data-store/save contact (if contact-db true false))))
(defn save-all
[contacts]
(mapv save contacts))
(defn exists?
[whisper-identity]
(data-store/exists? whisper-identity))

View File

@ -0,0 +1,10 @@
(ns status-im.data-store.core
(:require [taoensso.timbre :as log]
[status-im.data-store.realm.core :as data-source]))
(defn init []
(data-source/reset-account))
(defn change-account [address new-account? handler]
(data-source/change-account address new-account? handler))

View File

@ -0,0 +1,23 @@
(ns status-im.data-store.discovery
(:require [status-im.data-store.realm.discovery :as data-store]))
(defn get-all
[]
(->> (data-store/get-all-as-list)
(mapv #(update % :tags vals))))
(defn save
[discovery]
(data-store/save discovery))
(defn save-all
[discoveries]
(data-store/save-all discoveries))
(defn delete
[by ordering critical-count to-delete-count]
(data-store/delete by ordering critical-count to-delete-count))
(defn get-all-tags
[]
(data-store/get-all-tags))

View File

@ -0,0 +1,92 @@
(ns status-im.data-store.messages
(:require [status-im.data-store.realm.messages :as data-store]
[clojure.string :refer [join split]]
[status-im.utils.random :refer [timestamp]]
[clojure.walk :refer [stringify-keys keywordize-keys]]
[status-im.commands.utils :refer [generate-hiccup]]
[cljs.reader :refer [read-string]]
[status-im.constants :as c])
(:refer-clojure :exclude [update]))
(defn- map-to-str
[m]
(join ";" (map #(join "=" %) (stringify-keys m))))
(defn- str-to-map
[s]
(keywordize-keys (apply hash-map (split s #"[;=]"))))
(defn- user-statuses-to-map
[user-statuses]
(->> (vals user-statuses)
(mapv (fn [{:keys [whisper-identity] :as status}]
[whisper-identity status]))
(into {})))
(defn- command-type?
[type]
(contains?
#{c/content-type-command c/content-type-command-request}
type))
(def default-values
{:outgoing false
:to nil
:same-author false
:same-direction false
:preview nil})
(defn get-by-id
[message-id]
(some-> (data-store/get-by-id message-id)
(clojure.core/update :user-statuses user-statuses-to-map)))
(defn get-by-chat-id
([chat-id]
(get-by-chat-id chat-id 0))
([chat-id from]
(->> (data-store/get-by-chat-id chat-id from c/default-number-of-messages)
(mapv #(clojure.core/update % :user-statuses user-statuses-to-map))
(into '())
reverse
(keep (fn [{:keys [content-type preview] :as message}]
(if (command-type? content-type)
(-> message
(clojure.core/update :content str-to-map)
(assoc :rendered-preview
(when preview
(generate-hiccup (read-string preview)))))
message))))))
(defn get-last-message
[chat-id]
(data-store/get-last-message chat-id))
(defn get-unviewed
[]
(data-store/get-unviewed))
(defn save
;; todo remove chat-id parameter
[chat-id {:keys [message-id content]
:as message}]
(when-not (data-store/exists? message-id)
(let [content' (if (string? content)
content
(map-to-str content))
message' (merge default-values
message
{:chat-id chat-id
:content content'
:timestamp (timestamp)})]
(data-store/save message'))))
(defn update
[{:keys [message-id] :as message}]
(when (data-store/exists? message-id)
(let [message (clojure.core/update message :user-statuses vals)]
(data-store/save message))))
(defn delete-by-chat-id [chat-id]
(data-store/delete-by-chat-id chat-id))

View File

@ -0,0 +1,48 @@
(ns status-im.data-store.pending-messages
(:require [status-im.data-store.realm.pending-messages :as data-store]
[clojure.string :as str]
[status-im.utils.hex :as i]))
(defn- get-id
[message-id to]
(let [to' (i/normalize-hex to)
to'' (when to' (subs to' 0 7))
id' (if to''
(str message-id "-" (subs to'' 0 7))
message-id)]
id'))
(defn get-all
[]
(data-store/get-all-as-list))
(defn get-by-chat-id
[chat-id]
(data-store/get-by-chat-id chat-id))
(defn get-by-message-id
[message-id]
(data-store/get-by-message-id message-id))
(defn save
[{:keys [id to group-id message] :as pending-message}]
(let [{:keys [from topics payload]} message
id' (get-id id to)
chat-id (or group-id to)
message' (-> pending-message
(assoc :id id'
:from from
:message-id id
:chat-id chat-id
:payload payload
:topics (prn-str topics))
(dissoc :message))]
(data-store/save message')))
(defn delete
[pending-message]
(data-store/delete pending-message))
(defn delete-all-by-chat-id
[chat-id]
(data-store/delete-all-by-chat-id chat-id))

View File

@ -0,0 +1,21 @@
(ns status-im.data-store.realm.accounts
(:require [status-im.data-store.realm.core :as realm]))
(defn get-all []
(realm/get-all realm/base-realm :account))
(defn get-all-as-list []
(-> (get-all)
realm/realm-collection->list))
(defn get-by-address [address]
(realm/get-one-by-field-clj realm/base-realm :account :address address))
(defn save [account update?]
(realm/write realm/base-realm
#(realm/create realm/base-realm :account account update?)))
(defn save-all [accounts update?]
(realm/write realm/base-realm
(fn []
(mapv #(realm/create realm/base-realm :account % update?) accounts))))

View File

@ -0,0 +1,112 @@
(ns status-im.data-store.realm.chats
(:require [status-im.data-store.realm.core :as realm]
[status-im.utils.random :refer [timestamp]])
(:refer-clojure :exclude [exists?]))
(defn get-all
[]
(-> (realm/get-all @realm/account-realm :chat)
(realm/sorted :timestamp :desc)))
(defn get-all-as-list
[]
(-> (get-all)
realm/realm-collection->list))
(defn get-all-active
[]
(-> (realm/get-by-field @realm/account-realm :chat :is-active true)
(realm/sorted :timestamp :desc)
realm/realm-collection->list))
(defn- groups
[active?]
(realm/filtered (get-all)
(str "group-chat = true && is-active = "
(if active? "true" "false"))))
(defn get-active-group-chats
[]
(map
(fn [{:keys [chat-id public-key private-key]}]
{:chat-id chat-id
:keypair {:private private-key
:public public-key}})
(realm/realm-collection->list (groups true))))
(defn get-by-id
[chat-id]
(-> (realm/get-one-by-field-clj @realm/account-realm :chat :chat-id chat-id)
(realm/list->array :contacts)))
(defn save
[chat update?]
(realm/save @realm/account-realm :chat chat update?))
(defn exists?
[chat-id]
(realm/exists? @realm/account-realm :chat {:chat-id chat-id}))
(defn delete
[chat-id]
(when-let [chat (get-by-id chat-id)]
(realm/write @realm/account-realm
(fn []
(doto chat
(aset "is-active" false)
(aset "removed-at" timestamp))))))
(defn get-contacts
[chat-id]
(-> (realm/get-one-by-field @realm/account-realm :chat :chat-id chat-id)
(aget "contacts")))
(defn has-contact?
[chat-id identity]
(let [contacts (get-contacts chat-id)
contact (.find contacts (fn [object index collection]
(= identity (aget object "identity"))))]
(if contact true false)))
(defn- save-contacts
[identities contacts added-at]
(doseq [contact-identity identities]
(if-let [contact (.find contacts (fn [object index collection]
(= contact-identity (aget object "identity"))))]
(doto contact
(aset "is-in-chat" true)
(aset "added-at" added-at))
(.push contacts (clj->js {:identity contact-identity
:added-at added-at})))))
(defn add-contacts
[chat-id identities]
(let [contacts (get-contacts chat-id)
added-at (timestamp)]
(realm/write @realm/account-realm
#(save-contacts identities contacts added-at))))
(defn- delete-contacts
[identities contacts]
(doseq [contact-identity identities]
(when-let [contact (.find contacts (fn [object index collection]
(= contact-identity (aget object "identity"))))]
(realm/delete @realm/account-realm contact))))
(defn remove-contacts
[chat-id identities]
(let [contacts (get-contacts chat-id)]
(realm/write @realm/account-realm
#(delete-contacts identities contacts))))
(defn save-property
[chat-id property-name value]
(realm/write @realm/account-realm
(fn []
(-> (realm/get-one-by-field @realm/account-realm :chat :chat-id chat-id)
(aset (name property-name) value)))))
(defn get-property
[chat-id property]
(when-let [chat (realm/get-one-by-field @realm/account-realm :chat :chat-id chat-id)]
(aget chat (name property))))

View File

@ -0,0 +1,11 @@
(ns status-im.data-store.realm.commands
(:require [status-im.data-store.realm.core :as realm]))
(defn get-by-chat-id
[chat-id]
(realm/get-one-by-field-clj @realm/account-realm :command
:chat-id identity))
(defn save
[command]
(realm/save @realm/account-realm :command command true))

View File

@ -0,0 +1,25 @@
(ns status-im.data-store.realm.contacts
(:require [status-im.data-store.realm.core :as realm])
(:refer-clojure :exclude [exists?]))
(defn get-all
[]
(-> (realm/get-all @realm/account-realm :contact)
(realm/sorted :name :asc)))
(defn get-all-as-list
[]
(-> (get-all)
realm/realm-collection->list))
(defn get-by-id
[whisper-identity]
(realm/get-one-by-field-clj @realm/account-realm :contact :whisper-identity whisper-identity))
(defn save
[contact update?]
(realm/save @realm/account-realm :contact contact update?))
(defn exists?
[whisper-identity]
(realm/exists? @realm/account-realm :contact {:whisper-identity whisper-identity}))

View File

@ -0,0 +1,187 @@
(ns status-im.data-store.realm.core
(:require [status-im.utils.utils :as u]
[status-im.utils.types :refer [to-string]]
[status-im.data-store.realm.schemas.account.core :as account]
[status-im.data-store.realm.schemas.base.core :as base]
[taoensso.timbre :as log]
[status-im.utils.fs :as fs]
[clojure.string :as str])
(:refer-clojure :exclude [exists?]))
(def realm-class (u/require "realm"))
(defn realm-version
[file-name]
(.schemaVersion realm-class file-name))
(defn open-realm
[options file-name]
(let [options (merge options {:path file-name})]
(when (cljs.core/exists? js/window)
(realm-class. (clj->js options)))))
(defn close [realm]
(.close realm))
(defn migrate [file-name schemas]
(let [current-version (realm-version file-name)]
(doseq [schema schemas
:when (> (:schemaVersion schema) current-version)
:let [migrated-realm (open-realm schema file-name)]]
(close migrated-realm))))
(defn open-migrated-realm
[file-name schemas]
(migrate file-name schemas)
(open-realm (last schemas) file-name))
(def new-account-filename "new-account")
(def new-accout-realm-file (str new-account-filename ".realm"))
(def base-realm (open-migrated-realm (.-defaultPath realm-class) base/schemas))
(def account-realm (atom (open-migrated-realm new-account-filename account/schemas)))
(defn close-account-realm []
(close @account-realm)
(reset! account-realm nil))
(defn reset-account []
(when @account-realm
(close @account-realm))
(reset! account-realm (open-migrated-realm new-account-filename account/schemas))
(.write @account-realm #(.deleteAll @account-realm)))
(defn move-file-handler [address err handler]
(log/debug "Moved file with error: " err address)
(if err
(log/error "Error moving account realm: " (.-message err))
(reset! account-realm (open-migrated-realm address account/schemas)))
(handler err))
(defn change-account [address new-account? handler]
(let [path (.-path @account-realm)]
(log/debug "closing account realm: " path)
(close-account-realm)
(log/debug "is new account? " new-account?)
(if new-account?
(let [new-path (str/replace path new-accout-realm-file (str address ".realm"))]
(log/debug "Moving file to " new-path)
(fs/move-file path new-path #(move-file-handler address % handler)))
(do
(reset! account-realm (open-migrated-realm address account/schemas))
(handler nil)))))
; realm functions
(defn and-query [queries]
(str/join " and " queries))
(defn or-query [queries]
(str/join " or " queries))
(defn write [realm f]
(.write realm f))
(defn create
([realm schema-name obj]
(create realm schema-name obj false))
([realm schema-name obj update?]
(.create realm (to-string schema-name) (clj->js obj) update?)))
(defn save
([realm schema-name obj]
(save realm schema-name obj false))
([realm schema-name obj update?]
(write realm #(create realm schema-name obj update?))))
(defn save-all
([realm schema-name objs]
(save-all realm schema-name objs false))
([realm schema-name objs update?]
(write realm (fn []
(mapv #(save realm schema-name % update?) objs)))))
(defn delete [realm obj]
(write realm #(.delete realm obj)))
(defn get-all [realm schema-name]
(.objects realm (to-string schema-name)))
(defn sorted [results field-name order]
(.sorted results (to-string field-name) (if (= order :asc)
false
true)))
(defn get-count [objs]
(.-length objs))
(defn page [results from to]
(js/Array.prototype.slice.call results from to))
(defn filtered [results filter-query]
(.filtered results filter-query))
(defn realm-collection->list [collection]
(-> (.map collection (fn [object _ _] object))
(js->clj :keywordize-keys true)))
(defn list->array [record list-field]
(update-in record [list-field] (comp vec vals)))
(defn single [result]
(-> (aget result 0)))
(defn single-cljs [result]
(some-> (aget result 0)
(js->clj :keywordize-keys true)))
(defn get-by-filter [realm schema-name filter]
(-> (.objects realm (name schema-name))
(.filtered filter)))
(defn- get-schema-by-name [opts]
(->> opts
(mapv (fn [{:keys [name] :as schema}]
[(keyword name) schema]))
(into {})))
(defn- field-type [realm schema-name field]
(let [schema-by-name (get-schema-by-name (js->clj (.-schema realm) :keywordize-keys true))
field-def (get-in schema-by-name [schema-name :properties field])]
(if (map? field-def)
(:type field-def)
field-def)))
(defmulti to-query (fn [realm schema-name operator field value]
operator))
(defmethod to-query :eq [realm schema-name operator field value]
(let [value (to-string value)
field-type (field-type realm schema-name field)
query (str (name field) "=" (if (= "string" (name field-type))
(str "\"" value "\"")
value))]
query))
(defn get-by-field [realm schema-name field value]
(let [q (to-query realm schema-name :eq field value)]
(.filtered (.objects realm (name schema-name)) q)))
(defn get-one-by-field [realm schema-name field value]
(single (get-by-field realm schema-name field value)))
(defn get-one-by-field-clj [realm schema-name field value]
(single-cljs (get-by-field realm schema-name field value)))
(defn get-by-fields [realm schema-name op fields]
(let [queries (map (fn [[k v]]
(to-query realm schema-name :eq k v))
fields)]
(.filtered (.objects realm (name schema-name))
(case op
:and (and-query queries)
:or (or-query queries)))))
(defn exists? [realm schema-name fields]
(pos? (.-length (get-by-fields realm schema-name :and fields))))

View File

@ -0,0 +1,73 @@
(ns status-im.data-store.realm.discovery
(:require [status-im.data-store.realm.core :as realm]
[taoensso.timbre :as log]))
(defn get-all
[]
(-> (realm/get-all @realm/account-realm :discovery)
(realm/sorted :priority :desc)))
(defn get-all-as-list
[]
(-> (get-all)
realm/realm-collection->list))
(defn get-tag-by-name [tag]
(log/debug "Getting tag: " tag)
(realm/get-one-by-field-clj @realm/account-realm :tag :name tag))
(defn- update-tag-counter [func tag]
(let [tag (:name tag)
tag-object (get-tag-by-name tag)]
(if tag-object
(realm/create @realm/account-realm :tag
{:name tag
:count (func (:count tag-object))}
true))))
(defn- update-tags-counter [func tags]
(doseq [tag (distinct tags)]
(update-tag-counter func tag)))
(defn- get-tags
[message-id]
(-> (realm/get-one-by-field-clj @realm/account-realm :discovery :message-id message-id)
(:tags)
(vals)))
(defn- upsert-discovery [{:keys [message-id tags] :as discovery}]
(log/debug "Creating/updating discovery with tags: " tags)
(let [prev-tags (get-tags message-id)]
(if prev-tags
(update-tags-counter dec prev-tags))
(realm/create @realm/account-realm :discovery discovery true)
(update-tags-counter inc tags)))
(defn save
[discovery]
(realm/write @realm/account-realm
#(upsert-discovery discovery)))
(defn save-all
[discoveries]
(realm/write @realm/account-realm
(fn []
(doseq [discovery discoveries]
(upsert-discovery discovery)))))
(defn delete
[by ordering critical-count to-delete-count]
(let [discoveries (realm/get-all @realm/account-realm :discovery)
count (realm/get-count discoveries)]
(if (> count critical-count)
(let [to-delete (-> (realm/sorted discoveries by ordering)
(realm/page 0 to-delete-count))]
(realm/write @realm/account-realm
(fn []
(log/debug (str "Deleting " (realm/get-count to-delete) " discoveries"))
(realm/delete @realm/account-realm to-delete)))))))
(defn get-all-tags []
(-> (realm/get-all @realm/account-realm :tag)
(realm/sorted :count :desc)
realm/realm-collection->list))

View File

@ -0,0 +1,55 @@
(ns status-im.data-store.realm.messages
(:require [status-im.data-store.realm.core :as realm])
(:refer-clojure :exclude [exists?]))
(defn get-all
[]
(realm/get-all @realm/account-realm :message))
(defn get-all-as-list
[]
(-> (get-all)
realm/realm-collection->list))
(defn get-by-id
[message-id]
(realm/get-one-by-field-clj @realm/account-realm :message :message-id message-id))
(defn get-by-chat-id
([chat-id]
(realm/get-by-field @realm/account-realm :message :chat-id chat-id))
([chat-id number-of-messages]
(get-by-chat-id chat-id 0 number-of-messages))
([chat-id from number-of-messages]
(-> (realm/get-by-field @realm/account-realm :message :chat-id chat-id)
(realm/sorted :timestamp :desc)
(realm/page from (+ from number-of-messages))
(realm/realm-collection->list))))
(defn get-last-message
[chat-id]
(-> (realm/get-by-field @realm/account-realm :message :chat-id chat-id)
(realm/sorted :timestamp :desc)
(realm/single)
(js->clj :keywordize-keys true)))
(defn get-unviewed
[]
(-> (realm/get-by-fields @realm/account-realm :message :and {:outgoing false
:message-status nil})
(realm/realm-collection->list)))
(defn exists?
[message-id]
(realm/exists? @realm/account-realm :message {:message-id message-id}))
(defn save
[message]
(realm/save @realm/account-realm :message message true))
(defn delete-by-chat-id
[chat-id]
(realm/write @realm/account-realm
#(realm/delete @realm/account-realm
(get-by-chat-id chat-id))))

View File

@ -0,0 +1,35 @@
(ns status-im.data-store.realm.pending-messages
(:require [status-im.data-store.realm.core :as realm]
[cljs.reader :refer [read-string]]))
(defn get-all
[]
(realm/get-all @realm/account-realm :pending-message))
(defn get-all-as-list
[]
(->> (get-all)
realm/realm-collection->list
(map (fn [message]
(update message :topics read-string)))))
(defn get-by-message-id
[message-id]
(realm/get-by-field @realm/account-realm :pending-message :message-id message-id))
(defn get-by-chat-id
[chat-id]
(realm/get-by-field @realm/account-realm :pending-message :chat-id chat-id))
(defn save
[pending-message]
(realm/save @realm/account-realm :pending-message pending-message true))
(defn delete
[{{:keys [message-id ack-of-message]} :payload}]
(let [message-id (or ack-of-message message-id)]
(realm/delete @realm/account-realm (get-by-message-id message-id))))
(defn delete-all-by-chat-id
[chat-id]
(realm/delete @realm/account-realm (get-by-chat-id chat-id)))

View File

@ -0,0 +1,40 @@
(ns status-im.data-store.realm.requests
(:require [status-im.data-store.realm.core :as realm]))
(defn get-all
[]
(realm/get-all @realm/account-realm :request))
(defn get-all-as-list
[]
(-> (get-all)
realm/realm-collection->list))
(defn get-open-by-chat-id
[chat-id]
(-> (realm/get-by-fields @realm/account-realm :request :and [[:chat-id chat-id]
[:status "open"]])
(realm/sorted :added :desc)
(realm/realm-collection->list)))
(defn save
[request]
(realm/save @realm/account-realm :request request true))
(defn save-all
[requests]
(realm/save-all @realm/account-realm :request requests true))
(defn- get-by-message-id
[chat-id message-id]
(-> (realm/get-by-fields @realm/account-realm :request :and [[:chat-id chat-id]
[:message-id message-id]])
(realm/single)))
(defn mark-as-answered
[chat-id message-id]
(realm/write @realm/account-realm
(fn []
(-> (get-by-message-id chat-id message-id)
(.-status)
(set! "answered")))))

View File

@ -0,0 +1,7 @@
(ns status-im.data-store.realm.schemas.account.core
(:require [status-im.data-store.realm.schemas.account.v1.core :as v1]))
; put schemas ordered by version
(def schemas [{:schema v1/schema
:schemaVersion 1
:migration v1/migration}])

View File

@ -0,0 +1,10 @@
(ns status-im.data-store.realm.schemas.account.v1.chat-contact
(:require [taoensso.timbre :as log]))
(def schema {:name :chat-contact
:properties {:identity "string"
:is-in-chat {:type "bool"
:default true}}})
(defn migration [old-realm new-realm]
(log/debug "migrating chat-contact schema"))

View File

@ -0,0 +1,30 @@
(ns status-im.data-store.realm.schemas.account.v1.chat
(:require [taoensso.timbre :as log]
[status-im.components.styles :refer [default-chat-color]]))
(def schema {:name :chat
:primaryKey :chat-id
:properties {:chat-id "string"
:name "string"
:color {:type "string"
:default default-chat-color}
:group-chat {:type "bool"
:indexed true}
:is-active "bool"
:timestamp "int"
:contacts {:type "list"
:objectType "chat-contact"}
:dapp-url {:type :string
:optional true}
:dapp-hash {:type :int
:optional true}
:removed-at {:type :int
:optional true}
:last-message-id "string"
:public-key {:type :string
:optional true}
:private-key {:type :string
:optional true}}})
(defn migration [old-realm new-realm]
(log/debug "migrating chat schema"))

View File

@ -0,0 +1,10 @@
(ns status-im.data-store.realm.schemas.account.v1.command
(:require [taoensso.timbre :as log]))
(def schema {:name :command
:primaryKey :chat-id
:properties {:chat-id "string"
:file "string"}})
(defn migration [old-realm new-realm]
(log/debug "migrating command schema"))

View File

@ -0,0 +1,21 @@
(ns status-im.data-store.realm.schemas.account.v1.contact
(:require [taoensso.timbre :as log]))
(def schema {:name :contact
:primaryKey :whisper-identity
:properties {:address {:type "string" :optional true}
:whisper-identity "string"
:name {:type "string" :optional true}
:photo-path {:type "string" :optional true}
:last-updated {:type "int" :default 0}
:last-online {:type "int" :default 0}
:pending {:type "bool" :default false}
:public-key {:type :string
:optional true}
:private-key {:type :string
:optional true}
:dapp? {:type :bool
:default false}}})
(defn migration [old-realm new-realm]
(log/debug "migrating contact schema"))

View File

@ -0,0 +1,39 @@
(ns status-im.data-store.realm.schemas.account.v1.core
(:require [status-im.data-store.realm.schemas.account.v1.chat :as chat]
[status-im.data-store.realm.schemas.account.v1.chat-contact :as chat-contact]
[status-im.data-store.realm.schemas.account.v1.command :as command]
[status-im.data-store.realm.schemas.account.v1.contact :as contact]
[status-im.data-store.realm.schemas.account.v1.discovery :as discovery]
[status-im.data-store.realm.schemas.account.v1.kv-store :as kv-store]
[status-im.data-store.realm.schemas.account.v1.message :as message]
[status-im.data-store.realm.schemas.account.v1.pending-message :as pending-message]
[status-im.data-store.realm.schemas.account.v1.request :as request]
[status-im.data-store.realm.schemas.account.v1.tag :as tag]
[status-im.data-store.realm.schemas.account.v1.user-status :as user-status]
[taoensso.timbre :as log]))
(def schema [chat/schema
chat-contact/schema
command/schema
contact/schema
discovery/schema
kv-store/schema
message/schema
pending-message/schema
request/schema
tag/schema
user-status/schema])
(defn migration [old-realm new-realm]
(log/debug "migrating v1 account database: " old-realm new-realm)
(chat/migration old-realm new-realm)
(chat-contact/migration old-realm new-realm)
(command/migration old-realm new-realm)
(contact/migration old-realm new-realm)
(discovery/migration old-realm new-realm)
(kv-store/migration old-realm new-realm)
(message/migration old-realm new-realm)
(pending-message/migration old-realm new-realm)
(request/migration old-realm new-realm)
(tag/migration old-realm new-realm)
(user-status/migration old-realm new-realm))

View File

@ -0,0 +1,17 @@
(ns status-im.data-store.realm.schemas.account.v1.discovery
(:require [taoensso.timbre :as log]))
(def schema {:name :discovery
:primaryKey :message-id
:properties {:message-id "string"
:name {:type "string" :optional true}
:status "string"
:whisper-id "string"
:photo-path {:type "string" :optional true}
:tags {:type "list"
:objectType "tag"}
:priority {:type "int" :default 0}
:last-updated "date"}})
(defn migration [old-realm new-realm]
(log/debug "migrating discovery schema"))

View File

@ -0,0 +1,10 @@
(ns status-im.data-store.realm.schemas.account.v1.kv-store
(:require [taoensso.timbre :as log]))
(def schema {:name :kv-store
:primaryKey :key
:properties {:key "string"
:value "string"}})
(defn migration [old-realm new-realm]
(log/debug "migrating kv-store schema"))

View File

@ -0,0 +1,32 @@
(ns status-im.data-store.realm.schemas.account.v1.message
(:require [taoensso.timbre :as log]))
(def schema {:name :message
:primaryKey :message-id
:properties {:message-id "string"
:from "string"
:to {:type "string"
:optional true}
:group-id {:type "string"
:optional true}
:content "string" ;; TODO make it ArrayBuffer
:content-type "string"
:timestamp "int"
:chat-id {:type "string"
:indexed true}
:outgoing "bool"
:retry-count {:type :int
:default 0}
:same-author "bool"
:same-direction "bool"
:preview {:type :string
:optional true}
:message-type {:type :string
:optional true}
:message-status {:type :string
:optional true}
:user-statuses {:type :list
:objectType "user-status"}}})
(defn migration [old-realm new-realm]
(log/debug "migrating message schema"))

View File

@ -0,0 +1,22 @@
(ns status-im.data-store.realm.schemas.account.v1.pending-message
(:require [taoensso.timbre :as log]))
(def schema {:name :pending-message
:primaryKey :id
:properties {:id :string
:message-id :string
:chat-id {:type :string
:optional true}
:ack? :bool
:requires-ack? :bool
:from :string
:to {:type :string
:optional true}
:payload :string
:type :string
:topics :string
:attempts :int
:was-sent? :bool}})
(defn migration [old-realm new-realm]
(log/debug "migrating pending-message schema"))

View File

@ -0,0 +1,13 @@
(ns status-im.data-store.realm.schemas.account.v1.request
(:require [taoensso.timbre :as log]))
(def schema {:name :request
:properties {:message-id :string
:chat-id :string
:type :string
:status {:type :string
:default "open"}
:added :date}})
(defn migration [old-realm new-realm]
(log/debug "migrating request schema"))

View File

@ -0,0 +1,10 @@
(ns status-im.data-store.realm.schemas.account.v1.tag
(:require [taoensso.timbre :as log]))
(def schema {:name :tag
:primaryKey :name
:properties {:name "string"
:count {:type "int" :optional true :default 0}}})
(defn migration [old-realm new-realm]
(log/debug "migrating tag schema"))

View File

@ -0,0 +1,12 @@
(ns status-im.data-store.realm.schemas.account.v1.user-status
(:require [taoensso.timbre :as log]))
(def schema {:name :user-status
:primaryKey :id
:properties {:id "string"
:whisper-identity {:type "string"
:default ""}
:status "string"}})
(defn migration [old-realm new-realm]
(log/debug "migrating user-status schema"))

View File

@ -0,0 +1,7 @@
(ns status-im.data-store.realm.schemas.base.core
(:require [status-im.data-store.realm.schemas.base.v1.core :as v1]))
; put schemas ordered by version
(def schemas [{:schema v1/schema
:schemaVersion 1
:migration v1/migration}])

View File

@ -0,0 +1,22 @@
(ns status-im.data-store.realm.schemas.base.v1.account
(:require [taoensso.timbre :as log]))
(def schema {:name :account
:primaryKey :address
:properties {:address "string"
:public-key "string"
:updates-public-key {:type :string
:optional true}
:updates-private-key {:type :string
:optional true}
:name {:type "string" :optional true}
:phone {:type "string" :optional true}
:email {:type "string" :optional true}
:status {:type "string" :optional true}
:photo-path "string"
:last-updated {:type "int" :default 0}
:signed-up? {:type :bool
:default false}}})
(defn migration [old-realm new-realm]
(log/debug "migrating account schema"))

View File

@ -0,0 +1,12 @@
(ns status-im.data-store.realm.schemas.base.v1.core
(:require [status-im.data-store.realm.schemas.base.v1.account :as account]
[status-im.data-store.realm.schemas.base.v1.kv-store :as kv-store]
[taoensso.timbre :as log]))
(def schema [account/schema
kv-store/schema])
(defn migration [old-realm new-realm]
(log/debug "migrating v1 base database: " old-realm new-realm)
(account/migration old-realm new-realm)
(kv-store/migration old-realm new-realm))

View File

@ -0,0 +1,10 @@
(ns status-im.data-store.realm.schemas.base.v1.kv-store
(:require [taoensso.timbre :as log]))
(def schema {:name :kv-store
:primaryKey :key
:properties {:key "string"
:value "string"}})
(defn migration [old-realm new-realm]
(log/debug "migrating kv-store schema"))

View File

@ -0,0 +1,22 @@
(ns status-im.data-store.requests
(:require [status-im.data-store.realm.requests :as data-store]))
(defn get-all
[]
(data-store/get-all-as-list))
(defn get-open-by-chat-id
[chat-id]
(data-store/get-open-by-chat-id chat-id))
(defn save
[request]
(data-store/save request))
(defn save-all
[requests]
(data-store/save-all requests))
(defn mark-as-answered
[chat-id message-id]
(data-store/mark-as-answered chat-id message-id))

View File

@ -4,7 +4,7 @@
[status-im.utils.handlers :refer [register-handler]]
[status-im.protocol.core :as protocol]
[status-im.navigation.handlers :as nav]
[status-im.discovery.model :as discoveries]
[status-im.data-store.discovery :as discoveries]
[status-im.utils.handlers :as u]
[status-im.utils.datetime :as time]
[status-im.utils.random :as random]))
@ -28,11 +28,11 @@
(defmethod nav/preload-data! :discovery
[{:keys [discoveries] :as db} _]
(-> db
(assoc :tags (discoveries/all-tags))
(assoc :tags (discoveries/get-all-tags))
;; todo add limit
;; todo hash-map with whisper-id as key and sorted by last-update
;; may be more efficient here
(assoc :discoveries (discoveries/discovery-list))))
(assoc :discoveries (discoveries/get-all))))
(register-handler :discovery-response-received
(u/side-effect!
@ -85,11 +85,11 @@
(defn save-discovery!
[{:keys [new-discovery]} _]
(discoveries/save-discoveries [new-discovery]))
(discoveries/save new-discovery))
(defn reload-tags!
[db _]
(assoc db :tags (discoveries/all-tags)))
(assoc db :tags (discoveries/get-all-tags)))
(register-handler :add-discovery
(-> add-discovery
@ -100,4 +100,4 @@
:remove-old-discoveries!
(u/side-effect!
(fn [_ _]
(discoveries/remove-discoveries! :priority :asc 1000 200))))
(discoveries/delete :priority :asc 1000 200))))

View File

@ -1,67 +0,0 @@
(ns status-im.discovery.model
(:require [taoensso.timbre :as log]
[status-im.persistence.realm.core :as r]))
(defn get-tag [tag]
(log/debug "Getting tag: " tag)
(-> (r/get-by-field :account :tag :name tag)
(r/single-cljs)))
(defn update-tag-counter [func tag]
(let [tag (:name tag)
tag-object (get-tag tag)]
(if tag-object
(r/create :account :tag
{:name tag
:count (func (:count tag-object))}
true))))
(defn update-tags-counter [func tags]
(doseq [tag (distinct tags)]
(update-tag-counter func tag)))
(defn get-tags [message-id]
(-> (r/get-by-field :account :discovery :message-id message-id)
(r/single-cljs)
(:tags)
(vals)))
(defn- upsert-discovery [{:keys [message-id tags] :as discovery}]
(log/debug "Creating/updating discovery with tags: " tags)
(let [prev-tags (get-tags message-id)]
(if prev-tags
(update-tags-counter dec prev-tags))
(r/create :account :discovery discovery true)
(update-tags-counter inc tags)))
(defn discovery-list []
(->> (-> (r/get-all :account :discovery)
(r/sorted :priority :desc)
(r/realm-collection->list))
(mapv #(update % :tags vals))))
(defn- add-discoveries [discoveries]
(r/write :account
(fn []
(doseq [discovery discoveries]
(upsert-discovery discovery)))))
(defn save-discoveries [discoveries]
(add-discoveries discoveries))
(defn remove-discoveries! [by ordering critical-count to-delete-count]
(let [objs (r/get-all :account :discovery)
count (r/get-count objs)]
(if (> count critical-count)
(let [to-delete (-> (r/sorted objs by ordering)
(r/page 0 to-delete-count))]
(r/write :account
(fn []
(log/debug (str "Deleting " (r/get-count to-delete) " discoveries"))
(r/delete :account to-delete)))))))
(defn all-tags []
(-> (r/get-all :account :tag)
(r/sorted :count :desc)
r/realm-collection->list))

View File

@ -1,13 +1,12 @@
(ns status-im.group-settings.handlers
(:require [re-frame.core :refer [debug dispatch after enrich]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.persistence.realm.core :as r]
[status-im.chat.handlers :refer [delete-messages!]]
[status-im.protocol.core :as protocol]
[status-im.utils.random :as random]
[status-im.models.contacts :as contacts]
[status-im.models.messages :as messages]
[status-im.models.chats :as chats]
[status-im.data-store.contacts :as contacts]
[status-im.data-store.messages :as messages]
[status-im.data-store.chats :as chats]
[status-im.constants :refer [text-content-type]]
[status-im.utils.handlers :as u]
[status-im.navigation.handlers :as nav]))
@ -18,11 +17,7 @@
(defn save-property!
[current-chat-id property-name value]
(r/write :account
(fn []
(-> (r/get-by-field :account :chat :chat-id current-chat-id)
(r/single)
(aset (name property-name) value)))))
(chats/save-property current-chat-id property-name value))
(defn save-chat-property!
[db-name property-name]
@ -80,15 +75,9 @@
(update-in db [:chats current-chat-id :contacts]
remove-identities selected-participants))
(defn remove-members-from-realm!
(defn remove-members-from-chat!
[{:keys [current-chat-id selected-participants] :as db} _]
(let [chat (get-in db [:chats current-chat-id])]
(r/write :account
(fn []
(r/create :account
:chat
(update chat :contacts remove-identities selected-participants)
true)))))
(chats/remove-contacts current-chat-id selected-participants))
(defn notify-about-removing!
[{:keys [current-chat-id selected-participants]} _]
@ -103,10 +92,10 @@
:content-type text-content-type})
(defn removed-participant-message [chat-id identity]
(let [contact-name (:name (contacts/contact-by-identity identity))]
(let [contact-name (:name (contacts/get-by-id identity))]
(->> (str "You've removed " (or contact-name identity))
(system-message (random/id))
(messages/save-message chat-id))))
(messages/save chat-id))))
(defn create-removing-messages!
[{:keys [current-chat-id selected-participants]} _]
@ -122,7 +111,7 @@
(-> remove-members
;; todo shouldn't this be done only after receiving of the "ack message"
;; about the api call that removes participants from the group?
((after remove-members-from-realm!))
((after remove-members-from-chat!))
;; todo uncomment
;((after notify-about-removing!))
((after create-removing-messages!))
@ -134,9 +123,9 @@
(let [new-identities (map #(hash-map :identity %) selected-participants)]
(update db [:chats current-chat-id :contacts] concat new-identities)))
(defn add-members-to-realm!
(defn add-members-to-chat!
[{:keys [current-chat-id selected-participants]} _]
(chats/chat-add-participants current-chat-id selected-participants))
(chats/add-contacts current-chat-id selected-participants))
(defn notify-about-new-members!
[{:keys [current-chat-id selected-participants
@ -166,6 +155,6 @@
(register-handler :add-new-participants
;; todo order of operations tbd
(-> add-memebers
((after add-members-to-realm!))
((after add-members-to-chat!))
((after notify-about-new-members!))
((enrich deselect-members))))

View File

@ -3,7 +3,7 @@
[re-frame.core :refer [after dispatch dispatch-sync debug]]
[schema.core :as s :include-macros true]
[status-im.db :refer [app-db schema]]
[status-im.persistence.realm.core :as realm]
[status-im.data-store.core :as data-store]
[taoensso.timbre :as log]
[status-im.utils.crypt :refer [gen-random-bytes]]
[status-im.components.status :as status]
@ -43,7 +43,7 @@
(register-handler :initialize-db
(fn [_ _]
(realm/reset-account)
(data-store/init)
(assoc app-db :current-account-id nil)))
(register-handler :initialize-account-db

View File

@ -22,7 +22,7 @@
[status-im.group-settings.screen :refer [group-settings]]
[status-im.profile.screen :refer [profile my-profile]]
[status-im.profile.photo-capture.screen :refer [profile-photo-capture]]
status-im.persistence.realm.core
status-im.data-store.core
[taoensso.timbre :as log]))
(defn orientation->keyword [o]

View File

@ -1,21 +0,0 @@
(ns status-im.models.accounts
(:require [status-im.persistence.realm.core :as r]))
(defn get-accounts []
(-> (r/get-all :base :account)
r/realm-collection->list))
(defn save-account [update?]
#(r/create :base :account % update?))
(defn save-accounts [accounts update?]
(r/write :base #(mapv (save-account update?) accounts)))
;;;;;;;;;;;;;;;;;;;;----------------------------------------------
(defn accounts-list []
(r/get-all :base :account))
(defn account-by-address [address]
(r/single-cljs (r/get-by-field :base :account :address address)))

View File

@ -1,141 +0,0 @@
(ns status-im.models.chats
(:require [clojure.set :refer [difference]]
[re-frame.core :refer [dispatch]]
[status-im.persistence.realm.core :as r]
[status-im.utils.random :as random :refer [timestamp]]
[clojure.string :refer [join blank?]]
[status-im.constants :refer [content-type-status]]
[status-im.models.messages :refer [save-message]]
[status-im.persistence.realm-queries :refer [include-query]]))
(defn chat-name-from-contacts [identities]
(let [chat-name (->> identities
(map (fn [identity]
(-> (r/get-by-field :account :contact :whisper-identity identity)
(r/single-cljs)
:name)))
(filter identity)
(join ","))]
(when-not (blank? chat-name)
chat-name)))
(defn get-chat-name [chat-id identities]
(or (chat-name-from-contacts identities)
chat-id))
(defn chat-exists? [chat-id]
(r/exists? :account :chat {:chat-id chat-id}))
(defn chat-contacts [chat-id]
(-> (r/get-by-field :account :chat :chat-id chat-id)
(r/single)
(aget "contacts")))
(defn re-join-group-chat [db group-id identities group-name]
(r/write :account
(fn []
(let [new-identities (set identities)
only-old-contacts (->> (chat-contacts group-id)
(r/cljs-list)
(remove (fn [{:keys [identity]}]
(new-identities identity))))
contacts (->> new-identities
(mapv (fn [ident]
{:identity ident}))
(concat only-old-contacts))]
(r/create :account :chat
{:chat-id group-id
:is-active true
:name group-name
:contacts contacts} true))))
db)
(defn normalize-contacts
[chats]
(map #(update % :contacts vals) chats))
(defn chats-list []
(-> (r/get-by-field :account :chat :is-active true)
(r/sorted :timestamp :desc)
r/realm-collection->list
normalize-contacts))
(defn chat-by-id [chat-id]
(-> (r/get-by-field :account :chat :chat-id chat-id)
(r/single-cljs)
(r/list-to-array :contacts)))
(defn update-chat [{:keys [last-message-id chat-id] :as chat}]
(let [{old-chat-id :chat-id
:as old-chat} (chat-by-id chat-id)]
(when old-chat-id
(let [chat (-> (merge old-chat chat)
(assoc chat :last-message-id (or last-message-id "")))]
(r/write :account #(r/create :account :chat chat true))))))
(defn create-chat
([{:keys [last-message-id] :as chat}]
(let [chat (assoc chat :last-message-id (or last-message-id ""))]
(r/write :account #(r/create :account :chat chat true)))))
(defn chat-add-participants [chat-id identities]
(r/write :account
(fn []
(let [contacts (chat-contacts chat-id)
added-at (timestamp)]
(doseq [contact-identity identities]
(if-let [contact (.find contacts (fn [object index collection]
(= contact-identity (aget object "identity"))))]
(doto contact
(aset "is-in-chat" true)
(aset "added-at" added-at))
(.push contacts (clj->js {:identity contact-identity
:added-at added-at})))))))
;; TODO temp. Update chat in db atom
(dispatch [:initialize-chats]))
(defn chat-remove-participants [chat-id identities]
(r/write :account
(fn []
(let [query (include-query :identity identities)
chat (r/single (r/get-by-field :account :chat :chat-id chat-id))]
(-> (aget chat "contacts")
(r/filtered query)
(.forEach (fn [object _ _]
(r/delete :account object))))))))
(defn- groups [active?]
(r/filtered (r/get-all :account :chat)
(str "group-chat = true && is-active = "
(if active? "true" "false"))))
(defn active-group-chats []
(map
(fn [{:keys [chat-id public-key private-key]}]
{:chat-id chat-id
:keypair {:private private-key
:public public-key}})
(r/realm-collection->list (groups true))))
(defn set-chat-active [chat-id active?]
(r/write :account
(fn []
(-> (r/get-by-field :account :chat :chat-id chat-id)
(r/single)
(aset "is-active" active?)))))
(defn get-property [chat-id property]
(when-let [chat (r/single (r/get-by-field :account :chat :chat-id chat-id))]
(aget chat (name property))))
(defn is-active? [chat-id]
(get-property chat-id :is-active))
(defn removed-at [chat-id]
(get-property chat-id :removed-at))
(defn contact [chat-id id]
(let [contacts (r/cljs-list (chat-contacts chat-id))]
(some (fn [{:keys [identity]}]
(= id identity))
contacts)))

View File

@ -1,50 +0,0 @@
(ns status-im.models.contacts
(:require [status-im.persistence.realm.core :as r]
[status-im.utils.identicon :refer [identicon]]
[status-im.persistence.realm-queries :refer [include-query
exclude-query]]))
(defn get-contacts []
(-> (r/get-all :account :contact)
(r/sorted :name :asc)
r/realm-collection->list))
(defn get-contact [id]
(r/get-one-by-field :account :contact :whisper-identity id))
(defn create-contact [{:keys [whisper-identity pending] :as contact}]
(let [{pending-db :pending
:as contact-db} (r/get-one-by-field :account :contact
:whisper-identity whisper-identity)
contact (assoc contact :pending (boolean (if contact-db
(and pending-db pending)
pending)))]
(r/create :account :contact contact (if contact-db true false))))
(defn save-contacts [contacts]
(r/write :account #(mapv create-contact contacts)))
;;;;;;;;;;;;;;;;;;;;----------------------------------------------
(defn contacts-list []
(r/sorted (r/get-all :account :contact) :name :asc))
(defn contacts-list-exclude [exclude-idents]
(if (empty? exclude-idents)
(contacts-list)
(let [query (exclude-query :whisper-identity exclude-idents)]
(-> (r/get-all :account :contact)
(r/filtered query)
(r/sorted :name :asc)))))
(defn contacts-list-include [include-indents]
(if (empty? include-indents)
()
(let [query (include-query :whisper-identity include-indents)]
(-> (r/get-all :account :contact)
(r/filtered query)
(r/sorted :name :asc)))))
(defn contact-by-identity [identity]
(r/single-cljs (r/get-by-field :account :contact :whisper-identity identity)))

View File

@ -1,89 +0,0 @@
(ns status-im.models.messages
(:require [status-im.persistence.realm.core :as r]
[re-frame.core :refer [dispatch]]
[cljs.reader :refer [read-string]]
[status-im.utils.random :refer [timestamp]]
[clojure.string :refer [join split]]
[clojure.walk :refer [stringify-keys keywordize-keys]]
[status-im.constants :as c]
[status-im.commands.utils :refer [generate-hiccup]]))
(defn- map-to-str
[m]
(join ";" (map #(join "=" %) (stringify-keys m))))
(defn- str-to-map
[s]
(keywordize-keys (apply hash-map (split s #"[;=]"))))
(defn- user-statuses-to-map
[user-statuses]
(->> (vals user-statuses)
(mapv (fn [{:keys [whisper-identity] :as status}]
[whisper-identity status]))
(into {})))
(def default-values
{:outgoing false
:to nil
:same-author false
:same-direction false
:preview nil})
(defn save-message
;; todo remove chat-id parameter
[chat-id {:keys [message-id content]
:as message}]
(when-not (r/exists? :account :message {:message-id message-id})
(r/write :account
(fn []
(let [content' (if (string? content)
content
(map-to-str content))
message' (merge default-values
message
{:chat-id chat-id
:content content'
:timestamp (timestamp)})]
(r/create :account :message message' true))))))
(defn command-type? [type]
(contains?
#{c/content-type-command c/content-type-command-request}
type))
(defn get-messages
([chat-id] (get-messages chat-id 0))
([chat-id from]
(->> (-> (r/get-by-field :account :message :chat-id chat-id)
(r/sorted :timestamp :desc)
(r/page from (+ from c/default-number-of-messages))
(r/realm-collection->list))
(mapv #(update % :user-statuses user-statuses-to-map))
(into '())
reverse
(keep (fn [{:keys [content-type preview] :as message}]
(if (command-type? content-type)
(-> message
(update :content str-to-map)
(assoc :rendered-preview
(when preview
(generate-hiccup (read-string preview)))))
message))))))
(defn update-message! [{:keys [message-id] :as message}]
(r/write :account
(fn []
(when (r/exists? :account :message {:message-id message-id})
(let [message (update message :user-statuses vals)]
(r/create :account :message message true))))))
(defn get-message [id]
(some-> (r/get-one-by-field :account :message :message-id id)
(update :user-statuses user-statuses-to-map)))
(defn get-last-message [chat-id]
(-> (r/get-by-field :account :message :chat-id chat-id)
(r/sorted :timestamp :desc)
(r/single)
(js->clj :keywordize-keys true)))

View File

@ -1,60 +0,0 @@
(ns status-im.models.pending-messages
(:require [status-im.persistence.realm.core :as r]
[re-frame.core :refer [dispatch]]
[cljs.reader :refer [read-string]]
[status-im.utils.random :refer [timestamp]]
[clojure.string :refer [join split]]
[clojure.walk :refer [stringify-keys keywordize-keys]]
[status-im.constants :as c]
[status-im.utils.types :refer [clj->json json->clj]]
[status-im.commands.utils :refer [generate-hiccup]]
[cljs.reader :as reader]
[clojure.string :as str]
[status-im.utils.hex :as i]))
(defn get-pending-messages! []
(->> (r/get-all :account :pending-message)
r/realm-collection->list
(map (fn [message]
(update message :topics reader/read-string)))))
(defn- get-id
[message-id to]
(let [to' (i/normalize-hex to)
to'' (when to' (subs to' 0 7))
id' (if to''
(str message-id "-" (subs to'' 0 7))
message-id)]
id'))
(defn add-pending-message!
[{:keys [id to group-id message] :as pending-message}]
(r/write :account
(fn []
(let [{:keys [from topics payload]} message
id' (get-id id to)
chat-id (or group-id to)
message' (-> pending-message
(assoc :id id'
:from from
:message-id id
:chat-id chat-id
:payload payload
:topics (prn-str topics))
(dissoc :message))]
(r/create :account :pending-message message' true)))))
(defn remove-pending-message!
[{{:keys [message-id ack-of-message]} :payload}]
(r/write :account
(fn []
(r/delete :account
(r/get-by-field :account :pending-message
:message-id (or ack-of-message message-id))))))
(defn remove-all-by-chat [chat-id]
(r/write
:account
(fn []
(r/delete :account
(r/get-by-field :account :pending-message :chat-id chat-id)))))

View File

@ -1,21 +0,0 @@
(ns status-im.models.requests
(:require [status-im.persistence.realm.core :as r]))
(defn get-requests []
(-> (r/get-all :account :request)
r/realm-collection->list))
(defn create-request [request]
(r/create :account :request request true))
(defn save-request [request]
(r/write :account
(fn []
(create-request request))))
(defn save-requests [requests]
(r/write :account #(mapv create-request requests)))
(defn requests-list []
(r/get-all :account :request))

View File

@ -3,7 +3,7 @@
[re-frame.core :refer [after dispatch debug enrich]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.components.styles :refer [default-chat-color]]
[status-im.models.chats :as chats]
[status-im.data-store.chats :as chats]
[clojure.string :as s]
[status-im.utils.handlers :as u]
[status-im.utils.random :as random]
@ -54,7 +54,7 @@
(defn create-chat!
[{:keys [new-chat]} _]
(chats/create-chat new-chat))
(chats/save new-chat))
(defn show-chat!
[{:keys [new-chat]} _]
@ -105,7 +105,7 @@
:public-key public
:private-key private
:contacts contacts'}]
(when (or (not (chats/chat-exists? group-id))
(when (or (not (chats/exists? group-id))
is-active
(> timestamp removed-at))
(dispatch [:add-chat group-id (assoc chat :is-active true

View File

@ -1,185 +0,0 @@
(ns status-im.persistence.realm.core
(:require [cljs.reader :refer [read-string]]
[status-im.components.styles :refer [default-chat-color]]
[status-im.utils.types :refer [to-string]]
[status-im.utils.utils :as u]
[status-im.utils.fs :as fs]
[taoensso.timbre :as log]
[status-im.persistence.realm.schemas :refer [base account]]
[clojure.string :as str])
(:refer-clojure :exclude [exists?]))
(def new-account-filename "new-account")
(def realm-class (u/require "realm"))
(defn create-account-realm [address]
(let [opts (merge account {:path (str address ".realm")})]
(when (cljs.core/exists? js/window)
(realm-class. (clj->js opts)))))
(def base-realm
(when (cljs.core/exists? js/window)
(realm-class. (clj->js base))))
(def account-realm (atom (create-account-realm new-account-filename)))
(defn is-new-account? []
(let [path (.-path @account-realm)
realm_file (str new-account-filename ".realm")]
(str/ends-with? path realm_file)))
(defn realm [schema]
(case schema
:base base-realm
:account @account-realm))
(defn close [schema]
(let [realm-db (realm schema)]
(when realm-db
(.close realm-db))))
(defn close-account-realm []
(close :account)
(reset! account-realm nil))
(defn reset-account []
(when @account-realm
(close-account-realm))
(reset! account-realm (create-account-realm new-account-filename))
(.write @account-realm #(.deleteAll @account-realm)))
(defn move-file-handler [address err handler]
(log/debug "Moved file with error: " err address)
(if err
(log/error "Error moving account realm: " (.-message err))
(reset! account-realm (create-account-realm address)))
(handler err))
(defn change-account-realm [address new-account? handler]
(let [path (.-path @account-realm)
realm-file (str new-account-filename ".realm")]
(log/debug "closing account realm: " path)
(close-account-realm)
(log/debug "is new account? " new-account?)
(if new-account?
(let [new-path (str/replace path realm-file (str address ".realm"))]
(log/debug "Moving file to " new-path)
(fs/move-file path new-path #(move-file-handler address % handler)))
(do
(reset! account-realm (create-account-realm address))
(handler nil)))))
(defn get-schema-by-name [opts]
(->> (:schema opts)
(mapv (fn [{:keys [name] :as schema}]
[name schema]))
(into {})))
(def schema-by-name
{:base (get-schema-by-name base)
:account (get-schema-by-name account)})
(defn field-type [schema schema-name field]
(let [schema-by-name (get schema-by-name schema)
field-def (get-in schema-by-name [schema-name :properties field])]
(if (map? field-def)
(:type field-def)
field-def)))
(defn write [schema f]
(.write (realm schema) f))
(defn create
([schema schema-name obj]
(create schema schema-name obj false))
([schema schema-name obj update?]
(.create (realm schema) (to-string schema-name) (clj->js obj) update?)))
(defn create-object
[schema schema-name obj]
(write schema (fn [] (create schema schema-name obj true))))
(defn and-query [queries]
(str/join " and " queries))
(defn or-query [queries]
(str/join " or " queries))
(defmulti to-query (fn [schema schema-name operator field value]
operator))
(defmethod to-query :eq [schema schema-name operator field value]
(let [value (to-string value)
field-type (field-type schema schema-name field)
query (str (name field) "=" (if (= "string" (name field-type))
(str "\"" value "\"")
value))]
query))
(defn get-by-filter [schema schema-name filter]
(-> (.objects (realm schema) (name schema-name))
(.filtered filter)))
(defn get-by-field [schema schema-name field value]
(let [q (to-query schema schema-name :eq field value)]
(.filtered (.objects (realm schema) (name schema-name)) q)))
(defn get-by-fields [schema schema-name op fields]
(let [queries (map (fn [[k v]]
(to-query schema schema-name :eq k v))
fields)]
(.filtered (.objects (realm schema) (name schema-name))
(case op
:and (and-query queries)
:or (or-query queries)))))
(defn get-all [schema schema-name]
(.objects (realm schema) (to-string schema-name)))
(defn sorted [results field-name order]
(.sorted results (to-string field-name) (if (= order :asc)
false
true)))
(defn filtered [results filter-query]
(.filtered results filter-query))
(defn page [results from to]
(js/Array.prototype.slice.call results from to))
(defn single [result]
(-> (aget result 0)))
(defn single-cljs [result]
(some-> (aget result 0)
(js->clj :keywordize-keys true)))
(defn cljs-list [results]
(-> (js->clj results :keywordize-keys true)
(vals)))
(defn list-to-array [record list-field]
(update-in record [list-field] (comp vec vals)))
(defn decode-value [{:keys [key value]}]
(read-string value))
(defn delete [schema obj]
(.delete (realm schema) obj))
(defn exists? [schema schema-name fields]
(pos? (.-length (get-by-fields schema schema-name :and fields))))
(defn get-count [objs]
(.-length objs))
(defn get-list [schema schema-name]
(vals (js->clj (.objects (realm schema) (to-string schema-name)) :keywordize-keys true)))
(defn realm-collection->list [collection]
(-> (.map collection (fn [object _ _] object))
(js->clj :keywordize-keys true)))
(defn get-one-by-field [schema schema-name field value]
(single-cljs (get-by-field schema schema-name field value)))

View File

@ -1,147 +0,0 @@
(ns status-im.persistence.realm.schemas
(:require [status-im.components.styles :refer [default-chat-color]]))
(def base {:schema [{:name :account
:primaryKey :address
:properties {:address "string"
:public-key "string"
:updates-public-key {:type :string
:optional true}
:updates-private-key {:type :string
:optional true}
:name {:type "string" :optional true}
:phone {:type "string" :optional true}
:email {:type "string" :optional true}
:status {:type "string" :optional true}
:photo-path "string"
:last-updated {:type "int" :default 0}
:signed-up? {:type :bool
:default false}}}
{:name :kv-store
:primaryKey :key
:properties {:key "string"
:value "string"}}]
:schemaVersion 0})
(def account {:schema [{:name :contact
:primaryKey :whisper-identity
:properties {:address {:type "string" :optional true}
:whisper-identity "string"
:name {:type "string" :optional true}
:photo-path {:type "string" :optional true}
:last-updated {:type "int" :default 0}
:last-online {:type "int" :default 0}
:pending {:type "bool" :default false}
:public-key {:type :string
:optional true}
:private-key {:type :string
:optional true}
:dapp? {:type :bool
:default false}}}
{:name :request
:properties {:message-id :string
:chat-id :string
:type :string
:status {:type :string
:default "open"}
:added :date}}
{:name :tag
:primaryKey :name
:properties {:name "string"
:count {:type "int" :optional true :default 0}}}
{:name :discovery
:primaryKey :message-id
:properties {:message-id "string"
:name {:type "string" :optional true}
:status "string"
:whisper-id "string"
:photo-path {:type "string" :optional true}
:tags {:type "list"
:objectType "tag"}
:priority {:type "int" :default 0}
:last-updated "date"}}
{:name :kv-store
:primaryKey :key
:properties {:key "string"
:value "string"}}
{:name :user-status
:primaryKey :id
:properties {:id "string"
:whisper-identity {:type "string"
:default ""}
:status "string"}}
{:name :message
:primaryKey :message-id
:properties {:message-id "string"
:from "string"
:to {:type "string"
:optional true}
:group-id {:type "string"
:optional true}
:content "string" ;; TODO make it ArrayBuffer
:content-type "string"
:timestamp "int"
:chat-id {:type "string"
:indexed true}
:outgoing "bool"
:retry-count {:type :int
:default 0}
:same-author "bool"
:same-direction "bool"
:preview {:type :string
:optional true}
:message-type {:type :string
:optional true}
:message-status {:type :string
:optional true}
:user-statuses {:type :list
:objectType "user-status"}}}
{:name :pending-message
:primaryKey :id
:properties {:id :string
:message-id :string
:chat-id {:type :string
:optional true}
:ack? :bool
:requires-ack? :bool
:from :string
:to {:type :string
:optional true}
:payload :string
:type :string
:topics :string
:attempts :int
:was-sent? :bool}}
{:name :chat-contact
:properties {:identity "string"
:is-in-chat {:type "bool"
:default true}}}
{:name :chat
:primaryKey :chat-id
:properties {:chat-id "string"
:name "string"
:color {:type "string"
:default default-chat-color}
:group-chat {:type "bool"
:indexed true}
:is-active "bool"
:timestamp "int"
:contacts {:type "list"
:objectType "chat-contact"}
:dapp-url {:type :string
:optional true}
:dapp-hash {:type :int
:optional true}
:removed-at {:type :int
:optional true}
:last-message-id "string"
:public-key {:type :string
:optional true}
:private-key {:type :string
:optional true}}}
{:name :command
:primaryKey :chat-id
:properties {:chat-id "string"
:file "string"}}]
:schemaVersion 0})

View File

@ -1,19 +0,0 @@
(ns status-im.persistence.realm-queries
(:require [clojure.string :as s]
[status-im.utils.types :refer [to-string]]))
(defn include-query [field-name values]
(->> values
(map (fn [val]
(str (to-string field-name) " == " (if (string? val)
(str "'" val "'")
val))))
(s/join " || ")))
(defn exclude-query [field-name values]
(->> values
(map (fn [val]
(str (to-string field-name) " != " (if (string? val)
(str "'" val "'")
val))))
(s/join " && ")))

View File

@ -2,10 +2,10 @@
(:require [status-im.utils.handlers :as u]
[re-frame.core :refer [dispatch after]]
[status-im.utils.handlers :refer [register-handler]]
[status-im.models.contacts :as contacts]
[status-im.models.messages :as messages]
[status-im.models.pending-messages :as pending-messages]
[status-im.models.chats :as chats]
[status-im.data-store.contacts :as contacts]
[status-im.data-store.messages :as messages]
[status-im.data-store.pending-messages :as pending-messages]
[status-im.data-store.chats :as chats]
[status-im.protocol.core :as protocol]
[status-im.constants :refer [text-content-type]]
[status-im.i18n :refer [label]]
@ -17,7 +17,7 @@
(let [{:keys [public-key status updates-public-key
updates-private-key]}
(get-in db [:accounts current-account-id])]
(let [groups (chats/active-group-chats)
(let [groups (chats/get-active-group-chats)
w3 (protocol/init-whisper!
{:rpc-url "http://localhost:8545"
:identity public-key
@ -32,7 +32,7 @@
:profile-keypair {:public updates-public-key
:private updates-private-key}
:hashtags (u/get-hashtags status)
:pending-messages (pending-messages/get-pending-messages!)
:pending-messages (pending-messages/get-all)
:contacts (keep (fn [{:keys [whisper-identity
public-key
private-key]}]
@ -40,8 +40,7 @@
{:identity whisper-identity
:keypair {:public public-key
:private private-key}}))
(contacts/get-contacts))})]
(contacts/get-all))})]
(assoc db :web3 w3)))))
(register-handler :incoming-message
@ -77,40 +76,40 @@
:content-type text-content-type})
(defn joined-chat-message [chat-id from message-id]
(let [contact-name (:name (contacts/contact-by-identity from))]
(messages/save-message chat-id {:from "system"
:message-id (str message-id "_" from)
:content (str (or contact-name from) " " (label :t/received-invitation))
:content-type text-content-type})))
(let [contact-name (:name (contacts/get-by-id from))]
(messages/save chat-id {:from "system"
:message-id (str message-id "_" from)
:content (str (or contact-name from) " " (label :t/received-invitation))
:content-type text-content-type})))
(defn participant-invited-to-group-message [chat-id current-identity identity from message-id]
(let [inviter-name (:name (contacts/contact-by-identity from))
(let [inviter-name (:name (contacts/get-by-id from))
invitee-name (if (= identity current-identity)
(label :t/You)
(:name (contacts/contact-by-identity identity)))]
(messages/save-message chat-id {:from "system"
:message-id message-id
:content (str (or inviter-name from) " " (label :t/invited) " " (or invitee-name identity))
:content-type text-content-type})))
(:name (contacts/get-by-id identity)))]
(messages/save chat-id {:from "system"
:message-id message-id
:content (str (or inviter-name from) " " (label :t/invited) " " (or invitee-name identity))
:content-type text-content-type})))
(defn participant-removed-from-group-message [chat-id identity from message-id]
(let [remover-name (:name (contacts/contact-by-identity from))
removed-name (:name (contacts/contact-by-identity identity))]
(let [remover-name (:name (contacts/get-by-id from))
removed-name (:name (contacts/get-by-id identity))]
(->> (str (or remover-name from) " " (label :t/removed) " " (or removed-name identity))
(system-message message-id)
(messages/save-message chat-id))))
(messages/save chat-id))))
(defn you-removed-from-group-message [chat-id from message-id]
(let [remover-name (:name (contacts/contact-by-identity from))]
(let [remover-name (:name (contacts/get-by-id from))]
(->> (str (or remover-name from) " " (label :t/removed-from-chat))
(system-message message-id)
(messages/save-message chat-id))))
(messages/save chat-id))))
(defn participant-left-group-message [chat-id from message-id]
(let [left-name (:name (contacts/contact-by-identity from))]
(let [left-name (:name (contacts/get-by-id from))]
(->> (str (or left-name from) " " (label :t/left))
(system-message message-id)
(messages/save-message chat-id))))
(messages/save chat-id))))
(register-handler :group-chat-invite-acked
(u/side-effect!
@ -122,7 +121,7 @@
(u/side-effect!
(fn [_ [action from group-id identity message-id]]
(log/debug action message-id from group-id identity)
(chats/chat-remove-participants group-id [identity])
(chats/remove-contacts group-id [identity])
(participant-removed-from-group-message group-id identity from message-id))))
(register-handler :you-removed-from-group
@ -130,7 +129,7 @@
(fn [_ [action from group-id message-id]]
(log/debug action message-id from group-id)
(you-removed-from-group-message group-id from message-id)
(chats/set-chat-active group-id false))))
(chats/set-active group-id false))))
(register-handler :participant-left-group
(u/side-effect!
@ -153,7 +152,7 @@
(register-handler ::remove-identity-from-chat!
(u/side-effect!
(fn [_ [_ group-id identity]]
(chats/chat-remove-participants group-id [identity]))))
(chats/remove-contacts group-id [identity]))))
(register-handler :participant-invited-to-group
(u/side-effect!
@ -167,7 +166,7 @@
(register-handler :add-contact-to-group!
(u/side-effect!
(fn [_ [_ group-id identity]]
(when-not (chats/contact group-id identity)
(when-not (chats/has-contact? group-id identity)
(dispatch [::add-contact group-id identity])
(dispatch [::store-contact! group-id identity])))))
@ -178,14 +177,14 @@
(register-handler ::store-contact!
(u/side-effect!
(fn [_ [_ group-id identity]]
(chats/chat-add-participants group-id [identity]))))
(chats/add-contacts group-id [identity]))))
(defn save-message-status! [status]
(fn [_ [_
{:keys [from]
{:keys [message-id ack-of-message group-id]} :payload}]]
(let [message-id' (or ack-of-message message-id)]
(when-let [{:keys [message-status] :as message} (messages/get-message message-id')]
(when-let [{:keys [message-status] :as message} (messages/get-by-id message-id')]
(when-not (= (keyword message-status) :seen)
(let [group? (boolean group-id)
message (if (and group? (not= status :sent))
@ -198,7 +197,7 @@
old-status
status)}))
(assoc message :message-status status))]
(messages/update-message! message)))))))
(messages/update message)))))))
(defn update-message-status [status]
@ -242,10 +241,10 @@
(register-handler :pending-message-upsert
(after
(fn [_ [_ {:keys [type id] :as pending-message}]]
(pending-messages/add-pending-message! pending-message)
(pending-messages/save pending-message)
(when (#{:message :group-message} type)
(messages/update-message! {:message-id id
:delivery-status :pending}))))
(messages/update {:message-id id
:delivery-status :pending}))))
(fn [db [_ {:keys [type id to group-id]}]]
(if (#{:message :group-message} type)
(let [chat-id (or group-id to)
@ -258,7 +257,7 @@
(register-handler :pending-message-remove
(u/side-effect!
(fn [_ [_ message]]
(pending-messages/remove-pending-message! message))))
(pending-messages/delete message))))
(register-handler :contact-request-received
(u/side-effect!