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

Commit be63f62

Browse files
committed
allow manual timestamps
1 parent b64e041 commit be63f62

File tree

8 files changed

+67
-16
lines changed

8 files changed

+67
-16
lines changed

docs/sdl.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
- [Scalar Types](#scalar-types)
55
- [Example](#example)
66
- [Altering your schema and Migrations](#altering-your-schema-and-migrations)
7-
- [Special cases and scripting migrations](#special-cases-and-scription-migrations)
7+
- [Special cases and scripting migrations](#special-cases-and-scripting-migrations)
88

99
## Type Definitions
1010

@@ -29,12 +29,14 @@ GraphQL Genie supports interfaces and unions! You may want to look into using th
2929
* The directive @connection can be put on a list field to turn it into a type following the [Relay Cursor Connections Specification](https://facebook.github.io/relay/graphql/connections.htm) rather than just returning a normal list.
3030
* **@model**
3131
* By default any object type will be part of the CRUD model, using the @model directive will limit to just types that use this directive
32-
* **@createdTimestamp**
32+
* **@createdTimestamp (allowManual: Boolean = false)**
3333
* The field will be automatically set when the record is created
3434
* Must be of type DateTime
35-
* **@updatedTimestamp**
35+
* If you want to also be able to allow the field to be set manually in mutations set allowManual to true
36+
* **@updatedTimestamp (allowManual: Boolean = false)**
3637
* The field will automatically be updated when the record is updated
3738
* Must be of type DateTime
39+
* If you want to also be able to allow the field to be set manually in mutations set allowManual to true
3840
* **@storeName(value: String!)**
3941
* If you want the actual name of the type in your backend store to be something other than based off the type name. Using this you can effectively rename your type without actually migrating any data
4042
* Interfaces and Unions

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "graphql-genie",
3-
"version": "0.4.9",
3+
"version": "0.4.10",
44
"description": "GraphQL Genie",
55
"browser": "./lib/browser.umd.js",
66
"jsnext:main": "./lib/module.js",
@@ -40,7 +40,7 @@
4040
"lint": "tslint -c tslint.json -p linttsconfig.json --fix",
4141
"lint-no-fix": "tslint -c tslint.json -p linttsconfig.json",
4242
"postpublish": "npm run tag",
43-
"tag": "git tag v`npm v graphql-genie version` && git push origin --tags"
43+
"tag": "git tag -a v`npm v graphql-genie version` && git push origin --tags"
4444
},
4545
"jest": {
4646
"testURL": "http://localhost",

src/FortuneGraph.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ export default class FortuneGraph implements DataResolver {
387387
return this.fortuneTypeNames;
388388
}
389389

390-
private getStoreName = (type, currStoreName: string, currTypeName: string): {storeName: string, typeName: string} => {
390+
private getStoreName = (type, currStoreName: string, currTypeName: string): { storeName: string, typeName: string } => {
391391
let storeName = get(type, 'metadata.storeName', null);
392392
let typeName = type.name;
393393
if (!isEmpty(storeName) && currStoreName && currStoreName !== storeName) {
@@ -442,7 +442,9 @@ export default class FortuneGraph implements DataResolver {
442442
this.addInputHook(name, (context, record) => {
443443
switch (context.request.method) {
444444
case 'create':
445-
record[field.name] = new Date();
445+
if ((isArray && isEmpty(record[field.name])) || !record[field.name]) {
446+
record[field.name] = new Date();
447+
}
446448
return record;
447449
}
448450
});
@@ -452,7 +454,9 @@ export default class FortuneGraph implements DataResolver {
452454
switch (context.request.method) {
453455
case 'update':
454456
if (!('replace' in update)) update.replace = {};
455-
update.replace[field.name] = new Date();
457+
if ((isArray && isEmpty(update.replace[field.name])) || !update.replace[field.name]) {
458+
update.replace[field.name] = new Date();
459+
}
456460
return update;
457461
}
458462
});

src/GenerateMigrations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class GenerateMigrations implements TypeGenerator {
7171
Note when merging list fields by default the array in the provided data will replace the existing data array. If you don't want to do that instead of providing an array you can provide an object with fields for push and pull or set. `
7272
},
7373
defaultTypename: {
74-
type: GraphQLBoolean,
74+
type: GraphQLString,
7575
descriptions: 'Must be provided if every object in data does not have a `__typename` property or ids with the typename encoded'
7676
},
7777
conditions: {

src/GraphQLSchemaBuilder.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,9 @@ export class GraphQLSchemaBuilder {
3636
3737
directive @unique on FIELD_DEFINITION
3838
39-
directive @updatedTimestamp on FIELD_DEFINITION
39+
directive @updatedTimestamp(allowManual: Boolean = false) on FIELD_DEFINITION
4040
41-
directive @createdTimestamp on FIELD_DEFINITION
42-
43-
directive @createdTimestamp on FIELD_DEFINITION
41+
directive @createdTimestamp(allowManual: Boolean = false) on FIELD_DEFINITION
4442
4543
"""
4644
An object with an ID
@@ -408,6 +406,9 @@ class UpdatedTimestampDirective extends SchemaDirectiveVisitor {
408406
const type = field.type;
409407
if (type.name === 'DateTime') {
410408
field['updatedTimestamp'] = true;
409+
if (this.args && this.args.allowManual) {
410+
field['updatedTimestampAllowManual'] = true;
411+
}
411412
}
412413
}
413414
}
@@ -416,6 +417,9 @@ class CreatedTimestampDirective extends SchemaDirectiveVisitor {
416417
const type = field.type;
417418
if (type.name === 'DateTime') {
418419
field.createdTimestamp = true;
420+
if (this.args && this.args.allowManual) {
421+
field['createdTimestampAllowManual'] = true;
422+
}
419423
}
420424
}
421425
}

src/InputGenerator.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ export class InputGenerator {
6161
if (field) {
6262
if (field.name === 'id') {
6363
isAutoField = true;
64-
} else if (get(field, 'metadata.updatedTimestamp') === true) {
64+
} else if (get(field, 'metadata.updatedTimestamp') === true && !get(field, 'metadata.updatedTimestampAllowManual', false) ) {
6565
isAutoField = true;
66-
} else if (get(field, 'metadata.createdTimestamp') === true) {
66+
} else if (get(field, 'metadata.createdTimestamp') === true && !get(field, 'metadata.createdTimestampAllowManual', false)) {
6767
isAutoField = true;
6868
}
6969
}

src/tests/__tests__/mutationTests.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ describe('mutationTests', () => {
8787
});
8888

8989
test('create - create post connect author', async () => {
90+
const date = new Date(1988, 2, 23);
9091
const post = await client.mutate({
9192
mutation: gql`mutation {
9293
createPost(
@@ -100,6 +101,8 @@ describe('mutationTests', () => {
100101
email: "zeus@example.com"
101102
}
102103
}
104+
created: "${date.toISOString()}"
105+
createdManual: "${date.toISOString()}"
103106
}
104107
}
105108
) {
@@ -111,17 +114,23 @@ describe('mutationTests', () => {
111114
author {
112115
email
113116
}
117+
created
118+
createdManual
114119
}
115120
}
116121
}
117122
`
118123
});
124+
console.log('post :', post);
119125
testData.posts.push(post.data.createPost.data);
120126
expect(post.data.createPost.data.title).toBe('Genie is great');
121127
expect(post.data.createPost.data.text).toBe('Look how fast I can create an executable schema');
122128
expect(post.data.createPost.data.tags).toEqual(['genie', 'graphql', 'database']);
123129
expect(post.data.createPost.data.author.email).toBe('zeus@example.com');
124-
130+
const created = new Date(post.data.createPost.data.created);
131+
expect(created > date).toBe(true);
132+
const createdManual = new Date(post.data.createPost.data.createdManual);
133+
expect(createdManual.getTime()).toBe(date.getTime());
125134
});
126135

127136
test('update - push onto tags', async () => {
@@ -258,6 +267,36 @@ describe('mutationTests', () => {
258267

259268
});
260269

270+
test('update - updated set to passed in value', async () => {
271+
const date = new Date(1988, 2, 23);
272+
const post = await client.mutate({
273+
mutation: gql`mutation {
274+
updatePost(
275+
input: {
276+
data: {
277+
updated: "${date.toISOString()}"
278+
updatedManual: "${date.toISOString()}"
279+
}
280+
where: {
281+
id: "${testData.posts[0].id}"
282+
}
283+
}
284+
) {
285+
data {
286+
id
287+
updated
288+
updatedManual
289+
}
290+
}
291+
}
292+
`
293+
});
294+
const updated = new Date(post.data.updatePost.data.updated);
295+
expect(updated > date).toBe(true);
296+
const updatedManual = new Date(post.data.updatePost.data.updatedManual);
297+
expect(updatedManual.getTime()).toBe(date.getTime());
298+
});
299+
261300
test('update - pull from tags', async () => {
262301
const post = await client.mutate({
263302
mutation: gql`mutation {

src/tests/setupTests.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ type Post implements Submission {
2424
published: Boolean @default(value: "true")
2525
created: DateTime @createdTimestamp
2626
updated: DateTime @updatedTimestamp
27+
createdManual: DateTime @createdTimestamp(allowManual: true)
28+
updatedManual: DateTime @updatedTimestamp(allowManual: true)
2729
}
2830
2931
type Comment implements Submission {

0 commit comments

Comments
 (0)