Fantastic. Keep up the good work. Schema conventions could be made flexible with a protocol.
(defprotocol IDBSchema (pk [_ table-name]) (rel [_ table-name rel-name]) (has-many? [_ table-name rel-name])) On Thursday, 31 March 2016 09:23:00 UTC+11, Krzysiek Herod wrote: > > I just released version 0.3.0 of Relational Mapper. Customization of keys > and foreign keys is done now, as well as possibility to specify relation > with a different name than the corresponding table ( > https://github.com/netizer/relational_mapper#different-name-of-an-association-than-a-table-name). > > > > @Oliver George: your example with SupervisorId, AnalystId would work now, > but have in mind that postgreSQL by default lowercases column names, so I'd > still recommend supervisor_id and analyst_id. > > Cheers, > Krzysiek > > On Tuesday, March 1, 2016 at 11:35:46 PM UTC+1, Oliver George wrote: >> >> >> Both those ideas seem sensible to me. Look foward to hearing more. >> >> On Tuesday, 1 March 2016 23:38:43 UTC+11, Krzysiek Herod wrote: >>> >>> I went through the paper very briefly, so I might be wrong, but from the >>> first look it seems like the algorithm would generate the actual SQL >>> queries . If so, although the idea seems interesting, I wouldn't go in this >>> direction because of the loss of flexibility for the user of the library. >>> For example sometimes it happens, that the slowest SQL query called by the >>> application is the one where database picked a sub-optimal index, or >>> sometimes combining data by adding one more join has a great performance >>> impact. >>> >>> Actually I was thinking about giving the programmer more flexibility, >>> and maybe splitting the whole code into query part and stitch part, so the >>> developer would choose the most efficient queries, but the stitching part >>> would put all those data together (with deep result structure). I'm curious >>> what do you think about this direction. I'll comment on your issue ( >>> https://github.com/netizer/relational_mapper/issues/3) with more >>> details about the idea. >>> >>> Cheers, >>> Krzysiek >>> >>> On Tue, Mar 1, 2016 at 6:03 AM, Oliver George <oli...@condense.com.au> >>> wrote: >>> >>>> Awesome, thanks. >>>> >>>> I did a little research last night looking for techniques for turning >>>> recursive queries into efficient SQL queries. I came across an >>>> interesting >>>> paper: >>>> >>>> Cheney, James, Sam Lindley, and Philip Wadler. "Query shredding: >>>> Efficient relational evaluation of queries over nested multisets (extended >>>> version)."*arXiv preprint arXiv:1404.7078* (2014). >>>> >>>> >>>> The details are obscured behind some intimidating equations but the >>>> concept seems pretty simple: The nested query gets normalised and then >>>> shredded into a set of sql queries and the results of those queries are >>>> stitched back together. >>>> >>>> There seem to be two version >>>> <https://scholar.google.com.au/scholar?hl=en&q=Query+shredding%3A+Efficient+relational+evaluation+of+queries+over+nested+multisets+%28extended+version%29&btnG=&as_sdt=1%2C5&as_sdtp=> >>>> >>>> of the paper. This one looks to be more detailed (26 pages): >>>> >>>> https://scholar.google.com/citations?view_op=view_citation&hl=en&user=Iz-3VFQAAAAJ&sortby=pubdate&citation_for_view=Iz-3VFQAAAAJ:9pM33mqn1YgC >>>> >>>> >>>> >>>> >>>> On Monday, 29 February 2016 21:06:23 UTC+11, Krzysiek Herod wrote: >>>>> >>>>> Thanks a lot for detailed notes. >>>>> >>>>> The problem with customization of foreign keys is on my TODO list. I >>>>> hope to fix that before releasing version 1.0. That would solve the >>>>> problem >>>>> with SupervisorId and AnalystId. >>>>> >>>>> What you said about deeper result structure (race -> meeting -> venue) >>>>> is very inspiring. You can't do that with this library (you can fetch >>>>> records with their - potentially indirect - relations, but those >>>>> relations >>>>> won't have own relations included), but definitely it's something worth >>>>> considering. I added it to my TODO list in the README but I don't have a >>>>> clear idea about how to do it well yet. >>>>> >>>>> Cheers, >>>>> Krzysiek >>>>> >>>>> On Monday, February 29, 2016 at 12:54:31 PM UTC+8, Oliver George wrote: >>>>>> >>>>>> Oops, one more. >>>>>> >>>>>> There was also a Users table (Id, Username, ...) >>>>>> >>>>>> I didn't see a way to handle join from Races to Users based on >>>>>> SupervisorId and AnalystId. >>>>>> >>>>>> >>>>>> On Monday, 29 February 2016 15:52:48 UTC+11, Oliver George wrote: >>>>>>> >>>>>>> Thanks for the details. >>>>>>> >>>>>>> I did a little experimenting and it works as advertised. Notes >>>>>>> below show what I did and found. >>>>>>> >>>>>>> I was interested to see if this might be suitable as a simple >>>>>>> om.next remote for a relational database. Potentially fanciful but >>>>>>> it's a >>>>>>> topic of interest for me at the moment. >>>>>>> >>>>>>> I used an existing database so I had a semi interesting dataset to >>>>>>> play with. >>>>>>> >>>>>>> Races (Id, RaceNumber, RaceTime, MeetingId, SupervisorId, >>>>>>> AnalystId...) >>>>>>> Meetings (Id, MeetingDate, MeetingTypeId, VenueId, JurisdictionId, >>>>>>> ...) >>>>>>> Venues (Id, Name) >>>>>>> Jurisdiction (Id, Name, Code) >>>>>>> >>>>>>> >>>>>>> The table and foreign key naming conventions didn't match so I >>>>>>> created views for each table. If that was configurable then you'd open >>>>>>> yourself to a wider audience. (e.g. MeetingId vs meetings_id) >>>>>>> >>>>>>> It was easy to setup some associations >>>>>>> >>>>>>> (def associations >>>>>>> {:meeting {:race :has-many >>>>>>> :jurisdiction :belongs-to >>>>>>> :venue :belongs-to} >>>>>>> :race {:meeting :belongs-to >>>>>>> :jurisdiction [:through :meeting :belongs-to]} >>>>>>> :venue {}}) >>>>>>> >>>>>>> My queries all worked as expected. >>>>>>> >>>>>>> (find-one db-state :meeting #{:race} [[:= :meeting.id 5617]]) >>>>>>> (find-one db-state :meeting #{:venue} [[:= :meeting.id 5617]]) >>>>>>> (find-one db-state :race #{:meeting :jurisdiction} [[:= :race.id >>>>>>> 42792]]) >>>>>>> >>>>>>> I couldn't see how I might pull data which requires three levels of >>>>>>> information (e.g. race -> meeting -> venue). I didn't dig deep enough >>>>>>> to >>>>>>> be sure. >>>>>>> >>>>>>> Incidentally, in case you haven't come across the datomic pull >>>>>>> inspired om.next remote pull syntax this is what it might look like: >>>>>>> >>>>>>> [{:meeting [:race]}] >>>>>>> (find-one db-state :meeting #{:race} []) >>>>>>> >>>>>>> [({:meeting [:race]} [:= :meeting.id 5617])] >>>>>>> (find-one db-state :meeting #{:race} [[:= :meeting.id 5617]]) >>>>>>> >>>>>>> [{:meeting [:venue]}] >>>>>>> (find-one db-state :meeting #{:venue} [[:= :meeting.id 5617]]) >>>>>>> >>>>>>> [{:race [{:meeting [{:venue :jurisdiction}]}]}] >>>>>>> >>>>>>> Not prettier necessarily but allows for composing multiple queries >>>>>>> into a request and for drilling deeper into available data. >>>>>>> >>>>>>> cheers, Oliver >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> On Sunday, 28 February 2016 20:02:15 UTC+11, Krzysiek Herod wrote: >>>>>>>> >>>>>>>> Thanks Oliver for the feedback, >>>>>>>> >>>>>>>> actually I came up with the idea of relational_mapper while working >>>>>>>> on a project in which I had one "data-model" that contained all the >>>>>>>> database related information, but the database related code contained >>>>>>>> a lot >>>>>>>> of features, and I really like working with small, focused clojure >>>>>>>> libraries, so in the end relational_mapper is as small as I could >>>>>>>> think of >>>>>>>> it. >>>>>>>> >>>>>>>> Also as you can see in this commit: >>>>>>>> https://github.com/netizer/relational_mapper/commit/6b4d79f92570bf723e4092d329978d484c01d2ab#diff-2b44df73d826687086fd1972295f8bd0L8 >>>>>>>> >>>>>>>> I actually was storing both: relations and fields in the same >>>>>>>> structure, >>>>>>>> but I changed that because I needed "fields" only for migrations that >>>>>>>> I >>>>>>>> used in tests, and because the whole structure was unnecessarily >>>>>>>> complex >>>>>>>> (it was much easier to make mistake modifying the fields/associations >>>>>>>> structure). >>>>>>>> >>>>>>>> Relational Mapper is meant only for reading data because whenever I >>>>>>>> tried to use complex structures to write data, I was unhappy with the >>>>>>>> result (often you have to update indexes of related records after one >>>>>>>> of >>>>>>>> them - with auto-increment field - is created, and there is a problem >>>>>>>> of >>>>>>>> determining if the related record has to be created or updated). >>>>>>>> >>>>>>>> I didn't write compare/contrast points because I couldn't find >>>>>>>> similar libraries in clojure. I mentioned ActiveRecord in README >>>>>>>> mostly >>>>>>>> because of the wording in types of relations, but even ActiveRecord is >>>>>>>> very >>>>>>>> far from Relational Mapper (it's much bigger, and has features that go >>>>>>>> way >>>>>>>> beyond simple relational mapping). >>>>>>>> >>>>>>>> Thanks again, >>>>>>>> Krzysiek >>>>>>>> >>>>>>>> On Sunday, February 28, 2016 at 10:54:57 AM UTC+8, Oliver George >>>>>>>> wrote: >>>>>>>>> >>>>>>>>> >>>>>>>>> Seems pretty nice to me. Like a light weight version of the >>>>>>>>> Django's migrate and queryset features which build on model >>>>>>>>> definitions. >>>>>>>>> >>>>>>>>> It seems like this would allow me to define a database schema >>>>>>>>> (tables, relations and fields) as data and use it to both create the >>>>>>>>> database and run select/insert/update/delete queries against it. >>>>>>>>> >>>>>>>>> Is that your intention for the library? >>>>>>>>> >>>>>>>>> I've not explored the options in this space before. It might be >>>>>>>>> good to have a section in the README pointing out to other related >>>>>>>>> tools >>>>>>>>> with some compare/contrast points. >>>>>>>>> >>>>>>>>> Thanks. >>>>>>>>> >>>>>>>>> >>>>>>>>> On Friday, 26 February 2016 17:51:10 UTC+11, Krzysiek Herod wrote: >>>>>>>>>> >>>>>>>>>> I created Relational Mapper, for situations where there is a >>>>>>>>>> relational database with certain amount of relations between tables >>>>>>>>>> and >>>>>>>>>> it's just not cool to fetch data from each table separately nor to >>>>>>>>>> write >>>>>>>>>> custom code for each such project so, with this library, you can >>>>>>>>>> just call: >>>>>>>>>> >>>>>>>>>> (find_all db-state :posts #{:authors :attachments} [:= post.id 1]) >>>>>>>>>> >>>>>>>>>> and assuming you have appropriate relations between these tables, >>>>>>>>>> you'll get: >>>>>>>>>> >>>>>>>>>> {:posts {:title "Christmas" >>>>>>>>>> :body "Merry Christmas!" >>>>>>>>>> :id 1 >>>>>>>>>> :authors_id 10 >>>>>>>>>> :authors {:name "Rudolf" :id 10} >>>>>>>>>> :attachments [{:name "rudolf.png" :id 100 :posts_id 1} >>>>>>>>>> {:name "santa.png" :id 101 :posts_id 1}] >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> The code is here: https://github.com/netizer/relational_mapper >>>>>>>>>> >>>>>>>>>> Please, guys, let me know what do you think, and if you have any >>>>>>>>>> ideas about improvements. If somebody would be so kind to take a >>>>>>>>>> look at >>>>>>>>>> the code, it would be awesome to read some feedback. >>>>>>>>>> >>>>>>>>>> Krzysiek HerĂ³d >>>>>>>>>> >>>>>>>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "Clojure" group. >>>> To post to this group, send email to clo...@googlegroups.com >>>> Note that posts from new members are moderated - please be patient with >>>> your first post. >>>> To unsubscribe from this group, send email to >>>> clojure+u...@googlegroups.com >>>> For more options, visit this group at >>>> http://groups.google.com/group/clojure?hl=en >>>> --- >>>> You received this message because you are subscribed to a topic in the >>>> Google Groups "Clojure" group. >>>> To unsubscribe from this topic, visit >>>> https://groups.google.com/d/topic/clojure/g6Yxk-o6_rQ/unsubscribe. >>>> To unsubscribe from this group and all its topics, send an email to >>>> clojure+u...@googlegroups.com. >>>> For more options, visit https://groups.google.com/d/optout. >>>> >>> >>> -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.