Does Rails recognize db view? - sql

Is there a way that to access my db view as a table for a model?

Yes, you can use views just fine, they behave just like tables in ActiveRecord. I don't know what database you're using, but I use them in Oracle and haven't had a problem.
The only difference is that if you want to have your migrations automatically create them, you'll have to forego the typical create_table and instead execute SQL statements to create it.

With MongoDb, I accessed to the MongoDB Views with the following method.
Firstly you should create a dummy model to be able to use MongoDB connectors. You can manually create new file with the name view_names.rb and append below lines.
class ViewName
include Mongoid::Document
include Mongoid::Timestamps
end
And then to access records;
ViewName.collection.find({})
>> #<Mongo::Collection::View:0x0000000107cd4378>)
find gets MongoDB queries as parameter, so you can pass your logic as hash to find method.
{created_at: { '$lte': Date.todat - 2.week }}
View name on MongoDB should be plural view_names just as same with the others.

Related

rename database field in upgrade wizard of an extension in TYPO3 11

I have an upgrade wizard (TYPO3 11) which changes the data of a table.
This is done with the querybuilder:
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('tt_content');
$queryBuilder
->update('tt_content')
->set('CType', 'newCType')
->where($queryBuilder
->expr()
->eq('CType',$queryBuilder->createNamedParameter('oldCType')))
->execute();
But I also need to rename a field in a table:
ALTER TABLE tt_content RENAME COLUMN tx_myext_old_field TO tx_myext_new_field;
I can't find any documentation or example of doing this with the querybuilder.
The normal way woult be to provide a ext_tables.sql in your extension. This is read by TYPO3 to build a virtual "database scheme" how it should look.
The database schema analyser will than provide the information, and database alteration are suggested.
You could add a database must be up to date constraint to your upgrade wizard, that way it is ensured that the field is changed.
DTL is a special task, and you have to provide the correspinng queries yourself ... which are different for different dbms systems. So using the normal way would be recommended.
The platform/driver may have some generig helper methods providing some native sql parts for doing stuffs like that. The may be possible to provide custom stuff based on SchemaMigrator or SchemaManger etc - but thats low-level stuff.
doctrine/dbal directly do not really provide these DTL as API. And the querybuilder is not meant to be used for that low level stuff at all. That's the wrong tool for such tasks.
You can also change columns of core tables that way, by providing simply the table name and the column defintion only for the field you want to change.
The official way is to handle this with ext_tables.sql and the database schema analyser.
See: https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/ExtTablesSql.html
The concept of renaming a column could not work:
On installing the extension all new fields are generated (or should be generated if in composer mode). And as the extension should work with the new columns they are already defined.
And before the upgrade wizard could rename a column these columns are existent already which prevents a rename.
In the end I do a content copy enhancing the update query like this:
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('tt_content');
$queryBuilder
->update('tt_content')
->set('CType', 'newCType')
->set('tx_myext_newfield1',$queryBuilder->quoteIdentifier('tx_myext_oldfield1'),false)
->set('tx_myext_newfield2',$queryBuilder->quoteIdentifier('tx_myext_oldfield2'),false)
->where($queryBuilder
->expr()
->eq('CType',$queryBuilder->createNamedParameter('oldCType')))
->executeStatement();

Executing raw SQL in migrations: keep SQL statements as strings inside a migration or as code inside a separate SQL file?

