Correct way to handle interdependencies for a configurator (javascript) in database tables - sql

I'm having hard time with this project, I'm building a boat configurator which is divided in categories / packages / extras.
Each category is disconnected with the other, so it's not a big problem.
The problem comes out with packages and extras. Extras are options that can be chosen within a package (increasing the total price). I'll explain all dependencies that can exists between these 2 objects:
There are times where you can also purchase a package all toghether, which could have an extra (or 2) that are upgrades to that package
There are times where you can buy a single package between 4-5 and additionally you can buy some extras in another 6th package
Sometimes an extra can be bought only if you have at least one item in a given package
Sometimes an extra can be bought only if you have a specific extra
At the moment I don't have any other dependency in my mind (but I'm sure there are others possible).
I don't know which approach I should take to store all this dependencies, I have 3 basic sql tables (category, package, extra which are not connected because a Package => Extra dependency could be different for other categories) and CategoryRelationship, PackageRelationship, ExtraRelationship but I'm having hard time in express some dependencies, expecially the 2nd which is not limited to a single id field.
How is normally handled all these interdependencies?
I never faced this problem, thanks for any suggestion
Edit 1:
I'm thinking about changing the approach to 1 Table for each "type" of dependency, can it be considered a good way to handle instead of a single table with all type of dependencies?

Because no one answered this, I'm posting the approach I finally used for this project and which I find interesting.
I created 1 table for each type of dependency (as I told in Edit 1). Each table can have multiple reference to an item of any id and is possible in this way to organize quite well all columns that represents dependencies.
The approach is inspired by CakePHP Validation model, where each validation is a class that has a validate method which will be run.
Hopefully this will help someone else; I'll mark this as answer if no one provide an answer with a better suggestion.

Related

Populate REDCap dropdown with data from outside source

