I have a table defined in Hasura (Postgres) using native uuid as the field datatype. My goal is to create an update mutation from Swift but the uuid type is not mapped implicitly from Postgres through Hasura and Apollo to Swift. The Hasura documentation states that the uuid type supports using String but when I define the variables, in the update mutation, as a String!,
mutation RedeemMagicLinkCode($code: String!, $iosIdentifierForVendor: String!) {
__typename
update_entityname(where: {code: {_eq: $code}, iosIdentifierForVendor: {_is_null: true}}, _set: {iosIdentifierForVendor: $iosIdentifierForVendor}) {
returning {
id
}
}
}
I get an error from the Apollo code gen build step that Variable "$code" of type "String!" used in position expecting type "uuid".. When I change that to uuid!,
mutation RedeemMagicLinkCode($code: uuid!, $iosIdentifierForVendor: uuid!) {
__typename
update_en...
The code gen step completes, producing API.swift, but several instances of the compile error Use of undeclared type 'uuid' raise and are now coming from a failure during compile of the Apollo generated API.swift.
/// API.swift
...
public let operationName = "RedeemMagicLinkCode"
public var code: uuid
public var iosIdentifierForVendor: uuid
...
Can someone point me in the right direction for letting Swift know what a uuid is or defining my query so that I can pass a String as a parameter through the Apollo managed mutation? Thanks so much!
OM(Goodness), I might need to blush at how simple this solution was.
I considered the error Use of undeclared type 'uuid' plus the documentation that Hasura will accept a String for this custom scalar...
/// API+typealias.swift
public typealias uuid = String
I placed the above type alias code in a file all by itself in the folder where my GraphQL files are and voila, it worked great!
I'm not thrilled with this public type alias now hanging out at the global scope but I am thrilled with a working data service
Related
I'm new to backend Swift and thought I'd use Vapor to get up-and-running on a side project fast...
I ran vapor new WebServer --template=auth-template, and now I'm trying to figure out what something like return \.email means.
For more context, I'm looking in WebServer > Sources > App > Models > Users.swift:
import Authentication
import FluentSQLite
import Vapor
/// Allows users to be verified by basic / password auth middleware.
extension User: PasswordAuthenticatable {
/// See `PasswordAuthenticatable`.
static var usernameKey: WritableKeyPath<User, String> {
return \.email
}
// ...
}
And here is the definition of the User class:
/// A registered user, capable of owning todo items.
final class User: SQLiteModel {
// {omit extra code} ...
var email: String
// {omit extra code} ...
/// Creates a new `User`.
init(id: Int? = nil, name: String, email: String, passwordHash: String) {
// {omit extra code} ...
self.email = email
// {omit extra code} ...
}
}
What does this backslash-dot notation mean?
tl;dr: We take a look at the Swift language reference, and sure enough, the usage of this backslash-dot notation is called a key-path-expression.
(The question has been sufficiently answered, by this point.)
A more hands-on approach on how to get to that piece of buried documentation:
As you can see from the code you posted, the User class contains a property named email.
Notice that, assuming you're using Xcode, if you replace return \.email with return \, you get the compile-error "Expected expression path in Swift key path", so this is a hint that this backslash-dot notation might have to do with something called a key path.
From that documentation on key-path, we see that we could also have written \User.email (and you can try it out in Xcode with no compiler error).
Understanding the greater context of what's going on in that code:
So, semantically, to understand the meaning of the usernameKey declaration you're looking at, we might want to understand what a WritableKeyPath is. In simple, from the documentation, we see that a WritableKeyPath is: "A key path that supports reading from and writing to the resulting value."
So, we see that the usernameKey declaration takes in a WritableKeyPath object and returns a String that is User.email.
Furthermore, it's apparent that the User class needs this usernameKey property in order to conform to the PasswordAuthenticatable protocol, which was imported on the first line with import Authentication (if you care to explore there, take a look at Dependencies > Auth 2.0.0 > Authentication > Basic > BasicAuthenticatable.swift).
I am trying to use UUID as my primary key in Postgres.
I am getting the trait FromSql<'_> is not implemented for Uuid in tokio-postgres.
First I try to use tokio-pg-mapper but it is also showing the same compile error.
So, I try diff approach and try to implement the From on Struct to covert it directly from Row.
When I try to implements From to convert the Row type to my struct Shop.
impl From<Row> for Shop {
fn from(row: Row) -> Self {
Self {
id: row.get("id"), // Id is UUID type
name: row.get("name"),
address: row.get("address")
}
}
}
Still getting the the trait FromSql<'_> is not implemented for Uuid in tokio-postgres
I know that it is asking me to implement the FromSql for the UUID type.
But I looked into the tokio-postgres docs and found that it is already implemented there.
Did I miss something ?
uuid=0.8
tokio-postgres=0.7.2
To activate the UUID support I need to declare it in my Cargo.toml file and it will start working with tokio-pg-mapper and with my custom solution too.
tokio-postgres = {version="0.7.2", features=["with-uuid-0_8"]}
To avoid duplication of data structures I wanted to reuse a type definition on an input type like this
export const DeviceStatus = new ObjectType('DeviceStatus', {
definition: {
time: timestamp,
firmwareVersion: string
},
});
export const DeviceStatusInput = new InputType('DeviceStatusInput', {
definition: {
tenantId: id_required,
deviceId: id_required,
// Reuse of DeviceStatus Field definition
status: DeviceStatus.attribute()
}
});
There is no error since the return type of DeviceStatus.attribute() is fine, and this works for ObjectType inheritance.
From my perspective this should work, but deploying results in a nasty "Internal Error creating Schema" error.
Of course I could move the whole definition into an object and reuse it but that seems weird. Is there any good solution on this for the CodeFirst approach
It seem to be invalid to reference object type in input type.
I recommend to view Can you make a graphql type both an input and output type?
Probably best you can do is to create some convenience method which will create you both object and input type from single definition.
I have two structures:
type GoogleAccount struct {
Id uint64
Token string
}
It represent my custom PostgreSQL object type (i created myself):
CREATE TYPE GOOGLE_ACCOUNT AS
(
id NUMERIC,
token TEXT
);
And next structure is table in DB:
type Client struct {
IdClient uint64 `gorm:"primary_key"`
Name string
PhotoUrl string
ApprovalNumber uint16
Phone string
Password string
HoursOfNotice int8
Google GoogleAccount
}
And my custom object nested in type Client and named as google. I've tried to read data by the next way:
var users model.Client
db.First(&users)
But unfortunately I can't read field google (have a default value). I don't want to create separate table with google_account, or make this structure as separated fields in client table or packed it as json (created separate entity, because this structure used not only in this table and I'm searching new ways, that get the same result, but more gracefully). The task is not to simplify the presentation of data in the table. I need to make the correct mapping of the object from postgres to the entity.
Right now I found one solution - implement Scanner to GoogleAccount. But value in the input method is []uint8. As I can suppose, []uint8 can cast to string, and after that I can parse this string. This string (that keep in db) look like (x,x) - where x - is value. Is the right way, to parse string and set value to object? Or is way to get this result by ORM?
Is the possible way, to read this data as nested structure object?
It looks like you'll want to do two things with what you have: (1) update the model so you have the right relationship binding, and (2) use the .Preload() method if you're trying to get it to associate the data on read.
Model Changes
Gorm automatically infers relationships based on the name of the attributes in your struct and the name of the referenced struct. The problem is that Google attribute of type GoogleAccount isn't associating because gorm is looking for a type Google struct.
You're also missing a foreign key on GoogleAccount. How would the ORM know which GoogleAccount to associate with which Client? You should add a ClientId to your GoogleAccount struct definition.
Also, I would change the primary keys you're using to type uint since that's what gorm defaults to (unless you have a good reason not to use it)
If I were you, I would change my struct definitions to the following:
type Client struct {
IdClient uint `gorm:"primary_key"`
Name string
PhotoUrl string
ApprovalNumber uint16
Phone string
Password string
HoursOfNotice int8
GoogleAccount GoogleAccount // Change this to `GoogleAccount`, the same name of your struct
}
type GoogleAccount struct {
Id uint
ClientId uint // Foreign key
Token string
}
For more information on this, take a look at the associations documentation here: http://gorm.io/associations.html#has-one
Preloading associations
Now that you actually have them properly related, you can .Preload() get the nested object you want:
db.Preload("GoogleAccount").First(&user)
Using .Preload() will populate the user.GoogleAccount attribute with the correctly associated GoogleAccount based on the ClientId.
For more information on this, take a look at the preloading documentation: http://gorm.io/crud.html#preloading-eager-loading
Right now I found one solution - implement Scanner to GoogleAccount. At input of the Scan method I got []uint8, that I cast to string and parse in the end. This string (that keeping in db) look like (x,x) - where x - is value. Of course, it is not correct way to achieve my goal. But I couldn't found other solution.
I highly recommended use classical binding by relationship or simple keeping these fields in table as simplest value (not as object).
But if you would like to experiment with nested object in table, you can look at my realization, maybe it would be useful for you:
type Client struct {
// many others fields
Google GoogleAccount `json:"google"`
}
type GoogleAccount struct {
Id uint64 `json:"id"`
Token string `json:"token"`
}
func (google GoogleAccount) Value() (driver.Value, error) {
return "(" + strconv.FormatUint(google.Id, 10) + "," + google.Token + ")", nil
}
func (google *GoogleAccount) Scan(value interface{}) error {
values := utils.GetValuesFromObject(value)
google.Id, _ = strconv.ParseUint(values[0], 10, 64)
google.Token = values[1]
return nil
}
I'm new to golang and am trying to understand a code example of type wrapping for the "non-atomic" type time.Time.
The type extension in question is from the Go client for GDAX on github, go-coinbase-exchange project.
The expected behavior would be for Time variables from the project (coinbase.Time), which are of type Time time.Time (as defined in the project's time.go file) to behave something like the following example for extending the "atomic" type int (from blog.riff.org in that they might follow a kind of "inheritance" from the base type for functions like Time.format (from golang's standard implementation of time:
package main
import "fmt"
type Int int
func (i Int) Add(j Int) Int {
return i + j
}
func main() {
i := Int(5)
j := Int(6)
fmt.Println(i.Add(j))
fmt.Println(i.Add(j) + 12)
}
But if I modify the code example from the project's List Account Ledger example found in Readme.md to include a print function which might otherwise give me a human-readable view of the CreatedAt struct variables (as follows), I get a compiler error saying that "type coinbase.Time has no field or method Format":
for _, e := range ledger {
print("Entry Creation: ")
fmt.Printf(e.CreatedAt.Format("2006-01-02 15:04:05.999999+00"))
}
The expected behavior inside the for loop would be for it to print the ledger entries in a human-readable format. I can get the contents of the structs, but I'm not really sure how to then use the resulting wall, ext and loc members.
For example, inserting fmt.Printf("%#v", e.CreatedAt) into the for loop gives me a representation of the time that looks something like this:
coinbase.Time{wall:0x3015a123, ext:63612345678, loc:(*time.Location)(nil)}
{806986000 63638738354 <nil>}
I can also see that wall is of type uint64, that ext is of type int64 and that loc is just GMT/UTC=0 by formatting the variable as a string because fmt.Printf("%s", e.CreatedAt) gives me output which is similar to the following:
{%!s(uint64=712345678) %!s(int64=63612345678) %!s(*time.Location=<nil>)}
It seems like I'm missing something. I've requested further information through issues tab on github, but maybe this is a nube question. So I'm not sure how quick the response time would be, and I'm interested in the more general case for extending non-atomic types in go.
Named types do not inherit any methods from the underlying type (indeed there is no inheritance at all in Go); you must cast to the underlying type to call any methods from that type:
(time.Time(e.CreatedAt)).Format("2006-01-02 15:04:05.999999+00")