chore: progress to versions
This commit is contained in:
@@ -35,15 +35,17 @@ export const createVersion: CreateVersion = async function createVersion(
|
||||
const table = this.tables[tableName]
|
||||
const relationshipsTable = this.tables[`${tableName}_relationships`]
|
||||
|
||||
await db.execute(sql`
|
||||
UPDATE ${table}
|
||||
SET latest = false
|
||||
FROM ${relationshipsTable}
|
||||
WHERE ${table.id} = ${relationshipsTable.parent}
|
||||
AND ${relationshipsTable.path} = ${'parent'}
|
||||
AND ${relationshipsTable[`${collectionSlug}ID`]} = ${parent}
|
||||
AND ${table.id} != ${result.id};
|
||||
`)
|
||||
if (collection.versions.drafts) {
|
||||
await db.execute(sql`
|
||||
UPDATE ${table}
|
||||
SET latest = false
|
||||
FROM ${relationshipsTable}
|
||||
WHERE ${table.id} = ${relationshipsTable.parent}
|
||||
AND ${relationshipsTable.path} = ${'parent'}
|
||||
AND ${relationshipsTable[`${collectionSlug}ID`]} = ${parent}
|
||||
AND ${table.id} != ${result.id};
|
||||
`)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -372,8 +372,8 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
case 'date': {
|
||||
let val = fieldData
|
||||
|
||||
if (fieldData instanceof Date) {
|
||||
val = fieldData.toISOString()
|
||||
if (typeof fieldData === 'string') {
|
||||
val = new Date(fieldData).toISOString()
|
||||
}
|
||||
|
||||
if (typeof locale === 'string') {
|
||||
|
||||
@@ -104,11 +104,12 @@ function initCollectionsGraphQL(payload: Payload): void {
|
||||
|
||||
collection.graphQL.paginatedType = buildPaginatedListType(pluralName, collection.graphQL.type)
|
||||
|
||||
collection.graphQL.whereInputType = buildWhereInputType(
|
||||
singularName,
|
||||
whereInputFields,
|
||||
singularName,
|
||||
)
|
||||
collection.graphQL.whereInputType = buildWhereInputType({
|
||||
name: singularName,
|
||||
fields: whereInputFields,
|
||||
parentName: singularName,
|
||||
payload,
|
||||
})
|
||||
|
||||
if (config.auth && !config.auth.disableLocalStrategy) {
|
||||
fields.push({
|
||||
@@ -218,11 +219,12 @@ function initCollectionsGraphQL(payload: Payload): void {
|
||||
}
|
||||
|
||||
if (config.versions) {
|
||||
const versionIDType = payload.db.defaultIDType === 'text' ? GraphQLString : GraphQLInt
|
||||
const versionCollectionFields: Field[] = [
|
||||
...buildVersionCollectionFields(config),
|
||||
{
|
||||
name: 'id',
|
||||
type: 'text',
|
||||
type: payload.db.defaultIDType as 'text',
|
||||
},
|
||||
{
|
||||
name: 'createdAt',
|
||||
@@ -246,7 +248,7 @@ function initCollectionsGraphQL(payload: Payload): void {
|
||||
|
||||
payload.Query.fields[`version${formatName(singularName)}`] = {
|
||||
args: {
|
||||
id: { type: GraphQLString },
|
||||
id: { type: versionIDType },
|
||||
...(payload.config.localization
|
||||
? {
|
||||
fallbackLocale: { type: payload.types.fallbackLocaleInputType },
|
||||
@@ -260,11 +262,12 @@ function initCollectionsGraphQL(payload: Payload): void {
|
||||
payload.Query.fields[`versions${pluralName}`] = {
|
||||
args: {
|
||||
where: {
|
||||
type: buildWhereInputType(
|
||||
`versions${singularName}`,
|
||||
versionCollectionFields,
|
||||
`versions${singularName}`,
|
||||
),
|
||||
type: buildWhereInputType({
|
||||
name: `versions${singularName}`,
|
||||
fields: versionCollectionFields,
|
||||
parentName: `versions${singularName}`,
|
||||
payload,
|
||||
}),
|
||||
},
|
||||
...(payload.config.localization
|
||||
? {
|
||||
@@ -284,7 +287,7 @@ function initCollectionsGraphQL(payload: Payload): void {
|
||||
}
|
||||
payload.Mutation.fields[`restoreVersion${formatName(singularName)}`] = {
|
||||
args: {
|
||||
id: { type: GraphQLString },
|
||||
id: { type: versionIDType },
|
||||
},
|
||||
resolve: restoreVersionResolver(collection),
|
||||
type: collection.graphQL.type,
|
||||
|
||||
@@ -130,11 +130,12 @@ function initGlobalsGraphQL(payload: Payload): void {
|
||||
payload.Query.fields[`versions${formattedName}`] = {
|
||||
args: {
|
||||
where: {
|
||||
type: buildWhereInputType(
|
||||
`versions${formattedName}`,
|
||||
versionGlobalFields,
|
||||
`versions${formattedName}`,
|
||||
),
|
||||
type: buildWhereInputType({
|
||||
name: `versions${formattedName}`,
|
||||
fields: versionGlobalFields,
|
||||
parentName: `versions${formattedName}`,
|
||||
payload,
|
||||
}),
|
||||
},
|
||||
...(payload.config.localization
|
||||
? {
|
||||
|
||||
@@ -571,7 +571,12 @@ function buildObjectType({
|
||||
const whereFields = payload.collections[relationTo].config.fields
|
||||
|
||||
upload.args.where = {
|
||||
type: buildWhereInputType(uploadName, whereFields, uploadName),
|
||||
type: buildWhereInputType({
|
||||
name: uploadName,
|
||||
fields: whereFields,
|
||||
parentName: uploadName,
|
||||
payload,
|
||||
}),
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { GraphQLInputObjectType, GraphQLList } from 'graphql'
|
||||
|
||||
import type { Payload } from '../..'
|
||||
import type { Field, FieldAffectingData } from '../../fields/config/types'
|
||||
|
||||
import {
|
||||
@@ -13,6 +14,13 @@ import formatName from '../utilities/formatName'
|
||||
import fieldToSchemaMap from './fieldToWhereInputSchemaMap'
|
||||
import { withOperators } from './withOperators'
|
||||
|
||||
type Args = {
|
||||
fields: Field[]
|
||||
name: string
|
||||
parentName: string
|
||||
payload: Payload
|
||||
}
|
||||
|
||||
/** This does as the function name suggests. It builds a where GraphQL input type
|
||||
* for all the fields which are passed to the function.
|
||||
* Each field has different operators which may be valid for a where input type.
|
||||
@@ -27,11 +35,12 @@ import { withOperators } from './withOperators'
|
||||
* directly searchable. Instead, we need to build a chained pathname
|
||||
* using dot notation so MongoDB can properly search nested paths.
|
||||
*/
|
||||
const buildWhereInputType = (
|
||||
name: string,
|
||||
fields: Field[],
|
||||
parentName: string,
|
||||
): GraphQLInputObjectType => {
|
||||
const buildWhereInputType = ({
|
||||
name,
|
||||
fields,
|
||||
parentName,
|
||||
payload,
|
||||
}: Args): GraphQLInputObjectType => {
|
||||
// This is the function that builds nested paths for all
|
||||
// field types with nested paths.
|
||||
|
||||
@@ -41,7 +50,10 @@ const buildWhereInputType = (
|
||||
if (fieldAffectsData(field) && field.name === 'id') idField = field
|
||||
|
||||
if (!fieldIsPresentationalOnly(field) && !field.hidden) {
|
||||
const getFieldSchema = fieldToSchemaMap(parentName)[field.type]
|
||||
const getFieldSchema = fieldToSchemaMap({
|
||||
parentName,
|
||||
payload,
|
||||
})[field.type]
|
||||
|
||||
if (getFieldSchema) {
|
||||
const fieldSchema = getFieldSchema(field)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { GraphQLEnumType, GraphQLInputObjectType, GraphQLString } from 'graphql'
|
||||
import GraphQLJSON from 'graphql-type-json'
|
||||
|
||||
import type { Payload } from '../..'
|
||||
import type {
|
||||
ArrayField,
|
||||
CheckboxField,
|
||||
@@ -22,14 +24,25 @@ import type {
|
||||
UploadField,
|
||||
} from '../../fields/config/types'
|
||||
|
||||
import { fieldAffectsData, fieldHasSubFields } from '../../fields/config/types'
|
||||
import combineParentName from '../utilities/combineParentName'
|
||||
import formatName from '../utilities/formatName'
|
||||
import recursivelyBuildNestedPaths from './recursivelyBuildNestedPaths'
|
||||
import { withOperators } from './withOperators'
|
||||
|
||||
const fieldToSchemaMap = (parentName: string, nestedFieldName?: string): any => ({
|
||||
array: (field: ArrayField) => recursivelyBuildNestedPaths(parentName, nestedFieldName, field),
|
||||
type Args = {
|
||||
nestedFieldName?: string
|
||||
parentName: string
|
||||
payload: Payload
|
||||
}
|
||||
|
||||
const fieldToSchemaMap = ({ nestedFieldName, parentName, payload }: Args): any => ({
|
||||
array: (field: ArrayField) =>
|
||||
recursivelyBuildNestedPaths({
|
||||
field,
|
||||
nestedFieldName2: nestedFieldName,
|
||||
parentName,
|
||||
payload,
|
||||
}),
|
||||
checkbox: (field: CheckboxField) => ({
|
||||
type: withOperators(field, parentName),
|
||||
}),
|
||||
@@ -37,14 +50,25 @@ const fieldToSchemaMap = (parentName: string, nestedFieldName?: string): any =>
|
||||
type: withOperators(field, parentName),
|
||||
}),
|
||||
collapsible: (field: CollapsibleField) =>
|
||||
recursivelyBuildNestedPaths(parentName, nestedFieldName, field),
|
||||
recursivelyBuildNestedPaths({
|
||||
field,
|
||||
nestedFieldName2: nestedFieldName,
|
||||
parentName,
|
||||
payload,
|
||||
}),
|
||||
date: (field: DateField) => ({
|
||||
type: withOperators(field, parentName),
|
||||
}),
|
||||
email: (field: EmailField) => ({
|
||||
type: withOperators(field, parentName),
|
||||
}),
|
||||
group: (field: GroupField) => recursivelyBuildNestedPaths(parentName, nestedFieldName, field),
|
||||
group: (field: GroupField) =>
|
||||
recursivelyBuildNestedPaths({
|
||||
field,
|
||||
nestedFieldName2: nestedFieldName,
|
||||
parentName,
|
||||
payload,
|
||||
}),
|
||||
json: (field: JSONField) => ({
|
||||
type: withOperators(field, parentName),
|
||||
}),
|
||||
@@ -77,7 +101,7 @@ const fieldToSchemaMap = (parentName: string, nestedFieldName?: string): any =>
|
||||
),
|
||||
}),
|
||||
},
|
||||
value: { type: GraphQLString },
|
||||
value: { type: GraphQLJSON },
|
||||
},
|
||||
}),
|
||||
}
|
||||
@@ -90,11 +114,23 @@ const fieldToSchemaMap = (parentName: string, nestedFieldName?: string): any =>
|
||||
richText: (field: RichTextField) => ({
|
||||
type: withOperators(field, parentName),
|
||||
}),
|
||||
row: (field: RowField) => recursivelyBuildNestedPaths(parentName, nestedFieldName, field),
|
||||
row: (field: RowField) =>
|
||||
recursivelyBuildNestedPaths({
|
||||
field,
|
||||
nestedFieldName2: nestedFieldName,
|
||||
parentName,
|
||||
payload,
|
||||
}),
|
||||
select: (field: SelectField) => ({
|
||||
type: withOperators(field, parentName),
|
||||
}),
|
||||
tabs: (field: TabsField) => recursivelyBuildNestedPaths(parentName, nestedFieldName, field),
|
||||
tabs: (field: TabsField) =>
|
||||
recursivelyBuildNestedPaths({
|
||||
field,
|
||||
nestedFieldName2: nestedFieldName,
|
||||
parentName,
|
||||
payload,
|
||||
}),
|
||||
text: (field: TextField) => ({
|
||||
type: withOperators(field, parentName),
|
||||
}),
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import type { Payload } from '../..'
|
||||
import type { FieldWithSubFields, TabsField } from '../../fields/config/types'
|
||||
|
||||
import { fieldAffectsData, fieldIsPresentationalOnly } from '../../fields/config/types'
|
||||
import fieldToSchemaMap from './fieldToWhereInputSchemaMap'
|
||||
|
||||
const recursivelyBuildNestedPaths = (
|
||||
parentName: string,
|
||||
nestedFieldName2: string,
|
||||
field: FieldWithSubFields | TabsField,
|
||||
) => {
|
||||
type Args = {
|
||||
field: FieldWithSubFields | TabsField
|
||||
nestedFieldName2: string
|
||||
parentName: string
|
||||
payload: Payload
|
||||
}
|
||||
|
||||
const recursivelyBuildNestedPaths = ({ field, nestedFieldName2, parentName, payload }: Args) => {
|
||||
const fieldName = fieldAffectsData(field) ? field.name : undefined
|
||||
const nestedFieldName = fieldName || nestedFieldName2
|
||||
|
||||
@@ -16,9 +20,14 @@ const recursivelyBuildNestedPaths = (
|
||||
// otherwise, treat it as a row
|
||||
return field.tabs.reduce((tabSchema, tab: any) => {
|
||||
tabSchema.push(
|
||||
...recursivelyBuildNestedPaths(parentName, nestedFieldName, {
|
||||
...tab,
|
||||
type: 'name' in tab ? 'group' : 'row',
|
||||
...recursivelyBuildNestedPaths({
|
||||
field: {
|
||||
...tab,
|
||||
type: 'name' in tab ? 'group' : 'row',
|
||||
},
|
||||
nestedFieldName2: nestedFieldName,
|
||||
parentName,
|
||||
payload,
|
||||
}),
|
||||
)
|
||||
return tabSchema
|
||||
@@ -30,14 +39,23 @@ const recursivelyBuildNestedPaths = (
|
||||
if (!fieldAffectsData(nestedField)) {
|
||||
return [
|
||||
...nestedFields,
|
||||
...recursivelyBuildNestedPaths(parentName, nestedFieldName, nestedField),
|
||||
...recursivelyBuildNestedPaths({
|
||||
field: nestedField,
|
||||
nestedFieldName2: nestedFieldName,
|
||||
parentName,
|
||||
payload,
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
const nestedPathName = fieldAffectsData(nestedField)
|
||||
? `${nestedFieldName ? `${nestedFieldName}__` : ''}${nestedField.name}`
|
||||
: undefined
|
||||
const getFieldSchema = fieldToSchemaMap(parentName, nestedFieldName)[nestedField.type]
|
||||
const getFieldSchema = fieldToSchemaMap({
|
||||
nestedFieldName,
|
||||
parentName,
|
||||
payload,
|
||||
})[nestedField.type]
|
||||
|
||||
if (getFieldSchema) {
|
||||
const fieldSchema = getFieldSchema({
|
||||
|
||||
@@ -178,7 +178,7 @@ const defaults: DefaultsType = {
|
||||
operators: [
|
||||
...[...operators.equality, ...operators.contains].map((operator) => ({
|
||||
name: operator,
|
||||
type: GraphQLString,
|
||||
type: GraphQLJSON,
|
||||
})),
|
||||
],
|
||||
},
|
||||
|
||||
@@ -601,7 +601,8 @@ describe('Versions', () => {
|
||||
const response = await graphQLClient.request(query)
|
||||
|
||||
const data = response.createAutosavePost
|
||||
collectionGraphQLPostID = data.id
|
||||
|
||||
collectionGraphQLPostID = payload.db.defaultIDType === 'number' ? data.id : `"${data.id}"`
|
||||
})
|
||||
describe('Create', () => {
|
||||
it('should allow a new doc to be created with draft status', async () => {
|
||||
@@ -633,7 +634,7 @@ describe('Versions', () => {
|
||||
// modify the post to create a new version
|
||||
// language=graphQL
|
||||
const update = `mutation {
|
||||
updateAutosavePost(id: "${collectionGraphQLPostID}", data: {title: "${updatedTitle2}"}) {
|
||||
updateAutosavePost(id: ${collectionGraphQLPostID}, data: {title: "${updatedTitle2}"}) {
|
||||
title
|
||||
updatedAt
|
||||
createdAt
|
||||
@@ -643,7 +644,7 @@ describe('Versions', () => {
|
||||
|
||||
// language=graphQL
|
||||
const query = `query {
|
||||
versionsAutosavePosts(where: { parent: { equals: "${collectionGraphQLPostID}" } }) {
|
||||
versionsAutosavePosts(where: { parent: { equals: ${collectionGraphQLPostID} } }) {
|
||||
docs {
|
||||
id
|
||||
}
|
||||
@@ -652,12 +653,15 @@ describe('Versions', () => {
|
||||
|
||||
const response = await graphQLClient.request(query)
|
||||
|
||||
collectionGraphQLVersionID = response.versionsAutosavePosts.docs[0].id
|
||||
collectionGraphQLVersionID =
|
||||
payload.db.defaultIDType === 'number'
|
||||
? response.versionsAutosavePosts.docs[0].id
|
||||
: `"${response.versionsAutosavePosts.docs[0].id}"`
|
||||
})
|
||||
|
||||
it('should allow read of versions by version id', async () => {
|
||||
const query = `query {
|
||||
versionAutosavePost(id: "${collectionGraphQLVersionID}") {
|
||||
versionAutosavePost(id: ${collectionGraphQLVersionID}) {
|
||||
id
|
||||
parent {
|
||||
id
|
||||
@@ -709,7 +713,7 @@ describe('Versions', () => {
|
||||
// modify the post to create a new version
|
||||
// language=graphQL
|
||||
const update = `mutation {
|
||||
updateAutosavePost(id: "${collectionGraphQLPostID}", data: {title: "${collectionGraphQLOriginalTitle}"}) {
|
||||
updateAutosavePost(id: ${collectionGraphQLPostID}, data: {title: "${collectionGraphQLOriginalTitle}"}) {
|
||||
title
|
||||
updatedAt
|
||||
createdAt
|
||||
@@ -719,7 +723,7 @@ describe('Versions', () => {
|
||||
|
||||
// language=graphQL
|
||||
const query = `query {
|
||||
versionsAutosavePosts(where: { parent: { equals: "${collectionGraphQLPostID}" } }) {
|
||||
versionsAutosavePosts(where: { parent: { equals: ${collectionGraphQLPostID} } }) {
|
||||
docs {
|
||||
id
|
||||
}
|
||||
@@ -728,12 +732,15 @@ describe('Versions', () => {
|
||||
|
||||
const response = await graphQLClient.request(query)
|
||||
|
||||
collectionGraphQLVersionID = response.versionsAutosavePosts.docs[0].id
|
||||
collectionGraphQLVersionID =
|
||||
payload.db.defaultIDType === 'number'
|
||||
? response.versionsAutosavePosts.docs[0].id
|
||||
: `"${response.versionsAutosavePosts.docs[0].id}"`
|
||||
})
|
||||
it('should allow a version to be restored', async () => {
|
||||
// Update it
|
||||
const update = `mutation {
|
||||
updateAutosavePost(id: "${collectionGraphQLPostID}", data: {title: "${'Wrong title'}"}) {
|
||||
updateAutosavePost(id: ${collectionGraphQLPostID}, data: {title: "${'Wrong title'}"}) {
|
||||
title
|
||||
updatedAt
|
||||
createdAt
|
||||
@@ -743,7 +750,7 @@ describe('Versions', () => {
|
||||
|
||||
// restore a versionsPost
|
||||
const restore = `mutation {
|
||||
restoreVersionAutosavePost(id: "${collectionGraphQLVersionID}") {
|
||||
restoreVersionAutosavePost(id: ${collectionGraphQLVersionID}) {
|
||||
title
|
||||
}
|
||||
}`
|
||||
@@ -751,7 +758,7 @@ describe('Versions', () => {
|
||||
await graphQLClient.request(restore)
|
||||
|
||||
const query = `query {
|
||||
AutosavePost(id: "${collectionGraphQLPostID}") {
|
||||
AutosavePost(id: ${collectionGraphQLPostID}) {
|
||||
title
|
||||
}
|
||||
}`
|
||||
@@ -995,13 +1002,16 @@ describe('Versions', () => {
|
||||
|
||||
const response = await graphQLClient.request(query)
|
||||
|
||||
globalGraphQLVersionID = response.versionsAutosaveGlobal.docs[0].id
|
||||
globalGraphQLVersionID =
|
||||
payload.db.defaultIDType === 'number'
|
||||
? response.versionsAutosaveGlobal.docs[0].id
|
||||
: `"${response.versionsAutosaveGlobal.docs[0].id}"`
|
||||
})
|
||||
describe('Read', () => {
|
||||
it('should allow read of versions by version id', async () => {
|
||||
// language=graphql
|
||||
const query = `query {
|
||||
versionAutosaveGlobal(id: "${globalGraphQLVersionID}") {
|
||||
versionAutosaveGlobal(id: ${globalGraphQLVersionID}) {
|
||||
id
|
||||
version {
|
||||
title
|
||||
@@ -1044,7 +1054,7 @@ describe('Versions', () => {
|
||||
it('should allow a version to be restored', async () => {
|
||||
// language=graphql
|
||||
const restore = `mutation {
|
||||
restoreVersionAutosaveGlobal(id: "${globalGraphQLVersionID}") {
|
||||
restoreVersionAutosaveGlobal(id: ${globalGraphQLVersionID}) {
|
||||
title
|
||||
}
|
||||
}`
|
||||
|
||||
Reference in New Issue
Block a user