DataMapper to migrate data from one table to another. - ruby

If I am using DataMapper, and I have two databases, is there any way using migration.rb to copy a table for example table person from database 1 to database 2? (same schema and table values).
Referring this:https://github.com/datamapper/dm-migrations/blob/master/examples/sample_migration.rb
It only tells me how to add/modify/drop tables.
Thanks for help.

I don't think that's the intention of dm-migrations. I believe the easiest way would be something like this:
DataMapper.setup(:default, db1_config)
DataMapper.setup(:new, db2_config)
class Foo
include DataMapper::Resource
property :id, Serial
property :name, String
...
end
DataMapper.finalize
Foo.each do |foo|
DataMapper.repository(:new) do
# It may not let you set the "id" attribute here...
Foo.create(foo.attributes)
end
end
Edit
In hindsight, I'm not sure if you were asking how to to copy table structure as to opposed to table data. This is obviously copying table data.

Related

Possible to use `one_to_many_through` associations in Sequel ORM?

I have a case where one model is related 2 other ones. I am trying to correctly setup the model relationships between these 3 models.
A simplified example... The first 2 tables are clients and invoices:
db.create_table(:clients) do
primary_key :id
String :name
end
db.create_table(:invoices) do
primary_key :id
String :description
Integer :balance
end
A third table, called files, contains records for files which can be related to either clients or invoices:
db.create_table(:files) do
primary_key :id
String :name
String :path
String :type # [image, pdf, word, excel]
end
There are 2 joiner tables to connect files to clients and invoices:
db.create_table(:clients_files) do
Integer :client_id
Integer :file_id
end
db.create_table(:files_invoices) do
Integer :invoice_id
Integer :file_id
end
The question is, how to correctly set up the relationships in the models, such that each client and invoice can have one or more related files?
I can accomplish this using many_to_many and has_many :through associations, however, this doesn't seem to be the right approach, because a given file can belong to only one customer or invoice, not to many.
I can also do this using polymorphism, but the documentation discourages this approach:
Sequel discourages the use of polymorphic associations, which is the
reason they are not supported by default. All polymorphic associations
can be made non-polymorphic by using additional tables and/or columns
instead of having a column containing the associated class name as a
string.
Polymorphic associations break referential integrity and are
significantly more complex than non-polymorphic associations, so their
use is not recommended unless you are stuck with an existing design
that uses them.
The more correct association would be one_to_many_through or many_to_one_through, but I can't find the right way to do this. Is there a vanilla Sequel way to achieve this, or is there a model plugin that provides this functionality?
With your current schema, you just want to use a many_to_many association to files:
Client.many_to_many :files
Invoice.many_to_many :files
To make sure each file can only have a single client/invoice, you can make file_id the primary key of clients_files and files_invoices (a plain unique constraint/index would also work). Then you can use one_through_one:
File.one_through_one :client
File.one_through_one :invoice
Note that this still allows a File to be associated to both a client and an invoice. If you want to prevent that, you need to change your schema. You could move the client_id and invoice_id foreign keys to the files table (or use a single join table with both keys), and have a check constraint that checks that only one of them is set.
Note that the main reason to avoid polymorphic keys (in addition to complexity), is that it allows the database to enforce referential integrity. With your current join tables, you aren't creating foreign keys, just integer fields, so you aren't enforcing referential integrity.

Datamapper - create unique index over belongs_to attribute

I'm using DataMapper connected to an SQLite backend. I need to create a Unique index across my four belongs_to columns. Here is the table.
class Score
include DataMapper::Resource
property :id, Serial
property :score, Integer
belongs_to :pageant
belongs_to :candidate
belongs_to :category
belongs_to :judge
#What we want is a UNIQUE INDEX on the four properties!
end
Things I've done:
A unique index on the four via something like :unique_index => :single_score. This works only if you have a property already included.
validates_uniqueness_of, I think the scope only works for a 2-column unique index.
My current solution, which is to just create a dummy field "dont_mind_me", just so I can put :unique_index => single_score in it and everything works. Is this something that's okay to do?
Create an index using raw SQL, SQLite supports a unique index among the four fields.
Basically there are two parts of this question:
Is my solution okay, or should I find another one? I'm at wit's end dealing with what seems to be something trivial, even with raw SQL
How do I create an "after_create_table" hook in DataMapper? The hooks in the documentation only tell about post-CRUD data.

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.

DataMapper association: How do I specify table name that contains the associated rows?

I am working with a database that is already in place and used by other applications.
The people who designed the database did not use pluralized table names, so DataMapper chooses the wrong table name when following associations.
For instance:
class Foo
has n :components # => the table name here should be COMPONENT, but datamapper uses COMPONENTS
end
How do I change this behavior?
Change the name on the model itself.
class Component
# ...
storage_names[:default] = 'component'
end

DataMapper import primary key

I'm running an import script which imports a CSV dump of a database into a local sqlite database using DataMapper.
My models look like this:
class Staff
include DataMapper::Resource
property :staff_id, String, :key => true
property :full_name, String
end
class Project
include DataMapper::Resource
property :project_id, Integer, :key => true
property :title, String
property :status, String
belongs_to :staff
end
The CSV contains the primary key so when I'm do the import I'm using that as it's key. Next time I run the import I clear the tables and start again, however datamapper moans because the primary keys have already been taken.
Is there a way to stop datamapper moaning about this or should I just delete the .db file and re-create an empty .db file just before the import runs? If so what's the easiest way to do this.
You can use DataMapper.auto_migrate! to blow away the tables, and then recreate them matching the current model state. The new tables will be empty of any data from previous runs.
So just after you define your models, but before you begin importing the data do something like the following:
DataMapper.finalize.auto_migrate!
If you create the complete DB from the import, I'd really recommend nuking the database completely to avoid any spill-over from earlier runs. This also keeps your build-db code path well tested.

Resources