-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: A lot of our tests have to write data into the store before testing some other logic. However, the payloads must be manually constructed using `generateRQLFieldAlias()`. It's not a big deal, but it's annoying. So this PR adds a new module `transformRelayQueryPayload(query: RelayQuery.Node, payload: Payload): Payload` - it accepts payloads where the keys correspond to field names/aliases (which cannot be written into the store as-is), and returns an equivalent payload where keys are renamed to the serialization key of the corresponding field (which *can* be written to the store). See the unit test for this module for an example, and how it (slightly) simplifies tests that write to the store. Closes #341 Reviewed By: @yungsters Differential Revision: D2457487
- Loading branch information
1 parent
03607d4
commit 98035f6
Showing
8 changed files
with
556 additions
and
218 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/** | ||
* Copyright 2013-2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* @providesModule transformRelayQueryPayload | ||
* @flow | ||
* @typechecks | ||
*/ | ||
|
||
'use strict'; | ||
|
||
var RelayQuery = require('RelayQuery'); | ||
var RelayQueryVisitor = require('RelayQueryVisitor'); | ||
|
||
var invariant = require('invariant'); | ||
var mapObject = require('mapObject'); | ||
|
||
type Payload = mixed; | ||
type PayloadState = { | ||
client: Payload, | ||
server: Payload, | ||
}; | ||
|
||
/** | ||
* Transforms "client" payloads with property keys that match the "application" | ||
* names (i.e. property names are schema names or aliases) into "server" | ||
* payloads that match what the server would return for the given query (i.e. | ||
* property names are serialization keys instead). | ||
*/ | ||
function transformRelayQueryPayload( | ||
root: RelayQuery.Root, | ||
clientData: Payload | ||
): Payload { | ||
// Handle both FB & OSS formats for root payloads on plural calls: FB | ||
// returns objects with array values, OSS returns arrays. | ||
if (clientData == null) { | ||
return clientData; | ||
} else if (Array.isArray(clientData)) { | ||
return clientData.map(item => transform(root, item)); | ||
} else { | ||
invariant( | ||
typeof clientData === 'object', | ||
'transformClientPayload(): Expected the root payload for query `%s` ' + | ||
'to be an array or object, got `%s`.', | ||
root.getName(), | ||
clientData | ||
); | ||
return mapObject(clientData, item => { | ||
if (Array.isArray(item)) { | ||
return item.map(innerItem => transform(root, innerItem)); | ||
} | ||
return transform(root, item); | ||
}); | ||
} | ||
} | ||
|
||
function transform( | ||
root: RelayQuery.Root, | ||
clientData: Payload | ||
): Payload { | ||
if (clientData == null) { | ||
return clientData; | ||
} | ||
var transform = new RelayPayloadTransformer(); | ||
var serverData = {}; | ||
transform.visit(root, { | ||
client: clientData, | ||
server: serverData, | ||
}); | ||
return serverData; | ||
} | ||
|
||
class RelayPayloadTransformer extends RelayQueryVisitor<PayloadState> { | ||
visitField( | ||
node: RelayQuery.Field, | ||
state: PayloadState | ||
): ?RelayQuery.Node { | ||
var {client, server} = state; | ||
// `client` represents the *parent* node value and should not be null | ||
// due to checks before traversing child values. | ||
invariant( | ||
typeof client === 'object' && client !== null, | ||
'RelayPayloadTransformer: Expected a client value for field `%s`.', | ||
node.getApplicationName() | ||
); | ||
invariant( | ||
typeof server === 'object' && server !== null, | ||
'RelayPayloadTransformer: Expected a server value for field `%s`.', | ||
node.getApplicationName() | ||
); | ||
var applicationName = node.getApplicationName(); | ||
var serializationKey = node.getSerializationKey(); | ||
var clientData = client[applicationName]; | ||
var serverData = server[serializationKey]; | ||
|
||
if (node.isScalar() || clientData == null) { | ||
server[serializationKey] = clientData; | ||
} else if (Array.isArray(clientData)) { | ||
invariant( | ||
serverData == null || Array.isArray(serverData), | ||
'RelayPayloadTransformer: Got conflicting values for field `%s`: ' + | ||
'expected values to be arrays.', | ||
applicationName | ||
); | ||
if (serverData == null) { | ||
server[serializationKey] = serverData = []; | ||
} | ||
clientData.forEach((clientItem, index) => { | ||
if (clientItem == null) { | ||
serverData[index] = clientItem; | ||
return; | ||
} | ||
var serverItem = serverData && serverData[index]; | ||
if (serverItem == null) { | ||
serverData[index] = serverItem = {}; | ||
} | ||
this.traverse(node, { | ||
client: clientItem, | ||
server: serverItem, | ||
}); | ||
}); | ||
} else { | ||
invariant( | ||
typeof clientData === 'object' && clientData !== null, | ||
'RelayPayloadTransformer: Expected an object value for field `%s`.', | ||
applicationName | ||
); | ||
invariant( | ||
serverData == null || typeof serverData === 'object', | ||
'RelayPayloadTransformer: Got conflicting values for field `%s`: ' + | ||
'expected values to be objects.', | ||
applicationName | ||
); | ||
if (serverData == null) { | ||
server[serializationKey] = serverData = {}; | ||
} | ||
this.traverse(node, { | ||
client: clientData, | ||
server: serverData, | ||
}); | ||
} | ||
} | ||
} | ||
|
||
module.exports = transformRelayQueryPayload; |
Oops, something went wrong.