feat: hasMany property for text fields (#4605)
* fix for supporting hasMany property in text field * Updated docs * handle text case types for schema and graphql schema * fix unit test for required failing * add unit test for has many text field * add end to end test for has many on text field creation * support has many feature for text field on postgres --------- Co-authored-by: Chris Heinz <chrisi.heinz@web.de>
This commit is contained in:
@@ -33,6 +33,16 @@ export const buildFindManyArgs = ({
|
||||
},
|
||||
}
|
||||
|
||||
if (adapter.tables[`${tableName}_texts`]) {
|
||||
result.with._texts = {
|
||||
columns: {
|
||||
id: false,
|
||||
parent: false,
|
||||
},
|
||||
orderBy: ({ order }, { asc: ASC }) => [ASC(order)],
|
||||
}
|
||||
}
|
||||
|
||||
if (adapter.tables[`${tableName}_numbers`]) {
|
||||
result.with._numbers = {
|
||||
columns: {
|
||||
|
||||
@@ -24,6 +24,7 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
||||
|
||||
buildTable({
|
||||
adapter: this,
|
||||
buildTexts: true,
|
||||
buildNumbers: true,
|
||||
buildRelationships: true,
|
||||
disableNotNull: !!collection?.versions?.drafts,
|
||||
@@ -41,6 +42,7 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
||||
|
||||
buildTable({
|
||||
adapter: this,
|
||||
buildTexts: true,
|
||||
buildNumbers: true,
|
||||
buildRelationships: true,
|
||||
disableNotNull: !!collection.versions?.drafts,
|
||||
@@ -57,6 +59,7 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
||||
|
||||
buildTable({
|
||||
adapter: this,
|
||||
buildTexts: true,
|
||||
buildNumbers: true,
|
||||
buildRelationships: true,
|
||||
disableNotNull: !!global?.versions?.drafts,
|
||||
@@ -72,6 +75,7 @@ export const init: Init = async function init(this: PostgresAdapter) {
|
||||
|
||||
buildTable({
|
||||
adapter: this,
|
||||
buildTexts: true,
|
||||
buildNumbers: true,
|
||||
buildRelationships: true,
|
||||
disableNotNull: !!global.versions?.drafts,
|
||||
|
||||
@@ -27,6 +27,7 @@ type Args = {
|
||||
adapter: PostgresAdapter
|
||||
baseColumns?: Record<string, PgColumnBuilder>
|
||||
baseExtraConfig?: Record<string, (cols: GenericColumns) => IndexBuilder | UniqueConstraintBuilder>
|
||||
buildTexts?: boolean
|
||||
buildNumbers?: boolean
|
||||
buildRelationships?: boolean
|
||||
disableNotNull: boolean
|
||||
@@ -41,6 +42,7 @@ type Args = {
|
||||
}
|
||||
|
||||
type Result = {
|
||||
hasManyTextField: 'index' | boolean
|
||||
hasManyNumberField: 'index' | boolean
|
||||
relationsToBuild: Map<string, string>
|
||||
}
|
||||
@@ -49,6 +51,7 @@ export const buildTable = ({
|
||||
adapter,
|
||||
baseColumns = {},
|
||||
baseExtraConfig = {},
|
||||
buildTexts,
|
||||
buildNumbers,
|
||||
buildRelationships,
|
||||
disableNotNull,
|
||||
@@ -67,12 +70,15 @@ export const buildTable = ({
|
||||
|
||||
let hasLocalizedField = false
|
||||
let hasLocalizedRelationshipField = false
|
||||
let hasManyTextField: 'index' | boolean = false
|
||||
let hasManyNumberField: 'index' | boolean = false
|
||||
let hasLocalizedManyTextField = false
|
||||
let hasLocalizedManyNumberField = false
|
||||
|
||||
const localesColumns: Record<string, PgColumnBuilder> = {}
|
||||
const localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder> = {}
|
||||
let localesTable: GenericTable
|
||||
let textsTable: GenericTable
|
||||
let numbersTable: GenericTable
|
||||
|
||||
// Relationships to the base collection
|
||||
@@ -94,11 +100,14 @@ export const buildTable = ({
|
||||
columns.id = idColTypeMap[idColType]('id').primaryKey()
|
||||
;({
|
||||
hasLocalizedField,
|
||||
hasLocalizedManyTextField,
|
||||
hasLocalizedManyNumberField,
|
||||
hasLocalizedRelationshipField,
|
||||
hasManyTextField,
|
||||
hasManyNumberField,
|
||||
} = traverseFields({
|
||||
adapter,
|
||||
buildTexts,
|
||||
buildNumbers,
|
||||
buildRelationships,
|
||||
columns,
|
||||
@@ -183,6 +192,50 @@ export const buildTable = ({
|
||||
adapter.relations[`relations_${localeTableName}`] = localesTableRelations
|
||||
}
|
||||
|
||||
if (hasManyTextField && buildTexts) {
|
||||
const textsTableName = `${rootTableName}_texts`
|
||||
const columns: Record<string, PgColumnBuilder> = {
|
||||
id: serial('id').primaryKey(),
|
||||
text: varchar('text'),
|
||||
order: integer('order').notNull(),
|
||||
parent: parentIDColumnMap[idColType]('parent_id')
|
||||
.references(() => table.id, { onDelete: 'cascade' })
|
||||
.notNull(),
|
||||
path: varchar('path').notNull(),
|
||||
}
|
||||
|
||||
if (hasLocalizedManyTextField) {
|
||||
columns.locale = adapter.enums.enum__locales('locale')
|
||||
}
|
||||
|
||||
textsTable = pgTable(textsTableName, columns, (cols) => {
|
||||
const indexes: Record<string, IndexBuilder> = {
|
||||
orderParentIdx: index('order_parent_idx').on(cols.order, cols.parent),
|
||||
}
|
||||
|
||||
if (hasManyTextField === 'index') {
|
||||
indexes.text_idx = index('text_idx').on(cols.text)
|
||||
}
|
||||
|
||||
if (hasLocalizedManyTextField) {
|
||||
indexes.localeParent = index('locale_parent').on(cols.locale, cols.parent)
|
||||
}
|
||||
|
||||
return indexes
|
||||
})
|
||||
|
||||
adapter.tables[textsTableName] = textsTable
|
||||
|
||||
const textsTableRelations = relations(textsTable, ({ one }) => ({
|
||||
parent: one(table, {
|
||||
fields: [textsTable.parent],
|
||||
references: [table.id],
|
||||
}),
|
||||
}))
|
||||
|
||||
adapter.relations[`relations_${textsTableName}`] = textsTableRelations
|
||||
}
|
||||
|
||||
if (hasManyNumberField && buildNumbers) {
|
||||
const numbersTableName = `${rootTableName}_numbers`
|
||||
const columns: Record<string, PgColumnBuilder> = {
|
||||
@@ -310,6 +363,9 @@ export const buildTable = ({
|
||||
result._locales = many(localesTable)
|
||||
}
|
||||
|
||||
if (hasManyTextField) {
|
||||
result._texts = many(textsTable)
|
||||
}
|
||||
if (hasManyNumberField) {
|
||||
result._numbers = many(numbersTable)
|
||||
}
|
||||
@@ -325,5 +381,5 @@ export const buildTable = ({
|
||||
|
||||
adapter.relations[`relations_${tableName}`] = tableRelations
|
||||
|
||||
return { hasManyNumberField, relationsToBuild }
|
||||
return { hasManyTextField, hasManyNumberField, relationsToBuild }
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import { validateExistingBlockIsIdentical } from './validateExistingBlockIsIdent
|
||||
|
||||
type Args = {
|
||||
adapter: PostgresAdapter
|
||||
buildTexts: boolean
|
||||
buildNumbers: boolean
|
||||
buildRelationships: boolean
|
||||
columnPrefix?: string
|
||||
@@ -55,13 +56,16 @@ type Args = {
|
||||
|
||||
type Result = {
|
||||
hasLocalizedField: boolean
|
||||
hasLocalizedManyTextField: boolean
|
||||
hasLocalizedManyNumberField: boolean
|
||||
hasLocalizedRelationshipField: boolean
|
||||
hasManyTextField: 'index' | boolean
|
||||
hasManyNumberField: 'index' | boolean
|
||||
}
|
||||
|
||||
export const traverseFields = ({
|
||||
adapter,
|
||||
buildTexts,
|
||||
buildNumbers,
|
||||
buildRelationships,
|
||||
columnPrefix,
|
||||
@@ -84,6 +88,8 @@ export const traverseFields = ({
|
||||
}: Args): Result => {
|
||||
let hasLocalizedField = false
|
||||
let hasLocalizedRelationshipField = false
|
||||
let hasManyTextField: 'index' | boolean = false
|
||||
let hasLocalizedManyTextField = false
|
||||
let hasManyNumberField: 'index' | boolean = false
|
||||
let hasLocalizedManyNumberField = false
|
||||
|
||||
@@ -135,7 +141,28 @@ export const traverseFields = ({
|
||||
}
|
||||
|
||||
switch (field.type) {
|
||||
case 'text':
|
||||
case 'text': {
|
||||
if (field.hasMany) {
|
||||
if (field.localized) {
|
||||
hasLocalizedManyTextField = true
|
||||
}
|
||||
|
||||
if (field.index) {
|
||||
hasManyTextField = 'index'
|
||||
} else if (!hasManyTextField) {
|
||||
hasManyTextField = true
|
||||
}
|
||||
|
||||
if (field.unique) {
|
||||
throw new InvalidConfiguration(
|
||||
'Unique is not supported in Postgres for hasMany text fields.',
|
||||
)
|
||||
}
|
||||
} else {
|
||||
targetTable[fieldName] = varchar(columnName)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'email':
|
||||
case 'code':
|
||||
case 'textarea': {
|
||||
@@ -286,21 +313,28 @@ export const traverseFields = ({
|
||||
baseExtraConfig._localeIdx = (cols) => index('_locale_idx').on(cols._locale)
|
||||
}
|
||||
|
||||
const { hasManyNumberField: subHasManyNumberField, relationsToBuild: subRelationsToBuild } =
|
||||
buildTable({
|
||||
adapter,
|
||||
baseColumns,
|
||||
baseExtraConfig,
|
||||
disableNotNull: disableNotNullFromHere,
|
||||
disableUnique,
|
||||
fields: disableUnique ? idToUUID(field.fields) : field.fields,
|
||||
rootRelationsToBuild,
|
||||
rootRelationships: relationships,
|
||||
rootTableIDColType,
|
||||
rootTableName,
|
||||
tableName: arrayTableName,
|
||||
})
|
||||
const {
|
||||
hasManyTextField: subHasManyTextField,
|
||||
hasManyNumberField: subHasManyNumberField,
|
||||
relationsToBuild: subRelationsToBuild,
|
||||
} = buildTable({
|
||||
adapter,
|
||||
baseColumns,
|
||||
baseExtraConfig,
|
||||
disableNotNull: disableNotNullFromHere,
|
||||
disableUnique,
|
||||
fields: disableUnique ? idToUUID(field.fields) : field.fields,
|
||||
rootRelationsToBuild,
|
||||
rootRelationships: relationships,
|
||||
rootTableIDColType,
|
||||
rootTableName,
|
||||
tableName: arrayTableName,
|
||||
})
|
||||
|
||||
if (subHasManyTextField) {
|
||||
if (!hasManyTextField || subHasManyTextField === 'index')
|
||||
hasManyTextField = subHasManyTextField
|
||||
}
|
||||
if (subHasManyNumberField) {
|
||||
if (!hasManyNumberField || subHasManyNumberField === 'index')
|
||||
hasManyNumberField = subHasManyNumberField
|
||||
@@ -361,6 +395,7 @@ export const traverseFields = ({
|
||||
}
|
||||
|
||||
const {
|
||||
hasManyTextField: subHasManyTextField,
|
||||
hasManyNumberField: subHasManyNumberField,
|
||||
relationsToBuild: subRelationsToBuild,
|
||||
} = buildTable({
|
||||
@@ -377,6 +412,11 @@ export const traverseFields = ({
|
||||
tableName: blockTableName,
|
||||
})
|
||||
|
||||
if (subHasManyTextField) {
|
||||
if (!hasManyTextField || subHasManyTextField === 'index')
|
||||
hasManyTextField = subHasManyTextField
|
||||
}
|
||||
|
||||
if (subHasManyNumberField) {
|
||||
if (!hasManyNumberField || subHasManyNumberField === 'index')
|
||||
hasManyNumberField = subHasManyNumberField
|
||||
@@ -425,11 +465,14 @@ export const traverseFields = ({
|
||||
if (!('name' in field)) {
|
||||
const {
|
||||
hasLocalizedField: groupHasLocalizedField,
|
||||
hasLocalizedManyTextField: groupHasLocalizedManyTextField,
|
||||
hasLocalizedManyNumberField: groupHasLocalizedManyNumberField,
|
||||
hasLocalizedRelationshipField: groupHasLocalizedRelationshipField,
|
||||
hasManyTextField: groupHasManyTextField,
|
||||
hasManyNumberField: groupHasManyNumberField,
|
||||
} = traverseFields({
|
||||
adapter,
|
||||
buildTexts,
|
||||
buildNumbers,
|
||||
buildRelationships,
|
||||
columnPrefix,
|
||||
@@ -453,6 +496,8 @@ export const traverseFields = ({
|
||||
|
||||
if (groupHasLocalizedField) hasLocalizedField = true
|
||||
if (groupHasLocalizedRelationshipField) hasLocalizedRelationshipField = true
|
||||
if (groupHasManyTextField) hasManyTextField = true
|
||||
if (groupHasLocalizedManyTextField) hasLocalizedManyTextField = true
|
||||
if (groupHasManyNumberField) hasManyNumberField = true
|
||||
if (groupHasLocalizedManyNumberField) hasLocalizedManyNumberField = true
|
||||
break
|
||||
@@ -462,11 +507,14 @@ export const traverseFields = ({
|
||||
|
||||
const {
|
||||
hasLocalizedField: groupHasLocalizedField,
|
||||
hasLocalizedManyTextField: groupHasLocalizedManyTextField,
|
||||
hasLocalizedManyNumberField: groupHasLocalizedManyNumberField,
|
||||
hasLocalizedRelationshipField: groupHasLocalizedRelationshipField,
|
||||
hasManyTextField: groupHasManyTextField,
|
||||
hasManyNumberField: groupHasManyNumberField,
|
||||
} = traverseFields({
|
||||
adapter,
|
||||
buildTexts,
|
||||
buildNumbers,
|
||||
buildRelationships,
|
||||
columnPrefix: `${columnName}_`,
|
||||
@@ -490,6 +538,8 @@ export const traverseFields = ({
|
||||
|
||||
if (groupHasLocalizedField) hasLocalizedField = true
|
||||
if (groupHasLocalizedRelationshipField) hasLocalizedRelationshipField = true
|
||||
if (groupHasManyTextField) hasManyTextField = true
|
||||
if (groupHasLocalizedManyTextField) hasLocalizedManyTextField = true
|
||||
if (groupHasManyNumberField) hasManyNumberField = true
|
||||
if (groupHasLocalizedManyNumberField) hasLocalizedManyNumberField = true
|
||||
break
|
||||
@@ -500,11 +550,14 @@ export const traverseFields = ({
|
||||
|
||||
const {
|
||||
hasLocalizedField: tabHasLocalizedField,
|
||||
hasLocalizedManyTextField: tabHasLocalizedManyTextField,
|
||||
hasLocalizedManyNumberField: tabHasLocalizedManyNumberField,
|
||||
hasLocalizedRelationshipField: tabHasLocalizedRelationshipField,
|
||||
hasManyTextField: tabHasManyTextField,
|
||||
hasManyNumberField: tabHasManyNumberField,
|
||||
} = traverseFields({
|
||||
adapter,
|
||||
buildTexts,
|
||||
buildNumbers,
|
||||
buildRelationships,
|
||||
columnPrefix,
|
||||
@@ -528,9 +581,10 @@ export const traverseFields = ({
|
||||
|
||||
if (tabHasLocalizedField) hasLocalizedField = true
|
||||
if (tabHasLocalizedRelationshipField) hasLocalizedRelationshipField = true
|
||||
if (tabHasManyTextField) hasManyTextField = true
|
||||
if (tabHasLocalizedManyTextField) hasLocalizedManyTextField = true
|
||||
if (tabHasManyNumberField) hasManyNumberField = true
|
||||
if (tabHasLocalizedManyNumberField) hasLocalizedManyNumberField = true
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
@@ -539,11 +593,14 @@ export const traverseFields = ({
|
||||
const disableNotNullFromHere = Boolean(field.admin?.condition) || disableNotNull
|
||||
const {
|
||||
hasLocalizedField: rowHasLocalizedField,
|
||||
hasLocalizedManyTextField: rowHasLocalizedManyTextField,
|
||||
hasLocalizedManyNumberField: rowHasLocalizedManyNumberField,
|
||||
hasLocalizedRelationshipField: rowHasLocalizedRelationshipField,
|
||||
hasManyTextField: rowHasManyTextField,
|
||||
hasManyNumberField: rowHasManyNumberField,
|
||||
} = traverseFields({
|
||||
adapter,
|
||||
buildTexts,
|
||||
buildNumbers,
|
||||
buildRelationships,
|
||||
columnPrefix,
|
||||
@@ -567,6 +624,8 @@ export const traverseFields = ({
|
||||
|
||||
if (rowHasLocalizedField) hasLocalizedField = true
|
||||
if (rowHasLocalizedRelationshipField) hasLocalizedRelationshipField = true
|
||||
if (rowHasManyTextField) hasManyTextField = true
|
||||
if (rowHasLocalizedManyTextField) hasLocalizedManyTextField = true
|
||||
if (rowHasManyNumberField) hasManyNumberField = true
|
||||
if (rowHasLocalizedManyNumberField) hasLocalizedManyNumberField = true
|
||||
break
|
||||
@@ -604,8 +663,10 @@ export const traverseFields = ({
|
||||
|
||||
return {
|
||||
hasLocalizedField,
|
||||
hasLocalizedManyTextField,
|
||||
hasLocalizedManyNumberField,
|
||||
hasLocalizedRelationshipField,
|
||||
hasManyTextField,
|
||||
hasManyNumberField,
|
||||
}
|
||||
}
|
||||
|
||||
19
packages/db-postgres/src/transform/read/hasManyText.ts
Normal file
19
packages/db-postgres/src/transform/read/hasManyText.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { TextField } from 'payload/types'
|
||||
|
||||
type Args = {
|
||||
field: TextField
|
||||
locale?: string
|
||||
textRows: Record<string, unknown>[]
|
||||
ref: Record<string, unknown>
|
||||
}
|
||||
|
||||
export const transformHasManyText = ({ field, locale, textRows, ref }: Args) => {
|
||||
const result = textRows.map(({ text }) => text)
|
||||
|
||||
if (locale) {
|
||||
ref[field.name][locale] = result
|
||||
} else {
|
||||
ref[field.name] = result
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ type TransformArgs = {
|
||||
// into the shape Payload expects based on field schema
|
||||
export const transform = <T extends TypeWithID>({ config, data, fields }: TransformArgs): T => {
|
||||
let relationships: Record<string, Record<string, unknown>[]> = {}
|
||||
let texts: Record<string, Record<string, unknown>[]> = {}
|
||||
let numbers: Record<string, Record<string, unknown>[]> = {}
|
||||
|
||||
if ('_rels' in data) {
|
||||
@@ -25,6 +26,11 @@ export const transform = <T extends TypeWithID>({ config, data, fields }: Transf
|
||||
delete data._rels
|
||||
}
|
||||
|
||||
if ('_texts' in data) {
|
||||
texts = createPathMap(data._texts)
|
||||
delete data._texts
|
||||
}
|
||||
|
||||
if ('_numbers' in data) {
|
||||
numbers = createPathMap(data._numbers)
|
||||
delete data._numbers
|
||||
@@ -42,6 +48,7 @@ export const transform = <T extends TypeWithID>({ config, data, fields }: Transf
|
||||
deletions,
|
||||
fieldPrefix: '',
|
||||
fields,
|
||||
texts,
|
||||
numbers,
|
||||
path: '',
|
||||
relationships,
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { BlocksMap } from '../../utilities/createBlocksMap'
|
||||
|
||||
import { transformHasManyNumber } from './hasManyNumber'
|
||||
import { transformRelationship } from './relationship'
|
||||
import { transformHasManyText } from './hasManyText'
|
||||
|
||||
type TraverseFieldsArgs = {
|
||||
/**
|
||||
@@ -34,6 +35,10 @@ type TraverseFieldsArgs = {
|
||||
* An array of Payload fields to traverse
|
||||
*/
|
||||
fields: (Field | TabAsField)[]
|
||||
/**
|
||||
* All hasMany text fields, as returned by Drizzle, keyed on an object by field path
|
||||
*/
|
||||
texts: Record<string, Record<string, unknown>[]>
|
||||
/**
|
||||
* All hasMany number fields, as returned by Drizzle, keyed on an object by field path
|
||||
*/
|
||||
@@ -61,6 +66,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
deletions,
|
||||
fieldPrefix,
|
||||
fields,
|
||||
texts,
|
||||
numbers,
|
||||
path,
|
||||
relationships,
|
||||
@@ -77,6 +83,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
deletions,
|
||||
fieldPrefix,
|
||||
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
||||
texts,
|
||||
numbers,
|
||||
path,
|
||||
relationships,
|
||||
@@ -96,6 +103,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
deletions,
|
||||
fieldPrefix,
|
||||
fields: field.fields,
|
||||
texts,
|
||||
numbers,
|
||||
path,
|
||||
relationships,
|
||||
@@ -127,6 +135,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
deletions,
|
||||
fieldPrefix: '',
|
||||
fields: field.fields,
|
||||
texts,
|
||||
numbers,
|
||||
path: `${sanitizedPath}${field.name}.${row._order - 1}`,
|
||||
relationships,
|
||||
@@ -151,6 +160,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
deletions,
|
||||
fieldPrefix: '',
|
||||
fields: field.fields,
|
||||
texts,
|
||||
numbers,
|
||||
path: `${sanitizedPath}${field.name}.${i}`,
|
||||
relationships,
|
||||
@@ -194,6 +204,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
deletions,
|
||||
fieldPrefix: '',
|
||||
fields: block.fields,
|
||||
texts,
|
||||
numbers,
|
||||
path: `${blockFieldPath}.${row._order - 1}`,
|
||||
relationships,
|
||||
@@ -224,6 +235,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
deletions,
|
||||
fieldPrefix: '',
|
||||
fields: block.fields,
|
||||
texts,
|
||||
numbers,
|
||||
path: `${blockFieldPath}.${i}`,
|
||||
relationships,
|
||||
@@ -285,6 +297,40 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
return result
|
||||
}
|
||||
|
||||
if (field.type === 'text' && field?.hasMany) {
|
||||
const textPathMatch = texts[`${sanitizedPath}${field.name}`]
|
||||
if (!textPathMatch) return result
|
||||
|
||||
if (field.localized) {
|
||||
result[field.name] = {}
|
||||
const textsByLocale: Record<string, Record<string, unknown>[]> = {}
|
||||
|
||||
textPathMatch.forEach((row) => {
|
||||
if (typeof row.locale === 'string') {
|
||||
if (!textsByLocale[row.locale]) textsByLocale[row.locale] = []
|
||||
textsByLocale[row.locale].push(row)
|
||||
}
|
||||
})
|
||||
|
||||
Object.entries(textsByLocale).forEach(([locale, texts]) => {
|
||||
transformHasManyText({
|
||||
field,
|
||||
locale,
|
||||
textRows: texts,
|
||||
ref: result,
|
||||
})
|
||||
})
|
||||
} else {
|
||||
transformHasManyText({
|
||||
field,
|
||||
textRows: textPathMatch,
|
||||
ref: result,
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
if (field.type === 'number' && field.hasMany) {
|
||||
const numberPathMatch = numbers[`${sanitizedPath}${field.name}`]
|
||||
if (!numberPathMatch) return result
|
||||
@@ -374,6 +420,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
deletions,
|
||||
fieldPrefix: groupFieldPrefix,
|
||||
fields: field.fields,
|
||||
texts,
|
||||
numbers,
|
||||
path: `${sanitizedPath}${field.name}`,
|
||||
relationships,
|
||||
@@ -390,6 +437,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
deletions,
|
||||
fieldPrefix: groupFieldPrefix,
|
||||
fields: field.fields,
|
||||
texts,
|
||||
numbers,
|
||||
path: `${sanitizedPath}${field.name}`,
|
||||
relationships,
|
||||
@@ -400,6 +448,21 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
break
|
||||
}
|
||||
|
||||
case 'text': {
|
||||
let val = fieldData
|
||||
if (typeof fieldData === 'string') {
|
||||
val = String(fieldData)
|
||||
}
|
||||
|
||||
if (typeof locale === 'string') {
|
||||
ref[locale] = val
|
||||
} else {
|
||||
result[field.name] = val
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 'number': {
|
||||
let val = fieldData
|
||||
if (typeof fieldData === 'string') {
|
||||
|
||||
@@ -18,6 +18,7 @@ type Args = {
|
||||
data: unknown
|
||||
field: ArrayField
|
||||
locale?: string
|
||||
texts: Record<string, unknown>[]
|
||||
numbers: Record<string, unknown>[]
|
||||
path: string
|
||||
relationships: Record<string, unknown>[]
|
||||
@@ -36,6 +37,7 @@ export const transformArray = ({
|
||||
data,
|
||||
field,
|
||||
locale,
|
||||
texts,
|
||||
numbers,
|
||||
path,
|
||||
relationships,
|
||||
@@ -86,6 +88,7 @@ export const transformArray = ({
|
||||
fieldPrefix: '',
|
||||
fields: field.fields,
|
||||
locales: newRow.locales,
|
||||
texts,
|
||||
numbers,
|
||||
parentTableName: arrayTableName,
|
||||
path: `${path || ''}${field.name}.${i}.`,
|
||||
|
||||
@@ -18,6 +18,7 @@ type Args = {
|
||||
data: Record<string, unknown>[]
|
||||
field: BlockField
|
||||
locale?: string
|
||||
texts: Record<string, unknown>[]
|
||||
numbers: Record<string, unknown>[]
|
||||
path: string
|
||||
relationships: Record<string, unknown>[]
|
||||
@@ -34,6 +35,7 @@ export const transformBlocks = ({
|
||||
data,
|
||||
field,
|
||||
locale,
|
||||
texts,
|
||||
numbers,
|
||||
path,
|
||||
relationships,
|
||||
@@ -84,6 +86,7 @@ export const transformBlocks = ({
|
||||
fieldPrefix: '',
|
||||
fields: matchedBlock.fields,
|
||||
locales: newRow.locales,
|
||||
texts,
|
||||
numbers,
|
||||
parentTableName: blockTableName,
|
||||
path: `${path || ''}${field.name}.${i}.`,
|
||||
|
||||
@@ -27,6 +27,7 @@ export const transformForWrite = ({
|
||||
blocks: {},
|
||||
blocksToDelete: new Set(),
|
||||
locales: {},
|
||||
texts: [],
|
||||
numbers: [],
|
||||
relationships: [],
|
||||
relationshipsToDelete: [],
|
||||
@@ -47,6 +48,7 @@ export const transformForWrite = ({
|
||||
fieldPrefix: '',
|
||||
fields,
|
||||
locales: rowToInsert.locales,
|
||||
texts: rowToInsert.texts,
|
||||
numbers: rowToInsert.numbers,
|
||||
parentTableName: tableName,
|
||||
path,
|
||||
|
||||
15
packages/db-postgres/src/transform/write/texts.ts
Normal file
15
packages/db-postgres/src/transform/write/texts.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
type Args = {
|
||||
baseRow: Record<string, unknown>
|
||||
data: unknown[]
|
||||
texts: Record<string, unknown>[]
|
||||
}
|
||||
|
||||
export const transformTexts = ({ baseRow, data, texts }: Args) => {
|
||||
data.forEach((val, i) => {
|
||||
texts.push({
|
||||
...baseRow,
|
||||
text: val,
|
||||
order: i + 1,
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { transformBlocks } from './blocks'
|
||||
import { transformNumbers } from './numbers'
|
||||
import { transformRelationship } from './relationships'
|
||||
import { transformSelects } from './selects'
|
||||
import { transformTexts } from './texts'
|
||||
|
||||
type Args = {
|
||||
adapter: PostgresAdapter
|
||||
@@ -44,6 +45,7 @@ type Args = {
|
||||
locales: {
|
||||
[locale: string]: Record<string, unknown>
|
||||
}
|
||||
texts: Record<string, unknown>[]
|
||||
numbers: Record<string, unknown>[]
|
||||
/**
|
||||
* This is the name of the parent table
|
||||
@@ -71,6 +73,7 @@ export const traverseFields = ({
|
||||
fields,
|
||||
forcedLocale,
|
||||
locales,
|
||||
texts,
|
||||
numbers,
|
||||
parentTableName,
|
||||
path,
|
||||
@@ -108,6 +111,7 @@ export const traverseFields = ({
|
||||
data: localeData,
|
||||
field,
|
||||
locale: localeKey,
|
||||
texts,
|
||||
numbers,
|
||||
path,
|
||||
relationships,
|
||||
@@ -128,6 +132,7 @@ export const traverseFields = ({
|
||||
blocksToDelete,
|
||||
data: data[field.name],
|
||||
field,
|
||||
texts,
|
||||
numbers,
|
||||
path,
|
||||
relationships,
|
||||
@@ -158,6 +163,7 @@ export const traverseFields = ({
|
||||
data: localeData,
|
||||
field,
|
||||
locale: localeKey,
|
||||
texts,
|
||||
numbers,
|
||||
path,
|
||||
relationships,
|
||||
@@ -175,6 +181,7 @@ export const traverseFields = ({
|
||||
blocksToDelete,
|
||||
data: fieldData,
|
||||
field,
|
||||
texts,
|
||||
numbers,
|
||||
path,
|
||||
relationships,
|
||||
@@ -203,6 +210,7 @@ export const traverseFields = ({
|
||||
fields: field.fields,
|
||||
forcedLocale: localeKey,
|
||||
locales,
|
||||
texts,
|
||||
numbers,
|
||||
parentTableName,
|
||||
path: `${path || ''}${field.name}.`,
|
||||
@@ -225,6 +233,7 @@ export const traverseFields = ({
|
||||
fieldPrefix: `${fieldName}_`,
|
||||
fields: field.fields,
|
||||
locales,
|
||||
texts,
|
||||
numbers,
|
||||
parentTableName,
|
||||
path: `${path || ''}${field.name}.`,
|
||||
@@ -258,6 +267,7 @@ export const traverseFields = ({
|
||||
fields: tab.fields,
|
||||
forcedLocale: localeKey,
|
||||
locales,
|
||||
texts,
|
||||
numbers,
|
||||
parentTableName,
|
||||
path: `${path || ''}${tab.name}.`,
|
||||
@@ -280,6 +290,7 @@ export const traverseFields = ({
|
||||
fieldPrefix: `${fieldPrefix || ''}${tab.name}_`,
|
||||
fields: tab.fields,
|
||||
locales,
|
||||
texts,
|
||||
numbers,
|
||||
parentTableName,
|
||||
path: `${path || ''}${tab.name}.`,
|
||||
@@ -303,6 +314,7 @@ export const traverseFields = ({
|
||||
fieldPrefix,
|
||||
fields: tab.fields,
|
||||
locales,
|
||||
texts,
|
||||
numbers,
|
||||
parentTableName,
|
||||
path,
|
||||
@@ -328,6 +340,7 @@ export const traverseFields = ({
|
||||
fieldPrefix,
|
||||
fields: field.fields,
|
||||
locales,
|
||||
texts,
|
||||
numbers,
|
||||
parentTableName,
|
||||
path,
|
||||
@@ -382,6 +395,37 @@ export const traverseFields = ({
|
||||
return
|
||||
}
|
||||
|
||||
if (field.type === 'text' && field.hasMany) {
|
||||
const textPath = `${path || ''}${field.name}`
|
||||
|
||||
if (field.localized) {
|
||||
if (typeof fieldData === 'object') {
|
||||
Object.entries(fieldData).forEach(([localeKey, localeData]) => {
|
||||
if (Array.isArray(localeData)) {
|
||||
transformTexts({
|
||||
baseRow: {
|
||||
locale: localeKey,
|
||||
path: textPath,
|
||||
},
|
||||
data: localeData,
|
||||
texts,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
} else if (Array.isArray(fieldData)) {
|
||||
transformTexts({
|
||||
baseRow: {
|
||||
path: textPath,
|
||||
},
|
||||
data: fieldData,
|
||||
texts,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (field.type === 'number' && field.hasMany) {
|
||||
const numberPath = `${path || ''}${field.name}`
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ export type RowToInsert = {
|
||||
locales: {
|
||||
[locale: string]: Record<string, unknown>
|
||||
}
|
||||
texts: Record<string, unknown>[]
|
||||
numbers: Record<string, unknown>[]
|
||||
relationships: Record<string, unknown>[]
|
||||
relationshipsToDelete: RelationshipToDelete[]
|
||||
|
||||
@@ -68,6 +68,7 @@ export const upsertRow = async <T extends TypeWithID>({
|
||||
|
||||
const localesToInsert: Record<string, unknown>[] = []
|
||||
const relationsToInsert: Record<string, unknown>[] = []
|
||||
const textsToInsert: Record<string, unknown>[] = []
|
||||
const numbersToInsert: Record<string, unknown>[] = []
|
||||
const blocksToInsert: { [blockType: string]: BlockRowToInsert[] } = {}
|
||||
const selectsToInsert: { [selectTableName: string]: Record<string, unknown>[] } = {}
|
||||
@@ -89,6 +90,14 @@ export const upsertRow = async <T extends TypeWithID>({
|
||||
})
|
||||
}
|
||||
|
||||
// If there are texts, add parent to each
|
||||
if (rowToInsert.texts.length > 0) {
|
||||
rowToInsert.texts.forEach((textRow) => {
|
||||
textRow.parent = insertedRow.id
|
||||
textsToInsert.push(textRow)
|
||||
})
|
||||
}
|
||||
|
||||
// If there are numbers, add parent to each
|
||||
if (rowToInsert.numbers.length > 0) {
|
||||
rowToInsert.numbers.forEach((numberRow) => {
|
||||
@@ -161,6 +170,29 @@ export const upsertRow = async <T extends TypeWithID>({
|
||||
await db.insert(adapter.tables[relationshipsTableName]).values(relationsToInsert)
|
||||
}
|
||||
|
||||
// //////////////////////////////////
|
||||
// INSERT hasMany TEXTS
|
||||
// //////////////////////////////////
|
||||
|
||||
const textsTableName = `${tableName}_texts`
|
||||
|
||||
if (operation === 'update') {
|
||||
await deleteExistingRowsByPath({
|
||||
adapter,
|
||||
db,
|
||||
localeColumnName: 'locale',
|
||||
parentColumnName: 'parent',
|
||||
parentID: insertedRow.id,
|
||||
pathColumnName: 'path',
|
||||
rows: textsToInsert,
|
||||
tableName: textsTableName,
|
||||
})
|
||||
}
|
||||
|
||||
if (textsToInsert.length > 0) {
|
||||
await db.insert(adapter.tables[textsTableName]).values(textsToInsert).returning()
|
||||
}
|
||||
|
||||
// //////////////////////////////////
|
||||
// INSERT hasMany NUMBERS
|
||||
// //////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user