Comments (7)
model.get(["genres",0,0,null]) current outputs "Die Hard". More specifically it outputs:
{ json: { genres: { "0": { "0": { "null": "Die Hard" } } } }
No it doesn't, it outputs:
{ json: { genres: { "0": { "0": "Die Hard" } } }
The current behavior has no valid use-cases. Developers are expected to request JSON when they are trying to create data they intend to show on-screen. Developers should never be displaying paths on screen. This is an anti-pattern, because it encourages developers to make display considerations when designing their path structures.
Here's an example:
<!DOCTYPE>
<html><head>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/rxjs/2.5.1/rx.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/rxjs-jquery/1.1.6/rx.jquery.js"></script>
<script type="text/javascript">
var haml = require("hamljs");
var falcor = require("falcor");
var Model = falcor.Model;
var template = haml.compile("\
%ul.devs \
- for dev in @devs \
%li.dev \
%a(href='#' + dev['more-info'].join('/')) = dev.name \
");
var teamListSelector = function (devs) {
return template({
devs: Object.keys(devs).sort().reduce(function (list, key) {
list.push(devs[key]);
return list;
}, [])
});
};
var employeeInfoTemplate = haml.compile("\
%div.employee-info \
%span.name = @name \
is in %span.building = @building \
on floor %span.floor = @floor
at dest number \
%span.desk = @desk \
");
var model = new Model({ cache: { "netflix": {
"tvui-devs": {
0: { "name": "Steve McGuire", "more-info": { "$type": "ref", ["netflix", "employees", "smcguire"] } },
1: { "name": "Jerry Hamlet", "more-info": { "$type": "ref", ["netflix", "employees", "jhamlet"] } },
2: { "name": "Ian McKay", "more-info": { "$type": "ref", ["netflix", "employees", "imckay"] } },
},
"falcor-devs": {
0: { "name": "Jafar Husain", "more-info": { "$type": "ref", ["netflix", "employees", "jhusain"] } },
1: { "name": "Paul Taylor", "more-info": { "$type": "ref", ["netflix", "employees", "ptaylor"] } },
2: { "name": "Michael Paulson", "more-info": { "$type": "ref", ["netflix", "employees", "mpaulson"] } }
},
"employees": {
"smcguire": { "building": "A", "floor": 3, "desk": 120 },
"jhamlet": { "building": "A", "floor": 3, "desk": 121 },
"imckay": { "building": "A", "floor": 3, "desk": 122 },
"jhusain": { "building": "A", "floor": 3, "desk": 123 },
"ptaylor": { "building": "A", "floor": 3, "desk": 124 },
"mpaulson": { "building": "A", "floor": 3, "desk": 125 }
}}}});
$(".teams a").clickAsObservable().
flatMap(function(e) {
var teamPath = $(e.target).attr("href").substr(1).join("/");
return model.bind(teamPath);
}).
flatMap(function(teamModel) {
return teamModel.get([{ to: 2 }, ["name", "more-info"]], teamListSelector);
}).
flatMap(function(teamHTML) {
$(".employees").replace(teamHTML).find(".dev a").clickAsObservable()
}).
flatMap(function(e) {
var employeePath = $(e.target).attr("href").substr(1).join("/");
return model.bind(employeePath);
}).
flatMap(function(employeeModel) {
return employeeModel.get([["building", "floor", "desk"]], employeeInfoTemplate);
}).
subscribe(function(employeeHTML) {
$(".employee-info").replace(employeeHTML);
});
</script></head><body>
<ul class="teams">
<li><a href="#netflix/tvui-devs">TVUI</a></li>
<li><a href="#netflix/falcor-devs">Falcor</a></li>
</ul>
<ul class="employees"></ul>
<div class="employee-info"></div>
</body></html>
- References are leaf values, and should be treated the same as any other leaf value when requested.
- Most References point to branch nodes, not leaf nodes (as in your example). Since it's illegal to request for branch nodes, the 80% case will be they do want the reference when they request for it.
- JSON is an output format, not a cult. Just because someone wants their data as JSON doesn't mean they're buying into the story of templating.
from falcor.
@jhusain Ill have to agree with @trxcllnt on this one. This seems to be more of an opinion.
Some points to consider.
I am a user, brand new to falcor. so i execute the following query.
model.get('someRefThatPointsToLeaf[0]').then(template.render);
They learn about the selector function. Super cool.
model.get('someRefThatPointsToLeaf[0]', function(x) { return x; }).then(template.render);
BOOM it breaks the template.
The key problem i have with this is that its not an output format problem, its a behavior problem. Falcor will fundamentally act different (not output different) by requesting different output. To me this should be sufficiently confusing.
There are also lots of logistical issues in the code with this change. I feel like we are hyper catering to the rookie. It is fundamental to falcor that you know about the data coming down. You don't have to know the IDs, you have to know the structure. -- Now i am just rambling.
from falcor.
It seems like an invalid request from a public API consumer to ask for "null" in the path.
It seems like we need "null" for internal implementation cases but not for public API. I don't understand the null in JSON responses at all. Why would an end user ever ask for or expect back null? Seems like an invalid request from a public API perspective.
from falcor.
Notes from Falcor meeting:
So we don't need null if its just about reporting, it's when we're taking the reported error message and trying to feed it back into invalidate.
How would the user know that they need to invalidate/remove the error vs. the reference itself?
@trxcllnt says in Falcor meeting:
With errors, sentinels, you would always want to invalidate the nodes in the cache instead of the references, but there are use cases where you want to invalidate references -- when you want to get fresh data from the server.
@michaelbpaulson We should either always hide references or never hide references, but not go halfsies.
Proposal from Falcor meeting (everyone in room is in agreement @trxcllnt, @michaelbpaulson, @sdesai, @ktrott00):
set(path, undefined) -> follows references in leaf position (today, we never follow reference in leaf position)
setReference(path, undefined) -> doesn't follow references in leaf position; allows invalidating a reference
This eliminates null from JSON Graph / paths entirely, which would be fantastic according to @trxcllnt and @michaelbpaulson. Cleans up the API quite a bit.
from falcor.
Falcor meeting (attendees: @jhusain, @sdesai, @michaelbpaulson, @trxcllnt, @ktrott00):
- Agreed that JSON is a behavior change so should treat as a mode not an output format
- Agreed that null is a rare case
- Agreed that null is invalid path in JSON mode
Arguments against:
- No way to get hierarchal w/ leaf references: What if I want a JSON tree but I want the reference for leaf nodes (don't want to follow the reference)
- Should be a more explicit API around following or not following references. There's no need to distinguish between switching between graph or tree as your model.
Counter proposal:
- You build your model w/ and w/o references and use get and set to work with it and have explicit separate getReference and setReference API. Problem with this approach: Batching gets broken by two separate APIs. Can't rely on asynchronity
from falcor.
The alternate proposal is here: #131
The proposal that includes special methods for references does not accommodate current requirements.
The most obvious deficiency is that it does not handle the call case. While get and set can rely on batching to ensure a getRef and get go together In a single request, calls cannot be batched because they are not idempotent. You could do a cal and a callRef because you could repeat side-effects. In other words the proposal above does not allow the retrieval of both refs and ref targets after a call is complete if you eliminate null.
Even if this proposal worked it would still violate one of Falcors previous guarantees: it is always possible to map a method call to an HTTP request. Batching will be common today, but we cant rely on it in the future. As soon as HTTP2 becomes ubiquitous the correct default for Falcor will be to run unbatched. HTTP2 will be much more efficient at batching requests and allow multiplexing of server results. This is why using batching to accomplish mainline scenarios like ensuring a set of data is retrieved in a single connection is ill-advised.
The alternate proposal maintains would introduce two Model modes: asJSON and asJSONGraph. The Model's default mode will be graph. These modes would create new Models, not mutate the existing one.
model.asTree().get("profiles[0..5].name")
In tree mode, all references are followed even if they are in found in the last key of the path. Sets behave the same way they would against a JSON object, replacing the target of a reference instead of the reference itself. This means that in tree mode the model will always emit JSON. In graph mode you can select references with paths, or select their target with a trailing null in the path. The null key will be aliased to a constant (REF_TARGET) for more readability. Note that null will only be necessary in the rare case in which references point to values.
This proposal can be clearly explained to developers using the same narrative we use to justify the JSON Graph language: JSON can't have refs. If you want to use a Graph, you go into Graph mode. If you want a tree, you will never see references.
Now that tree and graph moods are available, the model response output format options can be to just PathValue or Value. We've effectively separated the output format dimension from the behavior of whether the Model behaves like a tree or graph, which is a nice simplification.
Th only downside of this proposal is that references cannot appear in JSON. However if an application requires that refs not be transparent in a tree mode there is a workaround - introduce a key that contains the ref contents. I believe this wil not be a common-use case. If it comes up often, we could address to with a special constant in the last key (Model.REF).
from falcor.
Updated agreement: Leave as is for now and do nothing.
from falcor.
Related Issues (20)
- Less Data consumption, reducing of codes sizes HOT 1
- Go structs HOT 1
- Is Falcor being actively maintained? HOT 11
- Assign to read only property HOT 2
- Cannot read property $type of undefined at pathValueMerge HOT 2
- Need original response on call HOT 1
- Getting MaxRetryExceededError when using `$expires` HOT 1
- Limitations of Falcor HOT 3
- GET url limitation on IE HOT 2
- Returning empty object when getting branch nodes (useful for decoupling deref)
- Data corruption due to source-of-truth mismatch HOT 1
- Typo in doc HOT 2
- Crash in Falcor::ComputeStateObject::apiInit with slang shader on vulkan HOT 1
- .travis.yml: The 'sudo' tag is now deprecated in Travis CI
- Falcor can integrate with mongoose? HOT 1
- Optionally retain request info for cancelled get requests
- readme example throws 500 HOT 2
- decorating model resulting in setCache being undefined HOT 1
- Model#call arguments validation
- Video tutorials are unavailable on the website HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from falcor.