Package: gstorm
never forget:python setup.py sdist bdist_wheel && python -m twine upload dist/* --skip-existing # UPLOAD TO PYPIpython-gstormGraphql Simple Tiny Object Relational Mapping - Graphql ORM for pythonCurrent features:QUERYAliasesThere are several aliases for most Query-building functions, which make queries more concise:queryq = query, example:Type.q() # vs Type.query()qm = query, example:Type.qm() # vs Type.query()query_oneq1 = query_one, example:Type.q1() # vs Type.query_one()qs = query_one, example:Type.qs() # vs Type.query_one()filterfil = filter, example:Type.q().fil(...) # vs Type.query().filter(...)afterlong:Type.query().filter(after={'attribute': x, 'date': y})short:Type.q().after(attr=x, date=y)beforelong:Type.query().filter(before={'attribute': x, 'date': y})short:Type.q().before(attr=x, date=y)isNulllong:Type.query().filter(nullAttribute={'attribute': x, 'isNull': y})short:Type.q().isNull(attr=x, value=True)shorter:Type.q().isNull(attr=x)(Defaults to True)findByfb = findBy, example:Type.q(). # vs Type.query().find = findBy, example:Type.q(). # vs Type.query().orderByob = orderBy, example:Type.q(). # vs Type.query().order = orderBy, example:Type.q(). # vs Type.query().limitlim = limit, example:Type.q(). # vs Type.query().offsetoff = offset, example:Type.q(). # vs Type.query().childrenchild = children, example:Type.q(). # vs Type.query().ch = children, example:Type.q(). # vs Type.query().getrun = getQuery allfromtests.modelsimportTankall_tanks=Tank.query().get()# returns -> List[Tank]print(all_tanks)# [Tank(id=1,capacity=10),Tank(id=2,capacity=20),...]Query someYou can concatenate storm methods to manipulate the data and how you want to receive it,
this methods may receive parameters in several ways:filter(kwargs):.filter(name='L1').filter({'name': 'L1'}).filter(name='L1').filter(capacity=1250).filter(name='L1', capacity=1250).filter({'name': 'L1', 'capacity': 1250})orderBy(kwarg):Accepted keys = [asc, desc]Accepted values = GraphQLType ModelAttr enums..orderBy(asc=TypeAttrs.ID).orderBy(desc=TypeAttrs.INSERTED_AT)limit(count).limit(1)fromtests.modelsimportTankall_tanks=(Tank.query().filter(capacity=1250)).get()# returns -> List[Tank]print(all_tanks)# [Tank(id=1,capacity=10),Tank(id=3,capacity=10),...]Query onefromtests.modelsimportTankmy_tank=Tank.query_one().findBy(id=3).get()# returns -> Tankprint(my_tank)# Tank(id='3', name='R342', type='Reposo', capacity=0, room=None, inventories=[])Filtersper field value (exact match, regex accepted)fromtests.modelsimportTankgov_tanks=Tank.query().filter(type='^Gob').get()rest_tanks=Tank.query().filter(type='^Rep').get()print(len(gov_tanks))print(len(rest_tanks))Null attributefromtests.modelsimportTankok_tanks=(Tank.query().filter(nullAttribute={'attribute':'CAPACITY','isNull':False})).get()print(ok_tanks)# short-hand versionfromtests.modelsimportTankok_tanks=Tank.q().isNull(attr='CAPACITY',value=False).get()print(ok_tanks)# using null default value:fromtests.modelsimportTankbad_tanks=Tank.q().isNull(attr='CAPACITY').get()# value param defaults to Trueprint(bad_tanks)Comparison dates (after, before)fromtests.modelsimportBbtInventoryfromdatetimeimportdatetimeasdt,timedeltaastdfromgstorm.helpers.date_helpersimportget_iso8601_strtoday=get_iso8601_str(dt.now()-td(days=1))yesterday=get_iso8601_str(dt.now()-td(days=2))today_inventories=(BbtInventory.query().filter(after={'attribute':'INSERTED_AT','date':"2020-02-27T23:01:44Z"# or: 'date': dt.now() - td(days=1)})).get()print(today_inventories)# Short-hand versiontoday_inventories=(BbtInventory.query().after(attr='INSERTED_AT',date="2020-02-27T23:01:44Z")# or: 'date': dt.now() - td(days=1)).get()print(today_inventories)# Short-hand versionyesterday_inventories=(BbtInventory.query().after(attr='INSERTED_AT',date=yesterday).before(attr='INSERTED_AT',date=today)).get()print(yesterday_inventories)OrderingAsc, Desc, per fieldfromtests.modelsimportBbtInventorylatest_inventories=BbtInventory.query().orderBy(desc=BbtInventoryAttrs.ID).limit(5).get()print(latest_inventories)smallest_inventories=BbtInventory.query().orderBy(asc=BbtInventoryAttrs.VOLUME).limit(5).get()print(smallest_inventories)Limitfromtests.modelsimportBottlingLinefirst_10_lines=BottlingLine.query().limit(10).get()print(first_10_lines)Nested Queriesfromtests.modelsimportBottlingOrder# We want to include the sub-attributes:guid='abc123'orders=BottlingOrder.query()._with({'line':Line.query(),'plans':BottlingPlan.query().orderBy(asc=BottlingPlanAttrs.ID),'brightBeer':BrightBeer.query().filter(groupGuid=guid))}).print(orders[0])# >> BottlingOrder(id=1, name='123', line=Line(name='LINEA001'), ...)Pagination (API NOT FINAL)iterablefromtests.modelsimportDatumorder={'desc':'ID'}fordatum_pageinDatum.limit(100).offset(0).orderBy(asc=DatumAttrs.ORDER).paginate():fordatumindatum_page:print(datum)# type: Datum(id=x,value=y)Comparison numerical (>, >=, <, <=...)NOT WORKING IN VALIOT-APPMUTATIONCreatefromtests.modelsimportTanktank=Tank.load(csv='tanks.csv').limit(1).get()# load from any sourceresponse=storm.create(tank)# GraphqlType objectUpdatefromtests.modelsimportTank[gov_tank]=Tank.query().filter(name='L').limit(1).get()# process data...# ...response=storm.update(gov_tank).apply()# GraphqlType objectUpsertfromtests.modelsimportTank[gov_tank]=Tank.load(csv='tanks.csv').limit(1).get()# load from any sourceresponse=storm.upsert(gov_tank).apply()# GraphqlType objectifnotresponse.successful:print(response.messages)# everything ok, do other stuff...print(gov_tank)# has updated data (New ID, etc)Single mutationSee above examplesMultiple mutationSequentialfromtests.modelsimportTankgov_tanks=Tank.load(csv='tanks.csv').get()# load from any source# ! OPTION 1: one by onefortankingov_tanks:response=storm.upsert(tank).apply()# GraphqlType objectprint(tank)# has updated data (New ID, etc)# ! OPTION 2: All handled by storm:response=storm.upsert(gov_tanks).apply()# response type -> List[GraphqlMutationResponse]Batch (Multiple mutations in single Mutation tag)fromtests.modelsimportTankfromstormimportUploadModeasmodegov_tanks=Tank.load(csv='tanks.csv')# load from any sourceresponse=storm.upsert(gov_tanks).mode(mode.BATCH).apply()# default:# response = storm.upsert(gov_tanks, mode=mode.SEQUENTIAL)Nested mutationAPI WIP:fromtests.modelsimportBbtProgram,BbtPlanfromstormimportUploadModeasmode# algorithm runs...program=BbtProgram()# New with defaultsforplaninalgorithm_plans:program.plans.append(BbtPlan(**plan))# OPTION 1:response=storm.create(program).nested({'plans':Plan.create()}).apply()# OPTION 2:attrs=['plans']response=storm.create(program,nested=attrs)Parallel/Batch (Multiple mutations multi-threaded, each mutation may be batched)NOT PRIORITYSUBSCRIPTIONNOT PRIORITYCOMPARISON# # ! old way [No additional libraries]:
# import requests
# import json
# @dataclass
# class Line():
#   id: str
#   name: str
#   speed: float

# LINE = '''
#   query getLine($name: String!){
#     line(findBy:{ name: $name }){
#       id
#       name
#       speed
#     }
#   }
# '''
# url = 'https://test.valiot.app/'
# content = {
#   'query': LINE,
#   'variables': {'name': 'LINEA001'}
# }
# response = requests.post(url, json=content)
# line_data = json.loads(str(response.content))
# line = Line(**line_data)
# line.name # * >> LINEA001
# # ! current way [pygqlc]:
# gql = GraphQLClient()
# @dataclass
# class Line():
#   id: str
#   name: str
#   speed: float

# LINE = '''
#   query getLine($name: String!){
#     line(findBy:{ name: $name }){
#       id
#       name
#       speed
#     }
#   }
# '''
# line_data, _ = gql.query_one(LINE, {'name': 'LINEA001'})
# line = Line(**line_data)
# line.name # * >> LINEA001

# # * New way (TBD):
# gql = GraphQLClient()
# orm = GStorm(client=gql, schema=SCHEMA_PATH)
# Line = orm.getType('Line')
# line = Line.find_one({'name': 'LINEA001'})
# line.name # * >> LINEA001