In the database, I have multiple materialized views with big definitions. I also have multiple migrations that change the definitions of some of these materialized views using DROP and CREATE statements. Thus, we often are dropping / recreating the same views over and over, with small changes. These (rather bulky) statements are now stored inside strings:
class MyMigrationName < ActiveRecord::Migration[5.2]
def up
sql = <<~SQL
...
create materialized view if not exists foo_1 as ... ;
create materialized view if not exists foo_2 as ... ;
...
SQL
execute sql
end
def down
...
end
I am considering switching from this current approach to a different one, where the SQL code is stored inside separate SQL files, for example in db/migrate/concerns/create_foo_matviews.sql. The code is read from the file and executed from inside the migrations, like so:
class MyMigrationName < ActiveRecord::Migration[5.2]
def up
execute File.read(File.expand_path('./concerns/create_foo_matviews.rb', __FILE__))
end
def down
...
end
The pros of this approach are:
It is easier to see the differences between the old and the new SQL code using git diff (especially important given that materialized views' definitions are big, but the actual changes in migrations are relatively small).
The SQL file adds syntax highlighting to the SQL code.
There is less copy/pasted code if I only change the relevant parts in the SQL file.
Are there any problems associated with this proposed approach? If yes, what would be an alternative solution to maximize maintainability?
See also
Is it possible to use an external SQL file in a Rails migration?
Running sql file using rails migration file
Execute SQL-Statement from File with ActiveRecord
I'd leave it in the Migration.
Mainly because the migration then contains everything that actually makes up the DB change.
You would need to have two external SQL files (up and down) that I need to search/find first before I understand what the migration does.
Depending on the Editor you are using, you will get (limited) syntax highlighting
The migrations that execute custom SQL would all look the same, just the name of the external file would be different.
What problem are you trying to solve? Just the "bulky" strings? I don't think that this is problem (to be honest once the migration is run, you not go back to it anyhow) that is worth spennding a lot of time on. Just to the simplest thing: SQL in heredoc string.
There are also gems that allow you to create (materialized) views with normal migration code (by adding support for create_view or similar) but i'd not add an additional dependency for something this simple.
Also consider changing from schema.rb to structure.sql, if not yet done.
Sound like you want to create your own helpers to create materialized views, something like add_index or add_column.
You could make a module named like MaterializedMigrations in your lib directory. then you can required it in a initializer and for last you include it in your migration code, like this:
class MyMigrationName < ActiveRecord::Migration[5.2]
include MaterializedMigrations
def up
create_materialized_view("name_of_view")
end
end
The helper API is only a suggestion, you could design better API for your use cases.

Execute sql CREATE TABLE query in Hibernate

I need to dynamically create a table using a Java method and tranform all its rows into a list of Mapping class objects. The questions are..
Is there a way to execute CREATE TABLE query dynamically?
I saw some examples using doInHibernate() but it didn't work when I tried it. Can I do this without the particular method?
You could just execute a native sql query: session.createSQLQuery("create table .....").executeUpdate(); where "session" is your Hibernate session.
If you already have the mapping files, though, you can just set the hibernate.hbm2ddl.auto property in your hibernate configuration to generate the schema based on the mapping files.
Try this:
session.createSQLQuery(query).executeUpdate();
another possibility would be:
createStatement().execute(someddl);

NHibernate mapping: is it possible to insert values into the database via a mapping file without using a property?

I am writing an application which works with a legacy database (brownfield). I have a couple of tables in which I insert data. These tables have some fields which need values of which I do not want the properties in my domain entities. Is there a way to insert the default value into the field without having to create a property for it my mapping file? I cannot alter the database to create a trigger, so it has to be done via the mapping file/.net application.
Hope someone can help. I hoped I could use a formula, but that doesn't work and I couldn't find any other ways to do it either.
you could use a private / protected property.
That would mean introducing these fields into your domain model / mappings, but they would be limited to those, and not exposed to whoever uses your entities.
seems like a reasonable compromise to me.
You could use EventListeners
in the OnPostInsert / OnPostUpdate event you can get the db connection and ad-hoc execute a sql query.
NH makes it rather easy
using xml see here
using FluentNHibernate see here
the basic idea is to use PropertyAccessor on a non existing property which always has the constant value.

rails: does the build method protect against sql injection

Does build protect against sql injection?
Example:
#post = #user.posts.build(params[:post])
#post.save
Didn't see build in the rails security docs.
Thanks!
build itself doesn't write anything to the database so SQL injection doesn't apply. When you call save it doesn't matter whether the object was created via build or via another mechanism such as passing attributes to new or using individual attribute= methods, the same code will be used to save your object to the database.
From the documentation on build:
Returns a new object of the collection
type that has been instantiated with
attributes and linked to this object
through the join table, but has not
yet been saved.
The save method will escape any quotes etc in your attribute values using a method appropriate to the database you're using (e.g. MySQL) so that the resulting insert or create query is not susceptible to SQL injection. The same applies to update_attributes and to any parameterised :conditions that you pass to find. The time when you need to be careful and may need to do some manual escaping is if you are ever passing literal strings to the database connection as queries.