I think this question may be somewhat similar to this one : REDCap automatically populate fields from earlier records
That said, in that question they were populating the dropdown with data from elsewhere in REDCap, my question pertains to outside of REDCap.
What exactly I'm trying to do:
At our institution we store a bunch of information in a clinical trial management software called "OnCore". That's not SUPER important for this question, besides the fact that we connect to it for various reasons through a couple different possible channels (sql, api, Snowflake, etc..).
At the same time, we're building a REDCap project where staff can keep track of deviations that happen in trials and what was done about it. The problem is, staff currently have to manually type into REDCap the protocol they are working on.
Let's say in OnCore a protocol is called LS-P-Joe. Well, in REDCap, someone might type "LS-p-jOe" or "Joe" or "LSPJOE" etc.. etc.. and it'll cause a problem when I go to merge the data later.
I'd love to have a dropdown where staff can only select one spelling of the word, unfortunately there are dozens if not a few hundred studies to choose from (I don't want to build them all into the REDCap project manually).
Which brings me to: is there a way to have a dropdown in REDCap that dynamically connects to an outside data source? Let's say through SQL query?
Create a new REDCap project that contains only the legal protocol. No patient data points are needed.
Use a simplified version of #Jangari's solution (that you referenced above). But your scenario doesn't require the UNION clause. I think you'll need a REDCap admin to implement the Dynamic SQL Field.
Automate some script to periodically update the list of legal protocol names. Presumably you query OnCore (maybe with an Oracle driver) and update REDCap (see this list of packages that use REDCap's API).
I suggest involving your site's REDCap admin as soon as possible. They can also ask questions in the API space on the REDCap Community Site.

Finding subsets of ClearCase branch types

I'm working on a large project, for which several thousand branch types are defined, and would like to quickly retrieve a list of "my" branch types. This can be achieved either by listing branch types created by me, or by listing branch types whose names start with my username.
As the full list is huge and lstype runs for approximately an hour normally, is there a way to formulate a query that can be answered quickly?
I never found a native command able to return quickly an answer.
When looking at the cleartool lstype command, the technote "LSTYPE performance improvements" does mention that:
The -short, -nostatus and -unsorted options can be used to improve performance of the cleartool lstype command
But as with everything with ClearCase, this doesn't stand the test of the real world, where the number of (here) types quite be really big...
So what I usually do for this kind of request, considering I don't create a brtype every 5 minutes, is to have a batch job running every 2 hours, updating a list of brtype with the informations I need (owner, date, ...).
I can then at any time filter that file (at least the most updated version of that file) in order to extract the list of brtype I need.
There is the risk this list isn't up-to-date, but in practice this works relatively well.

Database design to avoid redundancy issue: use a convention or different design?

Note: Images are clickable to allow zoom
I have problem with this database design, I have different solution but none of them satisfact me enough.
The software is about a configurator for a product. You can choose with this configurator all the extras that will increase the price.
This is the data that I should present to the user. What's giving me problems is the fact that there are 2 type of extras:
This type of extra doesn't have a price, is merged inside a package which has a price for all its extras. (Relax [A123] is an example of package with price, first image)
This type of extra has a price and its package doesn't have any price, because they aren't boundled in the package (Water supply is an example of package without price)
Here is my current design, which I'm not satisfact with:
(Ignore ExtrasCategory which is only to group up extras)
The biggest problem is that each Extra (the class now) belongs to a package, even if it doesn't have a price.
However, each Package may have a price different for each Boat, so I need to set different prices.
I want something like this:
Each Extra has a "basic" Package.
If the Package has a price, we set it differently for each boat
If the Package doesn't have a price, we can use the "basic" Package of the Extra
However in this way I have redundancy: Extra has a Package, BoatExtra (an extra with price) has a BoatExtrasPackage and so we have 2 times a reference to a package
How can I solve this design issue?
Edit 1: Ok I've created an image which explains better what I want. I want a "default package" for an extra (on a per-extra basis), if the BoatExtra doesn't have one.
You have redundancy in your design ie: code and name. I would do it as attached if I understand properly your system.
Seems the problem is that I want to minimize space consumption, not make a good design. After I understood I were doing this (which for me it's wrong) I came up with a totally different design which is better than the previous one and fixed my problem.
I obviusly need to build more packages but this is what the logic wants

Importing content from one/two Drupal installs into a fresh Drupal install

We're upgrading a large site, opendemocracy.net, from Drupal 4.7 to Drupal 6. Our existing install has a lot of superfluous tables in the database from once-used modules we won't be using: ideally, we wouldn't keep these, or our old blocks, etc. This is because: (a) it'd be nice to keep the database as small as possible, (b) it'd be nice for new blocks to start at ID 1, etc., (c) as clean an install as possible should minimise any problems (for example, our crufty old install has some strange problems, e.g. not letting us create any new blocks).
All we really want to keep is our nodes (plus comments), taxonomies, files, statistics, users, path aliases, and one custom table. I've tried copying the tables that I think govern these (listed at the end of this question) into a fresh 4.7 install and then upgrading from this, and it appears to work. My questions are: would this work? Is it a good idea? Is there a better way to achieve some of the same goals?
Also, what if we needed to do the same with another install, also adding its content to the same new install? We have a separate install for our forums. The following approach seemed to work, but I'm worried it will cause problems when creating new content reaches the new nids I've created (how does Drupal check what nids are free; is there a database variable I should change?):
increment the nids (and vids) in the node and term_nodes tables of the forums install by the highest nid (or vid) in the main install
create a new vocabulary in the main install with the same terms as the Forums vocab in the forums install (at maininstall.com/admin/content/forum - I'm not sure how else to specify this is the forum vocabulary)
change the tids in the term_nodes tables of the forums install to the tid values of terms in this new vocabulary in the main install
insert the contents of the modified node and term_nodes tables of the forums install into the node and term_nodes tables of the main install.
PS: Here are the tables I've found which need copying:
audio, audio_attach, audio_image, audio_metadata, comments, files, node, node_access, node_comment_statistics, node_counter, node_revisions, node_type, od_story, term_data, term_hierarchy, term_node, term_relation, term_synonym, url_alias, users, vocabulary, vocabulary_node_types
I don't quite agree with Jeremy on the first part. You have to be very careful to mash around in your Drupal database. Sometimes things may seem to work, but then later, you find that you have created a lot of problems for yourself, because you delete something in one table that's referenced in another. Also id number of your blocks really wont effect Drupals ability to create new blocks etc. If you do want "pretty" ids, make sure you test things thoroughly though. But considering the cost/benefit, this is definitely not worth it.
Your tactic with creating a new 4.7 and then upgrading from there should work just fine. I would, however, suggest that you first copy your database, into a copy of your current distro and then deactivate and uninstall all the modules you wont be using. This will erase all the data that's associated to these modules, and should also help clean up your tables in case that have altered those you are using. This might not do anything, but it could help clean up the data you are using.
When Drupal create new nodes, it simply does a SQL INSERT, so it's the database that handles the ids. So you don't need to wory about that. The migrate module Jeremy suggests, should be able to help you out transferring data into your new Drupal install. Bit if you would rather write a script, what you propose seems just fine.
Note
As many upgrade guides and upgrade handbook say. When doing a major upgrade, you should always upgrade through all of the major Drupal releases (e.g. 4 to 5, 5 to 6...), until you reach your goal. The reason is that the internal structure and thus the database schema changes in every major release. So you need the changes done in the data-structure in version 5, to successfully upgrade to version 6. I didn't mention this in my original post, as took this for common knowledge, but it might be a good idea to mention none the less.
Another thing worth noticing, is that as Henrik O correctly points out, you can change the AUTO_INCREMENT value in your database. I can't remember 4.x upgrades, but I believe that Drupal will take care of this, in part of the 4-5 upgrade, as it implements serial tables in that release instead of managing this itself. Also whether or not to run a query to alter the AUTO_INCREMENT depends on the database backend, as not all backends use this property. PostgreSQL don't manage serials in that way, so it should automatically, start creating nodes with the correct nids, if you use it for Drupal.
I'd say your basic approach is fine, but you are right to be concerned about things silently breaking. Your main concern should indeed be referential integrity, as the id handling changed since version 4.7. Originally, Drupal did not use the auto increment/serial features of the Database engines, but did its own id generation by means of the sequences table. They switched to serials in Drupal 5, but for some reason that I do not remember they still kept the sequences table until dropping it in version 6.
So if I where in your position, I'd add an intermediate step and upgrade/migrate to a Drupal 5 install first, then do another upgrade to Drupal 6. The reasoning is that the upgrading process is a more or less hand tuned collection of operations that got refined using the input of users having troubles doing it. Since the most error reports came in from users doing '1 version' upgrades only, going the same route should minimize the probability of encountering unexpected errors/conditions.
Also, your post on drupal.org reveals that the forum instance you want to 'merge in' is a Drupal 5 install, so you could do the merge while you are in the intermediate Drupal 5 'phase' of your migration. (Alternatively, I'd upgrade that instance to Drupal 6 separately before merging it into the main instance.)
As for the id adjustment in Drupal >= 5, you'd need to adjust the AUTO_INCREMENT start value for each affected table explicitly. For example in MySQL, issuing:
ALTER TABLE node AUTO_INCREMENT = 5432;
would tell the node table to start setting new serials (ids) starting at 5432 from now on
(NOTE: AUTO_INCREMENT is the MySQL way of handling this, if using PostgreSQL, take a look at the documentation for the serial 'pseudo' type and the accompanying sequence generation mechanism)
Obviously, you'd need to test your new instance thoroughly. Put a heavy focus on testing the insertion of new data as well as updating existing data (nodes, terms, anything you migrated), as this would reveal errors with the referential integrity.
Be thorough and you should be fine - Good Luck :)
Edit: You should also check the 'variables' table entries carefully, as some settings there might contain a reference to an id of a 'standard' table entry (e.g. a vocabulary vid, a term tid or something similar - in your case especially forum_nav_vocabulary and forum_containers)
If your approach to creating a cleaner base install seems to work then stick with it.
For the second part of the question you may consider the migrate module. It is designed to copy from non drupal cms to drupal, but should be able to help you add drupal content to another drupal site.

Deciding on a database structure for pricing wizard

Option A
We are working on a small project that requires a pricing wizard for custom tables. (yes, actual custom tables- the kind you eat at. From here out I'll call them kitchen tables so we don't get confused) I came up with a model where each kitchen table part was a database table. So the database looked like this:
TableLineItem
-------------
ID
TableSizeID
TableEdgeWoodID
TableBaseID
Quantity
TableEdgeWoodID
---------------
ID
Name
MaterialUnitCost
LaborSetupHours
LaborWorkHours
Each part has to be able to calculate its price. Most of the calculations are very similar. I liked this structure because I can drag it right into the linq-to-sql designer, and have all of my classes generated. (Less code writing means less to maintain...) I then implement a calculate cost interface which just takes in the size of the table. I have written some tests and this functions pretty well. I added also added a table to filter parts in the UI based on previous selections. (You can't have a particular wood with a particular finish.) There some other one off exceptions in the model, and I have them hard coded. This model is very rigid, and changing requirements would change the datamodel. (For example, if all the tables suddenly need umbrellas.)
Option B:
After various meetings with my colleagues (which probably took more time than it should considering the size of this project), my colleagues decided they would prefer a more generic approach. Something like this:
Spec
----
SpecID
SpecTypeID
TableType_LookupID
Name
MaterialUnitCost
LaborSetupHours
LaborWorkHours
SpecType
--------
SpecTypeID
ParentSpecType_SpecTypeID
IsCustomerOption
IsRequiredCustomerOption
etc...
This is a much more generic approach that could be used to construct any product. (like, if they started selling chairs...) I think this would take longer time to implement, but would be more flexible in the future. (although I doubt we will revisit this.) Also you lose some referential integrity- you would need triggers to enforce that a table base cannot be set for a table wood.
Questions:
Which database structure do you prefer? Feel free to suggest your own.
What would be considered a best practice? If you have several similar database tables, do you create 1 database table with a type column, or several distinct tables? I suspect the answer begins with "It depends..."
What would an estimated time difference be in the two approaches (1 week, 1 day, 150% longer, etc)
Thanks in advance. Let me know if you have any questions so I can update this.
Having been caught out much more often than I should have by designing db structures that met my clients original specs but which turned out to be too rigid, I would always go for the more flexible approach, even though it takes more time to set up.
I don't have time for a complete answer right now, but I'll throw this out:
It's usually a bad idea to design a database based on the development tool that you're using to code against it.
You want to be generic to a point. Tables in a database should represent something and it is possible to make it too generic. For example, a table called "Things" is probably too generic.
It may be possible to make constraints that go beyond what you expect. Your example of a "table base" with a "table wood" didn't make sense to me, but if you can expand on a specific example someone might be able to help with that.
Finally, if this is a small application for a single store then your design is going to have much less impact on the project outcome than it would if you were designing for an application that would be heavily used and constantly changed. This goes back to the "too generic" comment above. It is possible to overdesign a system when its use will be minimal and well-defined. I hope that makes sense.
Given your comment below about the table bases and woods, you could set up a table called TableAttributes (or something similar) and each possible option would be of a particular table attribute type. You could then enforce that any given option is only used for the attribute to which it applies all through foreign keys.
There is a tendency to over-abstract with database schema design, because the cost of change can be high. Myself, I like table names that are fairly descriptive. I often equate schema design with OO design. E.g., you wouldn't normally create a class named Thing, you would probably call it Product, Furniture, Item, something that relates to your business.
In the schema you have provided there is a mix of the abstract (spec) and the specific (TableType_LookupID). I would tend to equalize the level of abstraction, so use entities like:
ProductGroup (for the case where you have a product that is a collection of other products)
Product
ProductType
ProductDetail
ProductDetailType
etc.
Here's what my experience would tell me:
Which database structure do you prefer? Without a doubt, I'd go for approach one. Go for the simplest setup that might work. If you add complexity, always ask yourself, what value will it have to the customer?
What would be considered a best practice? That does indeed depend, among others on the size of the project and the expected rate of change. As a general rule, generic tables are worth it when you expect the customer to be adding new types. For example, if your customer wants to be able to add a new "color" entity to the table, you'd need generic tables. You can't predict beforehand what they will add.
What would an estimated time difference be in the two approaches? Not knowing your business, skill, and environment, it's impossible to give a valid estimate. The approach that you are confident in coding will take the least time. Here, my guess would be approach #1 could be 5x-50x as fast. Generic tables are hard, both on the database and the client side.
Option B..
Generic is generally better than specific. Software already is doomed to fail or reach it's capacity by it's design for a certain set of tasks only. If you build something generic it will break less if abstracted with a realistic analysis of where it might head. As long as you stay away from over-abstraction and under-abstraction, it's probably the sweet spot.
In this case the adage "less code is more" would probably be drawn in that you wouldn't have to come back and re-write it again.