Perl DBIx::Class encounterd Object Json - json

I'm new to Perl and DBIx::Class.
This is how I get my meaning_ids from the table translation where language = 5:
my $translations = $schema -> resultset('Translation')->search({ language => '5'});
After it I'm trying to push my data from the database into my array data:
while ( my $translation =$translations->next ) {
push #{ $data }, {
meaning_id => $translation-> meaning
};
}
$self->body(encode_json $data );
If I do it like this, I get the following error:
encountered object
'TranslationDB::Schema::Result::Language=HASH(0x9707158)', but neither
allow_blessed , convert_blessed nor allow_tags settings are enabled
(or TO_JSON/FREEZE method missing)
But if I do it like that:
while ( my $translation =$translations->next ) {
push #{ $data }, {
meaning_id => 0+ $translation-> meaning
};
}
$self->body(encode_json $data );
I don't get the error anymore, but the meaning is not the number out of the database. It's way too big (something like 17789000, but only numbers till 7000 are valid).
Is there an easy way to tell Perl that meaning_id is an INT and not a string?

It's a bit hard without knowing your schema classes, but #choroba is right. The error message says $translation->meaning is an instance of TranslationDB::Schema::Result::Language. That's explained in DBIx::Class::Manual::ResultClass on CPAN.
I believe there is a relationship to a table called meaning, and when you call $translation->meaning what you get is a new result class. Instead you need to call $translation->meaning_id. Actually that would only happen in a join, but your code doesn't look like it does that.

It seems $translation->meaning returns an object. Using 0+ just returns its address (that's why the numbers are so high).

It looks like there's a relationship between your translation and meaning tables. Probably, the translation table contains a foreign key to the meaning table. If you look in the Result class for your translation class then you will see that relationship defined - it will be called "meaning".
As you have that relationship, then DBIC has added a meaning method to your class which retrieves the meaning object that is associated with your translation.
But it appears that the foreign key column in your translation table is also called "meaning", so you expect calling the "meaning" method gives you the value of the foreign key rather than the associated object. Unfortunately it doesn't work like that. The relationship method overrides the column method.
This is a result of bad naming practices. I recommend that you call the primary key for every table id and the foreign key that links to another table <table_name>_id - so the column in your translation table would be called meaning_id. That way you can distinguish between the value of the key ($translation->meaning_id) and the associated meaning object ($translation->meaning).
A work-around you can use if you can't rename columns, is to use the get_column method - $translation->get_column('meaning').

Related

Fluent NHibernate Schema output with errors when using list

I have two tables which are Many-To-One mapped. However, it is important to maintain the order of the second table, so when I use automapping, Fluent automapper creates a bag. I changed this to force a list by using this command:
.Override(Of ingredients)(Function(map) map.HasMany(Function(x) x.PolygonData).AsList())
(VB.NET syntax)
So I say "AsList" and instead of using a bag, the mapping xml which gets generated contains a list now. Fine so far. However,
the statement generated cannot be handled by MySQL. I use MySQL55Dialect to create the statements and I use exactly that version. But it creates the following create:
create table `ingredients` (
Id INTEGER NOT NULL AUTO_INCREMENT,
Name FLOAT,
Amout FLOAT,
Soup_id INTEGER,
Index INTEGER,
primary key (Id)
)
It crashes because of the line "Index INTEGER," but I don't know what to do here. Any ideas?
Thanks!!
Best,
Chris
I would suspect that Index could be a keyword for MySQL. To avoid such conflict, we can define different Index column name (sorry for C# notation)
HasMany(x => x.PolygonData)
.AsList(idx => idx.Column("indexColumnName").Type<int>())

Delete entry in couchbase bucket using key in the form of regex

I have a requirement wherein I have to delete an entry from the couchbase bucket. I use the delete method of the CouchbaseCient from my java application to which I pass the key. But in one particular case I dont have the entire key name but a part of it. So I thought that there would be a method that takes a matcher but I could not find one. Following is the actual key that is stored in the bucket
123_xyz_havefun
and the part of the key that I have is xyz. I am not sure whether this can be done. Can anyone help.
The DELETE operation of the Couchbase doesn't support neither wildcards, nor regular expressions. So you have to get the list of keys somehow and pass it to the function. For example, you might use Couchbase Views or maintain your own list of keys via APPEND command. Like create the key xyz and append to its value all the matching keys during application lifetime with flushing this key after real delete request
Well, I think you can achieve delete using wildcard or regex like expression.
Above answers basically says,
- Query the data from the Couchbase
- Iterate over resultset
- and fire delete for each key of your interest.
However, I believe: Delete on server should be delete on server, rather than requiring three steps as above.
In this regards, I think old fashioned RDBMS were better all you need to do is fire SQL query like 'DELETE * from database where something like "match%"'.
Fortunately, there is something similar to SQL is available in CouchBase called N1QL (pronounced nickle). I am not aware about JavaScript (and other language syntax) but this is how I did it in python.
Query to be used: DELETE from b where META(b).id LIKE "%"
layer_name_prefix = cb_layer_key + "|" + "%"
query = ""
try:
query = N1QLQuery('DELETE from `test-feature` b where META(b).id LIKE $1', layer_name_prefix)
cb.n1ql_query(query).execute()
except CouchbaseError, e:
logger.exception(e)
To achieve the same thing: alternate query could be as below if you are storing 'type' and/or other meta data like 'parent_id'.
DELETE from where type='Feature' and parent_id=8;
But I prefer to use first version of the query as it operates on key, and I believe Couchbase must have some internal indexes to operate/query faster on key (and other metadata).
Although it is true you cannot iterate over documents with a regex, you could create a new view and have your map function only emit keys that match your regex.
An (obviously contrived and awful regex) example map function could be:
function(doc, meta) {
if (meta.id.match(/_xyz_/)) {
emit(meta.id, null);
}
}
An alternative idea would be to extract that portion of the key from each document and then emit that. That would allow you to use the same index to match different documents by that particular key form.
function(doc, meta) {
var match = meta.id.match(/^.*_(...)_.*$/);
if (match) {
emit(match[1], null);
}
}
In your case, this would emit the key xyz (or the corresponding component from each key) for each document. You could then just use startkey and endkey to limit based on your criteria.
Lastly, there are a ton of options from the information retrieval research space for building text indexes that could apply here. I'll refer you to this doc on permuterm indexes to get you started.

Update empty string to NULL in a html form

I'm building a site in Laravel.
I have foreign key constraints set up among InnoDB tables.
My problem is that if i don't select a value in a, say, select box, the framework tries to insert or update a record in a table with '' (empty string). Which causes a MySQL error as it cannot find the equivalent foreign key value in the subtables.
Is there some elegant way to force the insertion of NULL in the foreign key fields other than checking out every single field? Or to force MySQL to accept '' as a "null" foreign key reference?
In other words: I have a, say, SELECT field with first OPTION blank. I leave the blank OPTION chosen. When I submit, an empty string '' is passed. In MySQL apparently I can do UPDATE table SET foreignKey=NULL but not UPDATE table SET foreignKey=''. It does not "convert" to NULL. I could check the fields one by one but and convert '' to NULL for every foreign key, maybe specifying all of them in an array, I was wondering if there's a more streamlined way to do this.
Maybe have to change my ON UPDATE action (which is not set) in my DB schema?
Edit: the columns DO accept the NULL value, the problem is in how the framework or MySQL handle the "empty value" coming from the HTML. I'm not suggesting MySQL "does it wrong", it is also logical, the problem is that you can't set a "NULL" value in HTML, and I would like to know if there's an elegant way to manage this problem in MySQL or Laravel.
In other words, do I have to specify manually the foreign keys and construct my query accordingly or is there another robust and elegant way?
My code so far for the model MyModel:
$obj = new MyModel;
$obj->fill(Input::all())); // can be all() or a subset of the request fields
$obj->save();
At least since v4 of Laravel (and Eloquent models), you can use mutators (aka setters) to check if a value is empty and transform it to null, and that logic is nicely put in the model :
class Anything extends \Eloquent {
// ...
public function setFooBarAttribute($value) {
$this->attributes['foo_bar'] = empty($value)?null:$value;
}
}
You can check out the doc on mutators.
I've been oriented by this github issue (not exactly related but still).
Instead of using
$obj = new MyModel;
$obj->fill(Input::all())); // can be all() or a subset of the request fields
$obj->save();
Use
$obj = new MyModel;
$obj->fieldName1 = Input::get('formField1');
$obj->fieldName2 = Input::has('formField2') && Input::get('formField2') == 'someValue' ? Input::get('formField2') : null;
// ...
$obj->save();
And make sure your database field accepts null values. Also, you can set a default value as null from the database/phpmyadmin.
You must remove the "not null" attribute from the field that maps your foreign key.
In the model add below function.
public function setFooBarAttribute($value)
{
$this->attributes['foo_bar'] = $value?:null;
}

