This is much more useful information than the last modified. For example:
- Token A is created. It becomes the last modified.
- Token B is created. It becomes the last modified.
- Token A completes. Mismatch. It becomes the last modified.
- Token B completes. Mismatch. It becomes the last modified.
So in this case, we're unable to use the flag to determine whether we should
ignore the token. But if we instead us the new flag to see what token was
last _created_, the problem is solved.
This should have been obvious the first time around.
* src/server/token/MongoTokenDao.ts (updateToken): Query
`lastState'. Return its value. Update its value.
(getToken): Query lastState. Return its value.
* src/server/token/Token.ts (Token)[last_state]: New field.
* src/server/token/TokenDao.ts (TokenQueryResult, TokenNamespaceResults):
Use type instead of interface.
(TokenStateHistory): New type.
(TokenNamespaceData)[lastState]: New optional field.
(TokenData)[prev_state]: New field.
* src/server/token/TokenStore.ts: Return previous state data for each
method.
* test/server/token/MongoTokenDaoTest.ts: Add last_state.
* test/server/token/TokenStoreTest.ts: Likewise.
This causes the DAO to return the state of the document prior to the
database operation (in the case of a retrieval, the previous state is the
same as the current state). This will allow determining whether other
tokens were modified since a previous request.
* src/server/token/MongoTokenDao.ts: Stop using TokenType in favor of new
TokenState.
(updateToken): Query for and return previous state. Use findAndModify
instead of update.
(getToken): Return previous state. Minor changes to account for new
TokenQueryResult types (null=>undefined).
* src/server/token/Token.ts: Add comments for existing Token{Id,Namespace}
nominal types.
(TokenState): New string enum.
* src/server/token/TokenDao.ts: Import new TokenState.
(TokenDao)[updateToken]: Use it.
(TokenType): Remove.
(TokenQueryResult, TokenNamespaceResults, TokenNamespaceData):
null=>undefined for unavailable value. null was wrong.
(TokenStatus): Token{Type=>State}.
(TokenData)[prev_state, prev_status]: New fields.
* test/server/token/MongoTokenDaoTest.ts: Update tests accordingly.
Since some of these data are generated within TokenDao (e.g. the timestamp),
the caller cannot infer all values.
* src/server/token/MongoTokenDao.ts (updateToken): Return
Promise<{void=>TokenData}>.
* src/server/token/TokenDao.ts (TokenDao)[#updateToken]: Update interface
accordingly.
* test/server/token/MongoTokenDaoTest.ts: Update test accordingly.
Rather than replying with null, which complicates using the returned promise
efficiently, we'll respond with a unique error that allows us to distinguish
between a database failure and a missing token.
These are more traditional errors, but we're moving toward structured
logging, so I want error objects that provide more context. I'll explore
that a bit more in next commit. Unfortunately, the untypedness of Promise
rejections make for a less than desirable situation here. Async/await is
not yet an option since we're still compiling to ES5 (have to support
IE11), and TS compiles async/await into generators for environments that
don't support them, which also are not available in ES5.
* src/server/service/TokenedService.js (_getQuoteToken): Remove null check,
since this situation can no longer occur.
* src/server/token/MongoTokenDao.ts (getToken): Remove null from return type
union; reject with `UnknownTokenError' instead.
* src/server/token/TokenDao.ts: Modify interface accordingly.
* src/server/token/UnknownTokenError.ts: New class.
* test/server/token/MongoTokenDaoTest.ts: Modify tests accordingly. Add
missing test for latest token namespace missing.
TokenDao has been renamed to MongoTokenDao. While it's good for this to
have its own interface anyway, the immediate motivation was for unit tests:
I started playing with mocking with TypeScript and researching some
libraries, but I don't have time to research enough to commit to any of them
at the moment. Interfaces remove the need to mock at all.
This also stops using `export default' in favor of just importing by
name. Using defaults only saves us a few characters, and it makes for
awkward syntax in various cases (e.g. with multiple exports). But I'm still
new to TS, so who knows if I'll be flip-flopping on this decision in the
future. If we kept to our normal 1:1 file:definition convention, it
wouldn't cause problems, but based on the types I've had to define so far,
that'd cause way too much bloat and boilerplate.
* src/server/daemon/controller.js: No long import `default'. Use
`MongoTokenDao'.
* src/server/token/TokenedService.js: Stop checking type (since TS
interfaces do not result in compiler output, easejs cannot validate
against them.)
* src/server/token/MongoTokenDao.ts: Rename from `TokenDao.ts'.
* src/server/token/TokenDao.ts: Rename from `TokenQueryResult.ts'.
(TokenDao): New interface.
* src/server/token/TokenQueryResult.ts: Rename to `TokenDao.ts'.
* test/server/token/MongoTokenDaoTest.ts: Rename from `TokenDaoTest.ts'.