How do I dynamically pick a table in Sequel associations? - ruby

I'm trying to create a one-to-one association between two models, called A and B. Model B can exist in either table Foo, if Foo exists, or table Bar, all other situations.
I tried using the :dataset flag of the one_to_one association method to get it to work, but can't seem to figure out how to make it work without introducing a circular dependency.
Is there a way to accomplish this with Sequel associations? Or is the best course of action to hand-write SQL?

I'm not sure I completely understand what you are attempting to do, but from your description, you should just need to make B's table dependent on whether table Foo exists:
class B < Sequel::Model(DB.table_exists?(:Foo) ? :Foo : :Bar); end
If you really wanted to do it just for the association and not for all of model B, you can modify the FROM table in the association block:
A.many_to_one(:b){|ds| ds.from(ds.db.table_exists?(:Foo) ? :Foo : :Bar)}
I haven't tested either of these, but they should work. If that's not what you want, you probably want to add more detail to your description.

Related

How to fetch data from multiple tables with one SQL query in Hanami?

I have Hanami models User and UserInfo that have has_one association.
Repositories look the following:
class UserInfoRepository < Hanami::Repository
end
class UserRepository < Hanami::Repository
associations do
has_one :user_info
end
end
Question: who can I join and load both tables with one query? (I am looking for something similar to Rails' includes).
So far I've tried
def users_with_info
users.join(:user_info)
end
It does the join, but does not select columns from user_infos table.
Thanks in advance.
When you fetch data via a Repository in Hanami the result set is mapped into entities.
By default the UserRepository will map to the User entity. I'm guessing that that entity does not have attributes for the columns from user_info.
What you need to do is create an Entity that can contain the data that you want to fetch from the database and then call .as(ThatEntityYouCreated) on the result set. E.g.,
def users_with_info
users.join(:user_info).map_to(UserWithInfo)
end
If you do not want to create an Entity and just want to get a plain hash, you can do this:
users.join(:user_info).map.to_a
However, I consider this to be a crutch. You should not return Hashes from your Repository methods.
I believe we faced this exact issue with a teammate of mine on one of our Hanami project, and this is how we solved it.
We basically bypassed Hanami repository, going straight to the underlying ROM relation, using ROM::Relation#wrap in order to get our User entity joined with the entity of interest.
Let met know if it helped you, or if you need more details. Cheers!

Rails model to handle composite records

The first form of database normalisation is to hold potentially null fields in a second table, and join these in when they are referred to. The SQL would look something like this.
SELECT A.*, DA.* FROM ANIMALS A
INNER JOIN DOG_ATTRIBUTES DA ON DA.ANIMAL_ID = A.ID
This is pretty common for large databases to use, so only a dog would have the dog-specific attributes. Now I know this could be implemented as a has_one relationship, e.g.
class Dog < Animal
has_one :dog_attribute
end
If it was a read-only model, I could implement the above SQL as a view, and just refer to the DOGS view in my Dog model.
Is there a way I can treat the composite Dog object (with attributes from the ANIMALS table and the DOG_ATTRIBUTES table) as a single model, placing attributes of both into forms, saving them as one command and retrieving the attributes of both?
You're looking for Multiple-Table Inheritance (MTI). Rails by default only supports single-table inheritance, but you can install ActiveRecord::ActsAs for this capability.
Simulates multiple-table-inheritance (MTI) for ActiveRecord models. By
default, ActiveRecord only supports single-table inheritance (STI).
MTI gives you the benefits of STI but without having to place dozens
of empty fields into a single table.`

Find Model name from Table name (Sequel ORM)

In a ruby script I am running a loop in which I am dynamically getting a table name from a list of tables and have to perform some sort of CRUD operation (mainly insertion) on it.
I am using Sequel Orm and have created models for the various tables.
How do I find the name of the Model for each table so that I can perform the insertion?
tables=["table1","table2",'table3",...]
tables.each do |t|
#perform insertion on t
#how to find the model name for table t?
end
I can use a hash to store the model names for each table or can follow a pattern like converting the first character of each table to uppercase or something like that.
Is there a better way to do this?
What you are asking is not possible in the general case without a brute force search, and even then it is ambiguous, for the simple reason that the following is valid:
class Foo < Sequel::Model(:table1); end
class Bar < Sequel::Model(:table1); end
Basically, each model has a related dataset (usually just a simple SELECT * FROM table). However, other models can use the same or similar dataset. So going from model to table is simple, but table to model is not.
If you've created your own models, the easiest way to handle what you want is to use a hash:
ModelMap = {}
ModelMap["table1"] = Model1
ModelMap["table2"] = Model2
Then you can just do:
ModelMap[t]
inside that each block to get the model class.
One way to get the model name from the table name, as long as pluralization conventions have been followed between your models and tables, is something like:
table_name = :users
table_name.to_s.classify
However it doesn't look like that's what you're trying to do. You need to insert new or update existing reords. Since you already have the table name, you may wish to consider doing something like:
tables=["table1","table2",'table3",...]
tables.each do |t|
DB[t.to_sym].insert(...)
end
However you may wish to consider that Jeremy Evans, whose answer is above, is the creator of the Sequel gem and if he didn't recommend this as a solution then there may be a good reason.

Rails -- Single Table Inheritance -- conceptual question about model relationships

I wanted to know if it is possible to have STI where the subclasses each relate to an unrelated model in different ways.
In other words, say B < A and C < A, and I implement single table inheritance on table A (e.g. a type column where you can have B or C to indicate a subclass).
Now let's say we have a separate model called Xyzzy.
Is it possible to implement a has_and_belongs_to_many relationship between C and Xyzzy while implementing a has_one relationship between B and Xyzzy?
How should I do this in the context of STI? Or would STI simply not affect this?
There is nothing particular to do to make this happen. Simply create your relationships.
Indeed, even if B and C have access to some columns they don't care about, well... they simply don't care about.

Doctrine ORM: How to define a 1-n realtionship with a n-n connecting table

So, this is a bit complicated: I have two tables, say cats and dogs.
They are in a many-to-many relationship (could be called friendships or whatever), so that Doctrine automatically creates a table cats_dogs for me with the appropriate fields. (that is rowid, cat_id, dog_id per default.)
Now, imagine I have a third table, award, where I want to award one of these friendships. Here I therefore need a field that references one row in cats_dogs. However, since this table does not really exist between my models, (Doctrine handles it for me) what would be the most elegant solution for this?
In the end, I want in my award model two fields, a cat and a dog, who need to be in a friendship.
I am using the annotation driver.
What stops you from manually creating the m:n table instead of having doctrine do it for you?
The Doctrine aims is to map objects from an E/R schema and to make easier the access to object connections. Therefore I believe that the table cats_dogs automatically provided by Doctrine is necessary as it is. It is concise and hits its purposes, i.e. it provides a list of all dogs of a cat or, vice versa, all the cats of a dog.
Thus, I can conclude that it is preferable to create a third entity (besides Cat and Dog) named Award which provides a one-to-one relationship with Cat and another one-to-one relationship with Dog. Making it consistent with the cats_dogs table is only up to you, and is not a Doctrine task by default. E.g., you can use some cascade persist option.
I believe that this is the most effective solution with Doctrine.
As a final remark, consider that each table should map a specific relationship between one or more entities, and in fact the table cats_dogs represents the friendship relationships, while the table Award will represent the awarded relationship relationship between two friends.

Resources