Circular reference with mongokit - is it possible? - mongokit

I'm having 2 classes Branch & User. User belongs to certain branch. However every branch has a CEO (a type of User). But when I design the mongokit classes and trying to use reference it does work for class User (as branch is defined ahead of User), but it doesn't work for class Branch, getting the following error:
'ceo': User
NameError: name 'User' is not defined
So the question - how to achieve such reference?
from mongokit import *
from datetime import datetime, date, time
import pprint
db = Connection()
#db.register
class Registry(Document):
structure = {
'created': datetime,
'updated': datetime,
'deleted': datetime
}
#db.register
class Branch(Registry):
structure = {
'name':unicode,
'groupEmail':unicode,
'timezone':unicode,
'address': {
'address1':unicode,
'address2':unicode,
'city':unicode,
'state':unicode,
'country':unicode,
'zip': unicode
},
'size':int,
'ceo': User
}
#db.register
class User(Document):
structure = {
'fname': unicode,
'lname': unicode,
'branch': Branch,
'address': {
'address1':unicode,
'address2':unicode,
'city':unicode,
'state':unicode,
'country':unicode,
'zip': unicode
},
'created': datetime,
'updated': datetime,
'deleted': datetime
}

Related

How To Get Pydantic To Discriminate On A Field Within List[Union[TypeA, TypeB]]?

I am trying to use Pydantic to validate a POST request payload for a Rest API. A list of applicants can contain a primary and optional other applicant. So far, I have written the following Pydantic models listed below, to try and reflect this. The Rest API json payload is using a boolean field isPrimary to discriminate between a primary and other applicant.
from datetime import date
from pydantic import BaseModel, validator
from typing import List, Literal, Optional, Union
class PrimaryApplicant(BaseModel):
isPrimary: Literal[True]
dateOfBirth: Optional[date]
class OtherApplicant(BaseModel):
isPrimary: Literal[False]
dateOfBirth: date
relationshipStatus: Literal["family", "friend", "other", "partner"]
class Application(BaseModel):
applicants: List[Union[PrimaryApplicant, OtherApplicant]]
#validator("applicants")
def validate(
cls,
v: List[Union[PrimaryApplicant, OtherApplicant]]
) -> List[Union[PrimaryApplicant, OtherApplicant]]:
list_count = len(v)
primary_count = len(
list(
filter(lambda item: item.isPrimary, v)
)
)
secondary_count = list_count - primary_count
if primary_count > 1:
raise ValueError("Only one primary applicant required")
if secondary_count > 1:
raise ValueError("Only one secondary applicant allowed")
return v
def main() -> None:
data_dict = {
"applicants": [
{
"isPrimary": True
},
{
"isPrimary": False,
"dateOfBirth": date(1990, 1, 15),
"relationshipStatus": "family"
},
]
}
_ = Application(**data_dict)
if __name__ == "__main__":
main()
With the example json payload listed above, when I try to remove some of the required mandatory fields from the OtherApplicant payload a ValidationError is correctly raised. For example, if I try to remove relationshipStatus or dateOfBirth field an error is raised. However, the isPrimary field is also reported by Pydantic to be invalid. Pydantic believes that this the isPrimary field should be True??? Example Pydantic validation output is listed below.
Why is Pydantic expecting that the isPrimary field should be True for an OtherApplicant list item in the json payload? Is it somehow associating the payload with PrimaryApplicant because of the use of Union? If so, how do I get Pydantic to use the isPrimary field to distinguish between primary and other applicants in the list payload?
Missing relationshipStatus field in list payload for OtherApplicant
pydantic.error_wrappers.ValidationError: 2 validation errors for Application
applicants -> 1 -> isPrimary
unexpected value; permitted: True (type=value_error.const; given=False; permitted=(True,))
applicants -> 1 -> dateOfBirth
field required (type=value_error.missing)
Missing dateOfBirth field in list payload for OtherApplicant
pydantic.error_wrappers.ValidationError: 2 validation errors for Application
applicants -> 1 -> isPrimary
unexpected value; permitted: True (type=value_error.const; given=False; permitted=(True,))
applicants -> 1 -> relationshipStatus
field required (type=value_error.missing)
Found the answer via also asking on Pydantic GitHub Repository
Pydantic 1.9 introduces the notion of discriminatory union.
After upgrading to Pydantic 1.9 and adding:
Applicant = Annotated[
Union[PrimaryApplicant, OtherApplicant],
Field(discriminator="isPrimary")]
It is now possible to have applicants: List[Applicant] field in my Application model. The isPrimary field is marked as being used to distinguish between a primary and other applicant.
The full code listing is therefore:
from datetime import date
from pydantic import BaseModel, Field, validator
from typing import List, Literal, Optional, Union
from typing_extensions import Annotated
class PrimaryApplicant(BaseModel):
isPrimary: Literal[True]
dateOfBirth: Optional[date]
class OtherApplicant(BaseModel):
isPrimary: Literal[False]
dateOfBirth: date
relationshipStatus: Literal["family", "friend", "other", "partner"]
Applicant = Annotated[
Union[PrimaryApplicant, OtherApplicant],
Field(discriminator="isPrimary")]
class Application(BaseModel):
applicants: List[Applicant]
#validator("applicants")
def validate(cls, v: List[Applicant]) -> List[Applicant]:
list_count = len(v)
primary_count = len(
list(
filter(lambda item: item.isPrimary, v)
)
)
secondary_count = list_count - primary_count
if primary_count > 1:
raise ValueError("Only one primary applicant required")
if secondary_count > 1:
raise ValueError("Only one secondary applicant allowed")
return v
def main() -> None:
data_dict = {
"applicants": [
{
"isPrimary": True
},
{
"isPrimary": False,
"relationshipStatus": "family"
},
]
}
_ = Application(**data_dict)
if __name__ == "__main__":
main()