Propel ORM with Two FK Columns To Same Foreign Table

I have a table that contains two foreign keys that map back to a membership table. They are named "from_member" and "to_member."
I am trying to get the Member object that represents this membership table by doing something like:
$feedbackQuery = FeedbackQuery::create()->findOne();
$fromMember = $feedbackQuery->getFromMember();
So that I can go like this:
$firstName = $fromMember->getFirstName();
The only problem is you can't do that, evidently Propel requires you to call $fedbackQuery->getMember()and who knows what that's going to return in this case.
Is there any easy way to accomplish getting the member data like this?
Assuming that you are using from_member_id and to_member_id as your foreign keys, you should have two methods at your disposal. getMemberRelatedByToMemberId() and getMemberRelatedByFromMemberId().
To find your from_member object and to use it.
$fromMember = $feedbackQuery->getMemberRelatedByToMemberId();
$firstname = $fromMember->getFirstName();

Errors creating generic relations using content types (object_pk)

I am working to use django's ContentType framework to create some generic relations for a my models; after looking at how the django developers do it at django.contrib.comments.models I thought I would imitate their approach/conventions:
from django.contrib.comments.models, line 21):
content_type = models.ForeignKey(ContentType,
verbose_name='content type',
related_name="content_type_set_for_%(class)s")
object_pk = models.TextField('object ID')
content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")
That's taken from their source and, of course, their source works for me (I have comments with object_pk's stored just fine (integers, actually); however, I get an error during syncdb on table creation that ends:
_mysql_exceptions.OperationalError: (1170, "BLOB/TEXT column 'object_pk' used in key specification without a key length")
Any ideas why they can do it and I can't ?
After looking around, I noticed that the docs actually state:
Give your model a field that can store a primary-key value from the models you'll be relating to. (For most models, this means an IntegerField or PositiveIntegerField.)
This field must be of the same type as the primary key of the models that will be involved in the generic relation. For example, if you use IntegerField, you won't be able to form a generic relation with a model that uses a CharField as a primary key.
But why can they do it and not me ?!
Thanks.
PS: I even tried creating an AbstractBaseModel with these three fields, making it abstract=True and using that (in case that had something to do with it) ... same error.
After I typed out that really long question I looked at the mysql and realized that the error was stemming from:
class Meta:
unique_together = (("content_type", "object_pk"),)
Apparently, I can't have it both ways. Which leaves me torn. I'll have to open a new question about whether it is better to leave my object_pk options open (suppose I use a textfield as a primary key?) or better to enforce the unique_togetherness...