{"action":"created","issue":{"url":"https://api.github.com/repos/pushtorefresh/storio/issues/700","repository_url":"https://api.github.com/repos/pushtorefresh/storio","labels_url":"https://api.github.com/repos/pushtorefresh/storio/issues/700/labels{/name}","comments_url":"https://api.github.com/repos/pushtorefresh/storio/issues/700/comments","events_url":"https://api.github.com/repos/pushtorefresh/storio/issues/700/events","html_url":"https://github.com/pushtorefresh/storio/issues/700","id":184549028,"number":700,"title":"Discussion on Rx and multiTable entities","user":{"login":"ZakTaccardi","id":461114,"avatar_url":"https://avatars.githubusercontent.com/u/461114?v=3","gravatar_id":"","url":"https://api.github.com/users/ZakTaccardi","html_url":"https://github.com/ZakTaccardi","followers_url":"https://api.github.com/users/ZakTaccardi/followers","following_url":"https://api.github.com/users/ZakTaccardi/following{/other_user}","gists_url":"https://api.github.com/users/ZakTaccardi/gists{/gist_id}","starred_url":"https://api.github.com/users/ZakTaccardi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ZakTaccardi/subscriptions","organizations_url":"https://api.github.com/users/ZakTaccardi/orgs","repos_url":"https://api.github.com/users/ZakTaccardi/repos","events_url":"https://api.github.com/users/ZakTaccardi/events{/privacy}","received_events_url":"https://api.github.com/users/ZakTaccardi/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2016-10-21T19:14:44Z","updated_at":"2016-10-24T19:36:31Z","closed_at":null,"body":"In my opinion, SQL is painless until you start having to write joins. With Rx, \"in-memory\" joins, while less efficient, they are API friendly when using an operator like `.combineLatest()`. \r\n\r\nProblem: When observing a multi-table entity via `.combineLatest()`, a `put` operation using that entity results in multiple `onNext()` calls (because multiple tables are updated).\r\n\r\nLet's say I have a `ShoppingCart` class, joined from data from two tables, `CartMeta` and `Items`.\r\n\r\n```\r\ndata class ShoppingCart(\r\n        val cartId: String,\r\n        val invoiceNumber: String?,\r\n        val isCheckedOut: Boolean,\r\n        val items: List<Item>\r\n) {\r\n    val cartMeta = CartMeta(cartId, invoiceNumber, isCheckedOut)\r\n\r\n    constructor(cartMeta: CartMeta, items: List<Item>) : this(\r\n            cartId = cartMeta.cartId, invoiceNumber = cartMeta.invoiceNumber, isCheckedOut = cartMeta.isCheckedOut, items = items\r\n    )\r\n}\r\n\r\n//backed by a \"CartMeta\" table\r\ndata class CartMeta(\r\n        val cartId: String,\r\n        val invoiceNumber: String?,\r\n        val isCheckedOut: Boolean\r\n)\r\n\r\n//backed by a \"Item\" table\r\ndata class Item(\r\n        val itemId: String,\r\n        val price: String,\r\n        val itemName: String\r\n)\r\n```\r\n\r\n\r\nA `Put` operation on `ShoppingCart` would look like this.\r\n\r\n```\r\n        storIo.put()\r\n                .`object`(shoppingCart.cartMeta)\r\n                .prepare()\r\n                .executeAsBlocking()\r\n\r\n        storIo.put()\r\n                .objects(shoppingCart.items)\r\n                .prepare()\r\n                .executeAsBlocking()\r\n```\r\n\r\nThat generates a notification for the `CartMeta` table, and another for the `Items` table. I utilize `.combineLatest(cartMeta(), items())`, so I get two notifications here, when I want only one. I know `throttleLast()` could mostly fix this, but that introduces an delay (slower loads) and invites a race condition.\r\n\r\n\r\nAn API that would postpone notifications to the affected tables until both updates complete would fix this issue. Something like:\r\n\r\n```\r\nstorIo.put()\r\n                .`object`(shoppingCart.cartMeta)\r\n                .`object`(shoppingCart.items)\r\n                .prepare()\r\n                .executeAsBlocking()\r\n```"},"comment":{"url":"https://api.github.com/repos/pushtorefresh/storio/issues/comments/255842661","html_url":"https://github.com/pushtorefresh/storio/issues/700#issuecomment-255842661","issue_url":"https://api.github.com/repos/pushtorefresh/storio/issues/700","id":255842661,"user":{"login":"ZakTaccardi","id":461114,"avatar_url":"https://avatars.githubusercontent.com/u/461114?v=3","gravatar_id":"","url":"https://api.github.com/users/ZakTaccardi","html_url":"https://github.com/ZakTaccardi","followers_url":"https://api.github.com/users/ZakTaccardi/followers","following_url":"https://api.github.com/users/ZakTaccardi/following{/other_user}","gists_url":"https://api.github.com/users/ZakTaccardi/gists{/gist_id}","starred_url":"https://api.github.com/users/ZakTaccardi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ZakTaccardi/subscriptions","organizations_url":"https://api.github.com/users/ZakTaccardi/orgs","repos_url":"https://api.github.com/users/ZakTaccardi/repos","events_url":"https://api.github.com/users/ZakTaccardi/events{/privacy}","received_events_url":"https://api.github.com/users/ZakTaccardi/received_events","type":"User","site_admin":false},"created_at":"2016-10-24T19:36:31Z","updated_at":"2016-10-24T19:36:31Z","body":"Thanks! \r\n\r\nHere's a kotlin extension function to wrap a transaction properly.\r\n\r\n```\r\nprivate fun StorIOSQLite.executeTransaction(function: () -> Unit) {\r\n    this.lowLevel().beginTransaction()\r\n    try {\r\n        function.invoke()\r\n        this.lowLevel().setTransactionSuccessful()\r\n    } finally {\r\n        this.lowLevel().endTransaction()\r\n    }\r\n}\r\n```\r\n\r\nFeel free to close this or leave it open (if you plan on some type of future 2.0 API improvement)"}}
{"actor":{"display_login":"ZakTaccardi"}}