Convert inline query to a query in TypeORM

I need to convert this SQL query:
DECLARE #user AS dsschema.user_tools;
INSERT INTO #user VALUES('`+ body.user_id+`','`+ body.tool_id+`');
EXECUTE dsschema.sp_user_tool #user
To a TypeORM createQueryBuilder();
Can someone please help me?
I tried the following but facing issues like:
Must declare the scalar variable #user:
Service.ts
class UserTools{
constructor(#InjectRepository(User) private userRepo: Repository:<User>)
async insertUserData(body){
try {
const result = await this.manager.query(`DECLARE #user AS dsschema.user_tools`);
const querybuilderResult = await this.userRepo.createQueryBuilder()
.insert().into(#user).values({user_id: body.user_id, tool_id: body.tool_id});
const spResult = await this.manager.query(`dsschema.sp_user_tool #user`);
return spResult;
} catch
{
throw error;
}
}
}
user.entity.ts
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
#Entity()
export class User {
#PrimaryGeneratedColumn()
user_id: string;
#Column()
tool_id: string;
}
First of all, #PrimaryGeneratedColumn() by default uses auto incrementing integers, meaning in your case user_id would be of type number, not string. You can find more information on the decorator in the TypeORM Docs:
#PrimaryGeneratedColumn() creates a primary column which value will be automatically generated with an auto-increment value. It will create int column with auto-increment/serial/sequence/identity (depend on the database and configuration provided).
Apart from that:
In your attempt you're executing the 3 instructions individually, meaning that the #user context is no longer available when you run your insert statement.
The table name is quoted by TypeORM, meaning it will try to insert to "#user" instead of #user. SQL server will reject this with Invalid object name '#user'.
Here's how you could do it:
// This is the variable where the
// user_tools table will be stored
const userVariable = '#user';
// getQueryAndParameters() returns an array with
// two items, the query and the parameters.
//
// In this case:
// [
// 'INSERT INTO "#user"("user_id", "tool_id") VALUES (#0, #1)',
// [ 123, 'abc' ]
// ]
//
const insertStatement = this.userRepo
.createQueryBuilder()
.insert()
.into(userVariable)
.values({
user_id: 123,
tool_id: 'abc',
})
.getQueryAndParameters();
// Here we execute the statements in the same batch
// to address [1]
// For [2] we have to unescape your variable
// name #user (which is currently the quoted "#user")
await this.userRepo.query(
`
DECLARE ${userVariable} AS dsschema.user_tools;
${insertStatement[0].replace(`"${userVariable}"`, userVariable)};
EXECUTE dsschema.sp_user_tool ${userVariable};
`,
insertStatement[1]
);

Vue instance data not the same as network response, where is the bug?

Network response:
Vue instance:
Expected network response would be that the all_members would show all (in my case 12) club_members. If I query without using first/skip, it shows only 10 club_members (which is incorrect)
I currently have found a workaround with letting data.totalClubMembers.club_members override the data.club.all_members. Related discussion here: https://github.com/Akryum/vue-apollo/issues/196
(A part of) the query with arguments: $where: 1, $first: 10, $skip: 0.
query club($where: ClubWhereUniqueInput!, $first: Int, $skip: Int){
club: club(where: $where){
name
all_members: club_members {
id
}
club_members: club_members(first: $first, skip: $skip) {
id
category
club_reference_id
valid_from
valid_to
}
}
totalClubMembers: club(where: $where){
club_members {
id
}
}
}
Please advise:
if/where I made a mistake
if there is a more "optimal" solution.
Only root aliases seem to work for now (dec. 2018): https://github.com/prisma/graphql-yoga/issues/340
Refactor into 2 graphql queries will solve it.

Finding the origin of Postgres/Sequelize duplicate alias error (code 42712)

I'm using Sequelize to manage by Postgres SQL database in a node.js project. I'm running into namespace errors but can't for the life of me figure out why.
The code that works:
// db variable holds initialized database connection
const link = name => ( {
through: db.define( name, {
amount: Sequelize.FLOAT,
unit: Sequelize.STRING,
dataSource: Sequelize.STRING
} ),
as: name + 's'
} )
// All model variables (Material, Component etc) have model names
// identical to their variable names (bit without capitals)
Material.belongsToMany( Material, link( 'materialchildmaterial' ) )
Component.belongsToMany( Component, link( 'componentchildcomponent' ) )
Input.belongsToMany( Input, link( 'inputchildinput' ) )
Component.belongsToMany( Component, link( 'componentchilddependency' ) )
The moment I add the following things break:
Input.belongsToMany( Component, link( 'componentchildinput' ) )
The error:
{ name: 'SequelizeDatabaseError',
parent:
{ name: 'error',
length: 177,
severity: 'ERROR',
code: '42712',
file: 'parse_relation.c',
line: '420',
routine: 'checkNameSpaceConflicts' },
original:
{ name: 'error',
length: 177,
severity: 'ERROR',
code: '42712',
file: 'parse_relation.c',
line: '420',
routine: 'checkNameSpaceConflicts' } }
From the postgres docs code 42712 stands for 'DUPLICATE ALIAS'.
My confusion: I am using unique names for everything (afaik). When I change the Input <--> Component link's name to 'randomthing' the error does not appear.
I've been stuck at this for a good day now. Any clues appreciated.

Django Rest Framework Displaying Serialized data through Views.py

class International(object):
""" International Class that stores versions and lists
countries
"""
def __init__(self, version, countrylist):
self.version = version
self.country_list = countrylist
class InternationalSerializer(serializers.Serializer):
""" Serializer for International page
Lists International countries and current version
"""
version = serializers.IntegerField(read_only=True)
country_list = CountrySerializer(many=True, read_only=True)
I have a serializer set up this way, and I wish to display serialized.data (which will be a dictionary like this: { "version": xx, and "country_list": [ ] } ) using views.py
I have my views.py setup this way:
class CountryListView(generics.ListAPIView):
""" Endpoint : somedomain/international/
"""
## want to display a dictionary like the one below
{
"version": 5
"country_list" : [ { xxx } , { xxx } , { xxx } ]
}
What do I code in this CountryListView to render a dictionary like the one above? I'm really unsure.
Try this
class CountryListView(generics.ListAPIView):
""" Endpoint : somedomain/international/
"""
def get(self,request):
#get your version and country_list data and
#init your object
international_object = International(version,country_list)
serializer = InternationalSerializer(instance=international_object)
your_data = serializer.data
return your_data
You can build on the idea from here:
http://www.django-rest-framework.org/api-guide/pagination/#example
Suppose we want to replace the default pagination output style with a modified format that includes the next and previous links under in a nested 'links' key. We could specify a custom pagination class like so:
class CustomPagination(pagination.PageNumberPagination):
def get_paginated_response(self, data):
return Response({
'links': {
'next': self.get_next_link(),
'previous': self.get_previous_link()
},
'count': self.page.paginator.count,
'results': data
})
As long as you don't need the pagination, you can setup a custom pagination class which would pack your response in whichever layout you may need:
class CountryListPagination(BasePagination):
def get_paginated_response(self, data):
return {
'version': 5,
'country_list': data
}
Then all you need to do is to specify this pagination to your class based view:
class CountryListView(generics.ListAPIView):
# Endpoint : somedomain/international/
pagination_class = CountryListPagination
Let me know how is this working for you.