Why does firstOrFail() cause the results of this eloquent query to change?
>>> Organization::find('300048');
=> Models\Organization {#889
id: 300048,
token: "redacted",
name: "DAYJK4EGPE",
domain: null,
created_at: "2017-05-19 17:42:55",
updated_at: "2017-05-19 17:42:56",
stripe_customer_id: "redacted",
referral_snippet: null,
primary_business: null,
}
>>> Organization::find('300048')->firstOrFail();
=> Models\Organization {#897
id: 300033,
token: "redacted",
name: "123456",
domain: "google.com",
created_at: "2017-05-17 13:24:23",
updated_at: "2017-05-24 15:50:25",
stripe_customer_id: "redacted",
referral_snippet: null,
primary_business: null,
}
>>>
The model with id 300033 is the first in my database, but I expected it to still return the organization with id 300048, since that was the only result in the collection firstOrFail() is being called on.
You've figured it out yourself, but essentially firstOrFail is going to grab the first record when you use a where, if you don't use a where clause it will just get the first record in the DB.
As you've figured out, you need findOrFail in order to find the first record with that ID, or fail.
You should use use Organization::findOrFail('300048');.
See the Laravel docs for more information on throwing exceptions.
Related
I'm probably missing something simple here but how do I get the primary key for a table using Laravel/Eloquent? When I execute the following I'm getting an Incorrect Syntax error while it works when executing directly on the database.
$primarykey = DB::table('table')->whereRaw('SHOW KEYS FROM table WHERE Key_name = "PRIMARY"')->get();
I tried it with following code and it worked.
$primarykey = DB::select('SHOW KEYS FROM users WHERE Key_name = "PRIMARY"');
I had used select of DB without get method because it returns array like this
[
{#3558
+"Table": "users",
+"Non_unique": 0,
+"Key_name": "PRIMARY",
+"Seq_in_index": 1,
+"Column_name": "id",
+"Collation": "A",
+"Cardinality": 1,
+"Sub_part": null,
+"Packed": null,
+"Null": "",
+"Index_type": "BTREE",
+"Comment": "",
+"Index_comment": "",
},
]
So please try and let me know if you find any issue in it.
Thanks
This question already has an answer here:
Karate - Nested JSON object schema validation causes KarateException
(1 answer)
Closed 1 year ago.
recently I started working with Karate and Yaml for the first time. I was able to validate simple response structures where all the answer data were on the same level. But now I have to validate a more complicated structure and I spent a lot of time without success.
When I perform a GET request I receive the next answer:
[
{
"factories": [
{
"id": 1,
"scopes": [
{
"id": null,
"name": "name 1",
"expireD": 10,
"isExpired": true
}
],
"companyName": "TEST",
},
{
"id": 2,
"scopes": [
{
"id": null,
"name": "name 2",
"expireD": 7,
"isExpired": true
}
],
"companyName": "TEST2",
}
],
"scopeId": null
}
]
The structure validation is not directly in the karate code. It is on a yml file like this:
operationId: getTest
statusCode: 200
params:
body: null
matchResponse: true
responseMatches:
scopeId: '##number'
factories:
companyName: '#string'
id: '#number'
scopes:
expireD: '#number'
name: '#string'
id: '#null'
isExpired: '#boolean'
I review the structure around 100 times and I have the same error all the time when I arrive here:
* match response contains responseMatches
The error is the next one:
$[1].factories | data types don't match (LIST:MAP)
I tried to use match each, ignore one by one the structures to see which one is failing and also reduce the validations as #array and it is not working.
Any help will be more than welcome. Thank you.
I really recommend NOT using YAML especially in a testing / validation scenario. But finally it is your call.
Here is a tip to save you some time, you can print out the value of the YAML and see where you were going wrong. I don't know YAML (and avoid it as far as possible), but I made a guess after a few failed attempts and managed to insert a - at the right place (apparently there are many other ways) to make some of the YAML a JSON array - which is what you want.
* text foo =
"""
operationId: getTest
statusCode: 200
params:
body: null
matchResponse: true
responseMatches:
scopeId: '##number'
factories:
-
companyName: '#string'
id: '#number'
scopes:
expireD: '#number'
name: '#string'
id: '#null'
isExpired: '#boolean'
"""
* yaml foo = foo
* print foo
Try the above and see how it differs from your example.
Finally, a solution was found. The Karate documentation offers an idea about how to use it defining a structure of data that could be used as a type. I tried before but I added before the responseMatches section. The yml file looks like this:
operationId: getTest
statusCode: 200
params:
body: null
matchResponse: true
responseMatches:
scopeId: '##number'
factories: '#[_ <= 5] factoryStructure'
factoryStructure:
companyName: '#string'
id: '#number'
scopes: '#[] scopeStructure'
scopesStructure:
expireD: '#number'
name: '#string'
id: '#null'
isExpired: '#boolean'
I running into what I assume is so simple I am just overthinking it. I am running the following commands in my Tinker session and it is working as expected:
$game = Games::find(1);
[!] Aliasing 'Games' to 'App\Models\Games' for this Tinker session.
=> App\Models\Games {#4386
id: 1,
user_id: 1,
title: "Test Game",
description: "This is a test of the game function",
max_players: 8,
deck: "default",
type: "Golf",
privacy: "Public",
current_player: null,
status: "pending",
deleted_at: null,
created_at: "2020-12-18 22:02:17",
updated_at: "2020-12-18 22:02:17",
}
>>> $game->players()->get();
=> Illuminate\Database\Eloquent\Collection {#4322
all: [
App\Models\User {#4384
id: 1,
name: "mark",
email: "test#test.com",
username: "user",
role: null,
email_verified_at: null,
created_at: "2020-12-18 22:02:08",
updated_at: "2020-12-18 22:02:08",
pivot: Illuminate\Database\Eloquent\Relations\Pivot {#4168
games_id: 1,
user_id: 1,
},
},
],
}
I have essentially placed that exact same code in my controller to pull a list of players in a game:
$game = Games::find($game);
$players = $game->players()->get();
and I am getting this when I hit the route:
Method Illuminate\Database\Eloquent\Collection::players does not exist.
I am confused why this wouldnt work in the controller if it works just fine in Tinker.
Thanks for the help!
The normal usage for find() is to pass an id, and it will return a model instance for that id. However, if you pass in an array, or an object that implements \Illuminate\Contracts\Support\Arrayable, it will return a Collection of all the found instances.
Your controller code is this:
$game = Games::find($game);
If the $game value passed into find() here is an array, it will return a Collection of all the models found using the ids in the array.
Another sneaky issue here is if the $game value passed into find() here is a model instance. In this case, this statement will return a Collection, because models implement the Arrayable contract mentioned above.
So, when you call find() and pass in a model, it will call toArray() on that model, attempt to find records for every value returned in the array, and return a Collection of all the records found.
In either case, $game is now a Collection, and you'll get an error when you attempt to call $game->players(), since the players() method does not exist on collections.
$game = Games::find($game);
If you pass a single id to find, it will return a Game model or null. But if you pass an array of ids (even if it's an array of length 1) or a Model (for some reason), it will return a Collection or null.
In your tinker session, try this and you'll have the same error thrown.
$game = Games::find(1);
$game = Games::find($game);
// or
$game = Games::find([1]);
$players = $game->players()->get();
Let's assume I have schema like
type StaticData {
id: Int!
language: String!
name: String!
description: String!
someA: SpecialType!
someB: SpecialType!
}
SpecialType is a scalar. SpecialType can be used in further nested structures as well. Let's now assume I query for a list of StaticData. Is it somehow possible to receive a list of all SpecialType values, without me extracting it manually from the returned object?
Example:
My return object looks like this:
[
{
id: 1,
language: 'en',
name: 'Something',
description: 'SomeDescription',
someA: 1234,
someB: 2345
},
{
id: 2,
language: 'en',
name: 'SomethingElse',
description: 'SomeDescription',
someA: 4564,
someB: 1234
},
]
Since I want all SpecialType values, I do want to extract [1234, 2345, 4564, 1234]. Maybe it is possible to do the extraction on the server using resolvers and receive it with the full result object?
If you want the GraphQL response to be just a list of integers, then you'll need to provide a type of that shape to your schema, i.e. someA: [SpecialType!].
You're on the right track - it's on you to then build and return a list in the resolver that satisfies this structure. Hope this helps!
When performing queries I can go through Mongoid:
product_obj = Product.where(
_id: "58f876f683c336eec88e9db5"
).first # => #<Product _id: 58f876f683c336eec88e9db5, created_at: nil, updated_at: nil, sku: "123", name: "Some text", ...)
or I can circumvent it:
product_hsh = Product.collection.find( {
_id: BSON::ObjectId.from_string("58f876f683c336eec88e9db5")
}, {
projection: {
_id: 1,
name: 1
}
} ).first # => {"_id"=>BSON::ObjectId('58f876f683c336eec88e9db5'), "name"=>"Some text"}
I prefer to circumvent, because it performs better; I can limit which fields to get in the response.
My problem, however, is how to further work with the returned product. The response is a hash, not an object, so if I have to update it I need to pull it through Mongoid anyway, and thereby the performance gains are gone:
Product.find(product_hsh["_id"]).update_attribute(:name, "Some other text")
My question is: how do I update without first having to pull a Mongoid object?
You don't need to pull/fetch at all. You can just send the $set commands directly:
Product.where(id: product_hsh["_id"]).update_all(name: "Some other text")