Replies: 12 comments 4 replies
-
FYI for anyone taking an interest, I now have BeerJSON support at the point where the program can read in (and store) Hop records from a BeerJSON file. This includes all the new attributes of hops that are not present in BeerXML (and need extra properties & DB columns in Brewtarget / Brewken). I think adding the ability to write Hop records to a BeerJSON file will be next, then other basics (fermentables, miscs, etc) should follow with not too much work. Recipes will likely be a bit more work, but, overall, we are slowly getting there. |
Beta Was this translation helpful? Give feedback.
-
Hi @matty0ung, |
Beta Was this translation helpful? Give feedback.
-
For anyone following along, here is a bit of an update on the BeerJSON work. I've been working on quite a number of different requirements for BeerJSON. Some are relatively straightforward and
As ever, happy to answer questions, discuss approach etc. |
Beta Was this translation helpful? Give feedback.
-
Another update. I think N° 7 is mostly done, except for UI support, which should be just "blank = null = std::nullopt" and which I'll come back to soon. I'm currently working on the joys of "mixed" fields. Historically these were things that could be measured by weight or by volume. But, of course, now there are things which could be measured by "mass concentration" (eg milligrams per liter) or "volume concentration" (eg parts per million). So I need to make "mixed" a bit more generic to handle this, which has a silver lining of making |
Beta Was this translation helpful? Give feedback.
-
Things are starting to come together. No 7 and 8 above are finally largely done, including the UI support (where there was a bit more to do than I thought). I can read and write A few details:
I've made a little tracker page at https://github.com/Brewken/brewken/wiki/BeerJSON for some of the turn-the-handle work. Although it looks like there is "a lot" to do, it should be rather less than it appears because a lot of what has been done to date is reusable. |
Beta Was this translation helpful? Give feedback.
-
OK, Styles are done and I can import BJCP Beer Style Guidelines in BeerJson format from https://github.com/beerjson/bjcp-json. (This helped uncover a couple of bugs in handling of optional values.) Looking at Equipment now. This is a bit more fun, as BeerJSON and BeerXML have a different approach. In BeerXML, there is a single Equipment record type for all the hot-side equipment a recipe might need to refer to. In BeerJSON equipment is modelled as a list of vessels of various forms ("HLT", "Mash Tun", "Lauter Tun", "Brew Kettle", "Fermenter", "Aging Vessel", "Packaging Vessel"). I think the BeerJSON structure is overly flexible, because it allows oddball set-ups like 3 mash tuns and 2 brew kettles. I'm going to assume that 99.9% of the time you only need at most one of each vessel in your equipment description. That way we retain a single overall Equipment record, and use the forms (HLT, Mash Tun, etc) as subrecords. (If it turns out that it's really important to model multiple Fermenters or something then we can make an array of them inside Equipment, but I'll avoid that complexity for now.) Long story short, I'm now tackling some more general work to do (on how to map BeerJSON arrays to our internal record structure) before I get back to the turn-the-handle stuff. |
Beta Was this translation helpful? Give feedback.
-
Equipment is pretty much done now. Just tidying up the "show lists of things" code (including to remove a bit of duplication and make things more consistent). Along the way, ended up doing a few neat things (well, they felt neat at the time anyway!):
I think next up are Mash and MashStep. |
Beta Was this translation helpful? Give feedback.
-
So, now we come to the tricky part, Recipes. This is where BeerJSON is going to force us to look more closely at something relatively fundamental that is (for entirely valid historical reasons) not really how we want it to be in the code. In the current code, when we have, say, a hop record, it's always the same type of record, whether it's the "master" record (storing everything we know about eg Fuggle hops) or the "use of" record (storing info about the addition of some Fuggle hops to a particular recipe). Back in the day when everything was stored in files and we didn't even have a database, this was the right thing to do to make every recipe completely self-contained. And BeerXML didn't draw a distinction, so we were aligned with that. Since then, things have changed, and everything is stored in a database, so it's now a bit duplicatory (Is that a word?) to make a full copy of the master Fuggle hop record every time we add Fuggle hops to a recipe. But everything works and it looks rather painful to change, so we haven't worried too much about it. BeerJSON however, being a bit more modern, draws a distinction between a hop and a use of a hop (and the same for fermentables, yeasts, etc, etc). Eg, for a "Fuggle" hop, there are two types of record:
So, we have to make a decision about how try to proceed. We might be able to get away with forcing the two types of BeerJSON hop record into our single all-purpose all-singing all-dancing hop record, depending on the context. We probably ought to bite the bullet and start splitting our hop record out into the two different things it really is. But this might be a fair bit of work. I'll have a think about this, and maybe try a couple of different things. I think it's the last substantive issue to solve before we can declare BeerJSON support working. If anyone wants to chime in with their thoughts and suggestions, please do; otherwise, watch this space. |
Beta Was this translation helpful? Give feedback.
-
Things are coming along reasonably well. We now have a new class One other structural change is that BeerJSON supports raw ale - ie beers brewed without a boil. At the moment, my plan is to support such "no-boil" recipes in the data structures, but leave fully enhancing the UI for a separate future project. |
Beta Was this translation helpful? Give feedback.
-
Of course, once you start thinking about what a "recipe addition" is, you then start asking what the quantity of a recipe addition can be, because different ingredients can be measured in different ways - eg some can be measured only by weight, others by weight or volume, and some (eg yeast) even by "count" (ie number of packets). The same question applies when you think about inventory (of all the same things). Previously, under the influence of BeerXML, there had been case-by-case flags for So now we have a class I've also removed the idea of a hop or another ingredient having a default amount. AFAICT it's a hangover (geddit!) from BeerXML which requires the amount field on Hop etc even when it's not inside a recipe. I can't think that it's useful in reality, and we can write a dummy amount to non-recipe BeerXML ingredient records to keep them "correct", so I don't expect anyone to mourn its passing. I still need to tidy up the UI and finish rewiring the XML / JSON mappings, but we're slowly getting there. |
Beta Was this translation helpful? Give feedback.
-
In addition to Hop, I've now coded recipe addition classes for Fermentable, Misc and Yeast, plus the corresponding Inventory classes. Now need to do Water (recipe addition but no inventory). As part of that, will bring the way we handle water closer into line with other "ingredients". (At the moment, if you import a recipe with a water profile from BeerXML, I don't think the water profile shows up anywhere.) |
Beta Was this translation helpful? Give feedback.
-
BeerJSON support is now live in Brewtarget 4.0. |
Beta Was this translation helpful? Give feedback.
-
As noted elsewhere, I've made a start on this. Subject to what people think, I'm going to try to do this differently than some of the previous "big" changes.
The actual reading in of JSON is not that hard (I think!). I already have code that validates a file against the BeerJSON schema for instance. (Two external libraries do most of the heavy lifting for that bit.) But there are likely to be a lot of code changes required to accommodate the richer content available in BeerJSON compared with the BeerXML 1.0 that we know and love/hate/etc. To take just one example, BeerJSON allows you to specify the units for most fields. Some of the units we support (eg diastatic power) and some we don't (eg pressure, which can be kPa, PSI or bar) and some we support partially (eg BeerJSON supports fluid ounces as a volume measurement, which we don't).
So, I'm thinking I'll try, over time, to make a series of PRs that eventually get us to BeerJSON support. Eg, one PR might be cleaning up and extending the unit system. Another might be adding the external (header-only) libraries we use to parse JSON files and do schema validation. Another might bring additional fields or objects (eg in BeerJSON a Recipe can have a pH field representing "The final beer pH at the end of fermentation") - though it may be we decide some of these extras can be left until we have a minimal version if import/export working.
The upside is that each PR is small(er) compared with doing one "everything we need for BeerJSON PR". The downside is that some of them might not be very exciting and I don't yet know how many there will be.
Anyway, would be good to get folks' views.
Beta Was this translation helpful? Give feedback.
All reactions