Skip to content
This repository was archived by the owner on Apr 14, 2022. It is now read-only.

Kh/to avro #58

Merged
merged 4 commits into from
Mar 13, 2018
Merged

Kh/to avro #58

merged 4 commits into from
Mar 13, 2018

Conversation

Khatskevich
Copy link
Contributor

No description provided.

Copy link
Member

@Totktonada Totktonada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Questions and comments for the code are attached. Answers for such questions can be good basis for proper documentation and code comments.

Please, give attention to my expectation to have backlog trackerized once the feature will be implemented in the current state (see related comment).

@@ -41,23 +84,74 @@ testdata.meta = {
"order_collection": {
"schema_name": "order",
"connections": [
{
"type": "1:N",
"name": "order__order_item",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having schema/collection name as part of connection makes understanding of a query harder.

-- - id
-- - first_name
-- - last_name
-- - order: Orders of users.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose to clarify (comment here) that order is a shopping cart to better understanding the example.

local item_id_max = #items
for _, item in ipairs(items) do
virtbox.item_collection:replace(
{item.id, item.description, item.name, item.price}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Broken indent.

order_item_cnt = order_item_cnt + 1
local item_id = order_item_cnt % item_id_max + 1
virtbox.order_item_collection:replace(
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Broken indent.

return result
end
error('Unknown type "' .. fieldTypeName .. '" for field "' ..
field.name .. '"')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

luacheck output:

graphql/query_to_avro.lua:62:13: accessing undefined variable field

end

if fieldTypeName == 'Scalar' or fieldTypeName == 'Enum' then
return fieldType.serialize(result)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you describe what is going on here? We have no any value to serialize… Also it is unexpected to see scalars here, as you process it separatelly.

return result
--return collection_to_avro(fieldType, result, subSelections, context)
elseif fieldTypeName == 'Interface' or fieldTypeName == 'Union' then
local objectType = fieldType.resolveType(result)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We trying to resolve union to a certain type based on what information? We have no values here to choose one of variants. Can you describe it, please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake. It should not work properly, but I did not know what to do with unions. 1. They are not implemented. 2. They are represented in different ways in gql and tarantool. A suttose at this point we should assert here.

elseif fieldTypeName == 'Interface' or fieldTypeName == 'Union' then
local objectType = fieldType.resolveType(result)
result.type = collection_to_avro(objectType, result,
subSelections, context)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python-style indent.

return result
end

collection_to_avro = function(objectType, object, selections, context)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe 'object_to_avro' is better name? I think about a case with inner record within a collection object or with an object within an array.

return result
end

if fieldTypeName == 'Scalar' or fieldTypeName == 'Enum' then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t know how to receive 'scalar' from our avro-schemas. Maybe we should ban it?

We have no enum / union support for now (and maybe interfaces too). I think we need to test it or stated explicitly that it need to be tested once will be available. So, I expect that you will file bunch of issues to support various types in AST or at least add notes re query schemas to existing issues for supporting of such features.

(is not for offend) If you don’t sure current implementation will work properly, maybe it is better to remove it for now to keep code compact and readable?

@Totktonada Totktonada requested a review from SudoBobo March 4, 2018 23:13
@Totktonada
Copy link
Member

Added @SudoBobo as optional reviewer.

@Khatskevich Khatskevich force-pushed the kh/to_avro branch 5 times, most recently from fe69468 to 49de748 Compare March 5, 2018 15:47
@Totktonada Totktonada requested a review from Kasen March 5, 2018 16:11
Copy link
Member

@Totktonada Totktonada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is good enough (there was worse code from me). Despite that I leave some comments to grow our feeling of a 'healthy code'.

---
--- @treturn table `avro_schema` avro schema for any `query:execute()` result.
function query_to_avro.convert(query)
local state = query.state
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: it is good to catch compiled_query.avro_schema() (period instead of colon) calls and produce a meaningfull message in the case. Just assert that the query parameter is a table.

-- The function converts avro type to nullable.
-- In current tarantool/avro-schema implementation we simply add '*'
-- to the end of type name.
-- The function do not copy the resulting type but changes it in place.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It changes and returns changed object both. Personally I prefer to implement one of that approaches to decrease possible area to misuse a function (one can expect that it does not change the parameter, because it returns the new result).

Copy link
Member

@Totktonada Totktonada Mar 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Khatskevich You just ignored the comment. So I don’t know your point and I have mine preferences. I’ll fix it according to what I know — mine preferences.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer here to leave it both return and change an input in place, because of immutability of strings in Lua.

-- @tparam table avro schema node to be converted to nullable
--
-- @tresult table schema node; basically it is the passed schema node,
-- however in nullable type implementation through unions it can be different
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't get you in two ways:

  1. As I see we always return the same table (but with change field).
  2. What is nullable type implementation through unions? The above statement says that nulable type is implemented via '*'. Maybe more context needed here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Khatskevich You just ignored the comment. I’ll fix it according to mine preferences.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed confusing part about an union.

avro.type = make_avro_type_nullable(avro.type)
return avro
end
assert(false, "Avro type should be a string or table")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is good to have "got " .. type_type at the end (saves some time at debug).

return result
end

-- The function converts avro type to nullable.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function cannot be applied to its result, yep? We need to check wheter passed type is nullable or stated non-self-applicability explicitly in the comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert on nullable types is worse option then self-applicability, IMO, but ok, you fixed it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked to allow nulllable type as an input.

local innerType = fieldType.ofType
-- Steal type from virtual object.
-- This is necessary because in case of arrays type should be
-- "completed" into results `items` field, but in case of 1:1 relations
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to oppose an array (List) vs a record (Object) and a scalar (Scalar). That is exactly what this part of the code doing. When you say about 1:1 connection it at least yield the question what is going with nested/top-level records and scalars.

--- root to the current object
---
--- @treturn table corresponding Avro schema
object_to_avro = function(object_type, selections, context, nullable)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused and undocumented parameter nullable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have --no-unused-args in luacheck, because it is too restricting in some cases. Say, when you don’t use self parameter of a function.

context.namespace_parts = {}
local rootType = state.schema[context.operation.operation]
local selections = context.operation.selectionSet.selections
return object_to_avro(rootType, selections, context, false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you’ll remove nullable parameter, don’t miss to remove it here.

NonNull)
local fieldTypeName = fieldType.__type
if fieldTypeName == 'NonNull' then
-- In case the field is NonNull, the real type is in ofType attibute.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attibute → attribute

local function complete_field_to_avro(fieldType, result, subSelections, context,
NonNull)
local fieldTypeName = fieldType.__type
if fieldTypeName == 'NonNull' then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if is… hmm… hard to read. Let’s look over with me:

  1. The fieldTypeName == 'NonNull' branch.
    • Here we see renaming that works like recursion, but expressed via fall-through.
    • By the way, it cannot process several nested NonNull’s.
  2. NonNull ~= true branch.
    • Never use x ~= true. Your reader does not want to normalize the code in the brain.
    • Here we use recursion and don’t use fall-through.

How to make the code readable? Options I see:

  • Save is_nonnull or is_nullable flag. Process fieldType/fieldType.ofType and save the result. Make it nullable in dependence of the flag. Return the result.
  • Save is_nonnull or is_nullable flag. In case of NonNull resursively call the function, but pass the flag in a parameter. Process result. Make it nullable in dependence of the flag. Return the result.

I appeal you to leave it as is if you comfortable with your approach, but I think that it is good to share argued opinions between us.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Khatskevich You just ignored the comment. I’ll fix it according to mine preferences.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked according to the first option. Make it returning a result using return instead of the mutable table parameter.

@Totktonada Totktonada self-assigned this Mar 13, 2018
Totktonada referenced this pull request Mar 13, 2018
The changes are debatable, but I'm trying to improve code readability as
stated in the comments to [1].

[1]: tarantool/graphql#58
Khatskevich and others added 4 commits March 14, 2018 00:10
Add goods (item) and order_item relation.
This patch is important for graphql query -> avro schema convertor
implementation, because both executor and convertor walks over query
AST.

Part of #7
Extend query object: add `avro_schema` method, which produces Avro
schema which can be used to verify or flatten any `query_exequte`
result.

Closes #7
The changes are debatable, but I'm trying to improve code readability as
stated in the comments to [1].

[1]: tarantool/graphql#58
@Totktonada Totktonada merged commit 831ead8 into master Mar 13, 2018
@Totktonada Totktonada deleted the kh/to_avro branch March 13, 2018 21:13
Totktonada added a commit that referenced this pull request Mar 13, 2018
This follows up the PR #58 (the work in the scope of the issue #7).
Totktonada added a commit that referenced this pull request Mar 13, 2018
This follows up the PR #58 (the work in the scope of the issue #7).
SudoBobo referenced this pull request Mar 14, 2018
The changes are debatable, but I'm trying to improve code readability as
stated in the comments to [1].

[1]: tarantool/graphql#58
SudoBobo pushed a commit that referenced this pull request Mar 14, 2018
This follows up the PR #58 (the work in the scope of the issue #7).
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants