chore: merge from 2.0
This commit is contained in:
10
packages/db-postgres/.eslintignore
Normal file
10
packages/db-postgres/.eslintignore
Normal file
@@ -0,0 +1,10 @@
|
||||
.tmp
|
||||
**/.git
|
||||
**/.hg
|
||||
**/.pnp.*
|
||||
**/.svn
|
||||
**/.yarn/**
|
||||
**/build
|
||||
**/dist/**
|
||||
**/node_modules
|
||||
**/temp
|
||||
15
packages/db-postgres/.eslintrc.cjs
Normal file
15
packages/db-postgres/.eslintrc.cjs
Normal file
@@ -0,0 +1,15 @@
|
||||
/** @type {import('prettier').Config} */
|
||||
module.exports = {
|
||||
extends: ['@payloadcms'],
|
||||
overrides: [
|
||||
{
|
||||
extends: ['plugin:@typescript-eslint/disable-type-checked'],
|
||||
files: ['*.js', '*.cjs', '*.json', '*.md', '*.yml', '*.yaml'],
|
||||
},
|
||||
],
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.json'],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
root: true,
|
||||
}
|
||||
10
packages/db-postgres/.prettierignore
Normal file
10
packages/db-postgres/.prettierignore
Normal file
@@ -0,0 +1,10 @@
|
||||
.tmp
|
||||
**/.git
|
||||
**/.hg
|
||||
**/.pnp.*
|
||||
**/.svn
|
||||
**/.yarn/**
|
||||
**/build
|
||||
**/dist/**
|
||||
**/node_modules
|
||||
**/temp
|
||||
15
packages/db-postgres/.swcrc
Normal file
15
packages/db-postgres/.swcrc
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/swcrc",
|
||||
"sourceMaps": "inline",
|
||||
"jsc": {
|
||||
"target": "esnext",
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"tsx": true,
|
||||
"dts": true
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "commonjs"
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,38 @@
|
||||
{
|
||||
"name": "@payloadcms/db-postgres",
|
||||
"version": "0.0.1",
|
||||
"description": "The officially supported Postgres database adapter for Payload",
|
||||
"main": "index.js",
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"author": "Payload CMS, Inc.",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
},
|
||||
"author": "Payload CMS, Inc.",
|
||||
"peerDependencies": {
|
||||
"better-sqlite3": "^8.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@libsql/client": "^0.3.1",
|
||||
"drizzle-kit": "^0.19.13-a511135",
|
||||
"drizzle-orm": "^0.28.0",
|
||||
"pg": "^8.11.1",
|
||||
"prompts": "^2.4.2",
|
||||
"to-snake-case": "^1.0.0"
|
||||
"drizzle-kit": "0.19.13-e99bac1",
|
||||
"drizzle-orm": "0.28.5",
|
||||
"pg": "8.11.3",
|
||||
"prompts": "2.4.2",
|
||||
"to-snake-case": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/pg": "^8.10.2",
|
||||
"@types/to-snake-case": "^1.0.0",
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
"@types/pg": "8.10.2",
|
||||
"@types/to-snake-case": "1.0.0",
|
||||
"better-sqlite3": "^8.5.0",
|
||||
"payload": "payloadcms/payload#build/chore/update-2.0",
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
"payload": "workspace:*"
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"repository": "https://github.com/payloadcms/payload",
|
||||
"scripts": {
|
||||
"build:swc": "swc ./src -d ./dist --config-file .swcrc",
|
||||
"build:types": "tsc --emitDeclarationOnly --outDir dist",
|
||||
"builddisabled": "pnpm build:swc && pnpm build:types"
|
||||
},
|
||||
"version": "0.0.1"
|
||||
}
|
||||
|
||||
@@ -13,133 +13,133 @@ import { DrizzleDB } from './types';
|
||||
|
||||
// Migration table def in order to use query using drizzle
|
||||
const migrationsSchema = pgTable('payload_migrations', {
|
||||
name: varchar('name'),
|
||||
batch: numeric('batch'),
|
||||
name: varchar('name'),
|
||||
schema: jsonb('schema'),
|
||||
});
|
||||
})
|
||||
|
||||
export const connect: Connect = async function connect(
|
||||
this: PostgresAdapter,
|
||||
payload,
|
||||
) {
|
||||
let db: DrizzleDB;
|
||||
export const connect: Connect = async function connect(this: PostgresAdapter, payload) {
|
||||
let db: DrizzleDB
|
||||
|
||||
this.schema = {
|
||||
...this.tables,
|
||||
...this.relations,
|
||||
...this.enums,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
if ('pool' in this && this.pool !== false) {
|
||||
const pool = new Pool(this.pool);
|
||||
db = drizzle(pool, { schema: this.schema });
|
||||
await pool.connect();
|
||||
const pool = new Pool(this.pool)
|
||||
db = drizzle(pool, { schema: this.schema })
|
||||
await pool.connect()
|
||||
}
|
||||
|
||||
if ('client' in this && this.client !== false) {
|
||||
const client = new Client(this.client);
|
||||
db = drizzle(client, { schema: this.schema });
|
||||
await client.connect();
|
||||
const client = new Client(this.client)
|
||||
db = drizzle(client, { schema: this.schema })
|
||||
await client.connect()
|
||||
}
|
||||
|
||||
if (process.env.PAYLOAD_DROP_DATABASE === 'true') {
|
||||
this.payload.logger.info('---- DROPPING TABLES ----');
|
||||
await db.execute(sql`drop schema public cascade;\ncreate schema public;`);
|
||||
this.payload.logger.info('---- DROPPED TABLES ----');
|
||||
this.payload.logger.info('---- DROPPING TABLES ----')
|
||||
await db.execute(sql`drop schema public cascade;\ncreate schema public;`)
|
||||
this.payload.logger.info('---- DROPPED TABLES ----')
|
||||
}
|
||||
} catch (err) {
|
||||
payload.logger.error(
|
||||
`Error: cannot connect to Postgres. Details: ${err.message}`,
|
||||
err,
|
||||
);
|
||||
process.exit(1);
|
||||
payload.logger.error(`Error: cannot connect to Postgres. Details: ${err.message}`, err)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
this.payload.logger.info('Connected to Postgres successfully');
|
||||
this.db = db;
|
||||
this.payload.logger.info('Connected to Postgres successfully')
|
||||
this.db = db
|
||||
|
||||
// Only push schema if not in production
|
||||
if (process.env.NODE_ENV === 'production') return;
|
||||
if (process.env.NODE_ENV === 'production') return
|
||||
|
||||
// This will prompt if clarifications are needed for Drizzle to push new schema
|
||||
const { hasDataLoss, warnings, statementsToExecute, apply } = await pushSchema(this.schema, this.db);
|
||||
const { apply, hasDataLoss, statementsToExecute, warnings } = await pushSchema(
|
||||
this.schema,
|
||||
this.db,
|
||||
)
|
||||
|
||||
this.payload.logger.debug({
|
||||
msg: 'Schema push results',
|
||||
hasDataLoss,
|
||||
warnings,
|
||||
msg: 'Schema push results',
|
||||
statementsToExecute,
|
||||
});
|
||||
warnings,
|
||||
})
|
||||
|
||||
if (warnings.length) {
|
||||
this.payload.logger.warn({
|
||||
msg: `Warnings detected during schema push: ${warnings.join('\n')}`,
|
||||
warnings,
|
||||
});
|
||||
})
|
||||
|
||||
if (hasDataLoss) {
|
||||
this.payload.logger.warn({
|
||||
msg: 'DATA LOSS WARNING: Possible data loss detected if schema is pushed.',
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
const { confirm: acceptWarnings } = await prompts(
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'confirm',
|
||||
message: 'Accept warnings and push schema to database?',
|
||||
initial: false,
|
||||
message: 'Accept warnings and push schema to database?',
|
||||
name: 'confirm',
|
||||
type: 'confirm',
|
||||
},
|
||||
{
|
||||
onCancel: () => {
|
||||
process.exit(0);
|
||||
process.exit(0)
|
||||
},
|
||||
},
|
||||
);
|
||||
)
|
||||
|
||||
// Exit if user does not accept warnings.
|
||||
// Q: Is this the right type of exit for this interaction?
|
||||
if (!acceptWarnings) {
|
||||
process.exit(0);
|
||||
process.exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
this.migrationDir = '.migrations';
|
||||
this.migrationDir = '.migrations'
|
||||
|
||||
// Create drizzle snapshot if it doesn't exist
|
||||
if (!fs.existsSync(`${this.migrationDir}/drizzle-snapshot.json`)) {
|
||||
// Ensure migration dir exists
|
||||
if (!fs.existsSync(this.migrationDir)) {
|
||||
fs.mkdirSync(this.migrationDir);
|
||||
fs.mkdirSync(this.migrationDir)
|
||||
}
|
||||
|
||||
const drizzleJSON = generateDrizzleJson(this.schema);
|
||||
const drizzleJSON = generateDrizzleJson(this.schema)
|
||||
|
||||
fs.writeFileSync(`${this.migrationDir}/drizzle-snapshot.json`, JSON.stringify(drizzleJSON, null, 2));
|
||||
fs.writeFileSync(
|
||||
`${this.migrationDir}/drizzle-snapshot.json`,
|
||||
JSON.stringify(drizzleJSON, null, 2),
|
||||
)
|
||||
}
|
||||
|
||||
const jsonSchema = configToJSONSchema(this.payload.config);
|
||||
const jsonSchema = configToJSONSchema(this.payload.config)
|
||||
|
||||
await apply();
|
||||
await apply()
|
||||
|
||||
const devPush = await this.db
|
||||
.select()
|
||||
.from(migrationsSchema)
|
||||
.where(eq(migrationsSchema.batch, '-1'));
|
||||
.where(eq(migrationsSchema.batch, '-1'))
|
||||
|
||||
if (!devPush.length) {
|
||||
await this.db.insert(migrationsSchema).values({
|
||||
name: 'dev',
|
||||
batch: '-1',
|
||||
name: 'dev',
|
||||
schema: JSON.stringify(jsonSchema),
|
||||
});
|
||||
})
|
||||
} else {
|
||||
await this.db
|
||||
.update(migrationsSchema)
|
||||
.set({
|
||||
schema: JSON.stringify(jsonSchema),
|
||||
})
|
||||
.where(eq(migrationsSchema.batch, '-1'));
|
||||
.where(eq(migrationsSchema.batch, '-1'))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { Create } from 'payload/dist/database/types';
|
||||
import toSnakeCase from 'to-snake-case';
|
||||
import { upsertRow } from '../upsertRow';
|
||||
import type { Create } from 'payload/database'
|
||||
|
||||
export const create: Create = async function create({
|
||||
collection: collectionSlug,
|
||||
data,
|
||||
req,
|
||||
}) {
|
||||
const collection = this.payload.collections[collectionSlug].config;
|
||||
import toSnakeCase from 'to-snake-case'
|
||||
|
||||
import { upsertRow } from '../upsertRow'
|
||||
|
||||
export const create: Create = async function create({ collection: collectionSlug, data, req }) {
|
||||
const collection = this.payload.collections[collectionSlug].config
|
||||
|
||||
const result = await upsertRow({
|
||||
adapter: this,
|
||||
@@ -15,7 +13,7 @@ export const create: Create = async function create({
|
||||
fields: collection.fields,
|
||||
operation: 'create',
|
||||
tableName: toSnakeCase(collectionSlug),
|
||||
});
|
||||
})
|
||||
|
||||
return result;
|
||||
};
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
/* eslint-disable no-restricted-syntax, no-await-in-loop */
|
||||
import fs from 'fs';
|
||||
import { CreateMigration } from 'payload/dist/database/types';
|
||||
import type { CreateMigration } from 'payload/database'
|
||||
import type { DatabaseAdapter, Init } from 'payload/database'
|
||||
|
||||
import { generateDrizzleJson, generateMigration } from 'drizzle-kit/utils';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { jsonb, numeric, pgEnum, pgTable, varchar } from 'drizzle-orm/pg-core';
|
||||
import { SanitizedCollectionConfig } from 'payload/dist/collections/config/types';
|
||||
import type { DatabaseAdapter, Init } from 'payload/dist/database/types';
|
||||
import { configToJSONSchema } from 'payload/dist/utilities/configToJSONSchema';
|
||||
import prompts from 'prompts';
|
||||
import { buildTable } from './schema/build';
|
||||
import type { GenericEnum, GenericRelation, GenericTable, PostgresAdapter } from './types';
|
||||
import { generateDrizzleJson, generateMigration } from 'drizzle-kit/utils'
|
||||
import { eq } from 'drizzle-orm'
|
||||
import { jsonb, numeric, pgEnum, pgTable, varchar } from 'drizzle-orm/pg-core'
|
||||
import fs from 'fs'
|
||||
import { SanitizedCollectionConfig } from 'payload/types'
|
||||
import { configToJSONSchema } from 'payload/utilities'
|
||||
import prompts from 'prompts'
|
||||
|
||||
import type { GenericEnum, GenericRelation, GenericTable, PostgresAdapter } from './types'
|
||||
|
||||
import { buildTable } from './schema/build'
|
||||
|
||||
const migrationTemplate = (upSQL?: string) => `
|
||||
import payload, { Payload } from 'payload';
|
||||
@@ -22,7 +24,7 @@ export async function up(payload: Payload): Promise<void> {
|
||||
export async function down(payload: Payload): Promise<void> {
|
||||
// Migration code
|
||||
};
|
||||
`;
|
||||
`
|
||||
|
||||
export const createMigration: CreateMigration = async function createMigration(
|
||||
this: PostgresAdapter,
|
||||
@@ -30,27 +32,30 @@ export const createMigration: CreateMigration = async function createMigration(
|
||||
migrationDir,
|
||||
migrationName,
|
||||
) {
|
||||
payload.logger.info({ msg: 'Creating migration from postgres adapter...' });
|
||||
const dir = migrationDir || '.migrations'; // TODO: Verify path after linking
|
||||
payload.logger.info({ msg: 'Creating migration from postgres adapter...' })
|
||||
const dir = migrationDir || '.migrations' // TODO: Verify path after linking
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir);
|
||||
fs.mkdirSync(dir)
|
||||
}
|
||||
|
||||
const [yyymmdd, hhmmss] = new Date().toISOString().split('T');
|
||||
const formattedDate = yyymmdd.replace(/\D/g, '');
|
||||
const formattedTime = hhmmss.split('.')[0].replace(/\D/g, '');
|
||||
const [yyymmdd, hhmmss] = new Date().toISOString().split('T')
|
||||
const formattedDate = yyymmdd.replace(/\D/g, '')
|
||||
const formattedTime = hhmmss.split('.')[0].replace(/\D/g, '')
|
||||
|
||||
const timestamp = `${formattedDate}_${formattedTime}`;
|
||||
const timestamp = `${formattedDate}_${formattedTime}`
|
||||
|
||||
const formattedName = migrationName.replace(/\W/g, '_');
|
||||
const fileName = `${timestamp}_${formattedName}.ts`;
|
||||
const filePath = `${dir}/${fileName}`;
|
||||
const formattedName = migrationName.replace(/\W/g, '_')
|
||||
const fileName = `${timestamp}_${formattedName}.ts`
|
||||
const filePath = `${dir}/${fileName}`
|
||||
|
||||
const snapshotJSON = fs.readFileSync(`${dir}/drizzle-snapshot.json`, 'utf8');
|
||||
const drizzleJsonBefore = generateDrizzleJson(JSON.parse(snapshotJSON));
|
||||
const drizzleJsonAfter = generateDrizzleJson(this.schema, drizzleJsonBefore.id);
|
||||
const sqlStatements = await generateMigration(drizzleJsonBefore, drizzleJsonAfter);
|
||||
fs.writeFileSync(filePath, migrationTemplate(sqlStatements.length ? sqlStatements?.join('\n') : undefined));
|
||||
const snapshotJSON = fs.readFileSync(`${dir}/drizzle-snapshot.json`, 'utf8')
|
||||
const drizzleJsonBefore = generateDrizzleJson(JSON.parse(snapshotJSON))
|
||||
const drizzleJsonAfter = generateDrizzleJson(this.schema, drizzleJsonBefore.id)
|
||||
const sqlStatements = await generateMigration(drizzleJsonBefore, drizzleJsonAfter)
|
||||
fs.writeFileSync(
|
||||
filePath,
|
||||
migrationTemplate(sqlStatements.length ? sqlStatements?.join('\n') : undefined),
|
||||
)
|
||||
|
||||
// TODO:
|
||||
// Get the most recent migration schema from the file system
|
||||
@@ -61,4 +66,4 @@ export const createMigration: CreateMigration = async function createMigration(
|
||||
// and then inject them each into the `migrationTemplate` above,
|
||||
// outputting the file into the migrations folder accordingly
|
||||
// also make sure to output the JSON schema snapshot into a `./migrationsDir/meta` folder like Drizzle does
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,14 +22,15 @@ export const buildFindManyArgs = ({
|
||||
}: BuildFindQueryArgs): Record<string, unknown> => {
|
||||
const result: Result = {
|
||||
with: {},
|
||||
};
|
||||
}
|
||||
|
||||
const _locales: Result = {
|
||||
columns: {
|
||||
id: false,
|
||||
_parentID: false,
|
||||
id: false,
|
||||
},
|
||||
};
|
||||
where: createLocaleWhereQuery({ fallbackLocale, locale }),
|
||||
}
|
||||
|
||||
if (adapter.tables[`${tableName}_relationships`]) {
|
||||
result.with._relationships = {
|
||||
@@ -42,13 +43,14 @@ export const buildFindManyArgs = ({
|
||||
}
|
||||
|
||||
if (adapter.tables[`${tableName}_locales`]) {
|
||||
result.with._locales = _locales;
|
||||
result.with._locales = _locales
|
||||
}
|
||||
|
||||
const locatedBlocks: Block[] = [];
|
||||
const locatedArrays: { [path: string]: ArrayField } = {};
|
||||
const locatedBlocks: Block[] = []
|
||||
const locatedArrays: { [path: string]: ArrayField } = {}
|
||||
|
||||
traverseFields({
|
||||
_locales,
|
||||
adapter,
|
||||
currentArgs: result,
|
||||
currentTableName: tableName,
|
||||
@@ -60,7 +62,7 @@ export const buildFindManyArgs = ({
|
||||
path: '',
|
||||
topLevelArgs: result,
|
||||
topLevelTableName: tableName,
|
||||
});
|
||||
})
|
||||
|
||||
return result;
|
||||
};
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { SanitizedConfig } from 'payload/config';
|
||||
import { buildFindManyArgs } from './buildFindManyArgs';
|
||||
import { PostgresAdapter } from '../types';
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
|
||||
import type { PostgresAdapter } from '../types'
|
||||
|
||||
import { buildFindManyArgs } from './buildFindManyArgs'
|
||||
|
||||
type BuildWithFromDepthArgs = {
|
||||
adapter: PostgresAdapter
|
||||
config: SanitizedConfig
|
||||
depth: number
|
||||
fallbackLocale?: string | false
|
||||
fallbackLocale?: false | string
|
||||
locale?: string
|
||||
}
|
||||
|
||||
@@ -19,23 +21,23 @@ export const buildWithFromDepth = ({
|
||||
locale,
|
||||
}: BuildWithFromDepthArgs): Record<string, unknown> | undefined => {
|
||||
const result = config.collections.reduce((slugs, coll) => {
|
||||
const { slug } = coll;
|
||||
const { slug } = coll
|
||||
|
||||
if (depth >= 1) {
|
||||
const args = buildFindManyArgs({
|
||||
adapter,
|
||||
config,
|
||||
collection: coll,
|
||||
config,
|
||||
depth: depth - 1,
|
||||
fallbackLocale,
|
||||
locale,
|
||||
});
|
||||
})
|
||||
|
||||
slugs[`${slug}ID`] = args;
|
||||
slugs[`${slug}ID`] = args
|
||||
}
|
||||
|
||||
return slugs;
|
||||
}, {});
|
||||
return slugs
|
||||
}, {})
|
||||
|
||||
return result;
|
||||
};
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -12,20 +12,26 @@ type TraverseFieldArgs = {
|
||||
depth?: number,
|
||||
fields: Field[]
|
||||
_locales: Record<string, unknown>
|
||||
locatedArrays: { [path: string]: ArrayField },
|
||||
locatedBlocks: Block[],
|
||||
path: string,
|
||||
topLevelArgs: Record<string, unknown>,
|
||||
adapter: PostgresAdapter
|
||||
config: SanitizedConfig
|
||||
currentArgs: Record<string, unknown>
|
||||
currentTableName: string
|
||||
depth?: number
|
||||
fields: Field[]
|
||||
locatedArrays: { [path: string]: ArrayField }
|
||||
locatedBlocks: Block[]
|
||||
path: string
|
||||
topLevelArgs: Record<string, unknown>
|
||||
topLevelTableName: string
|
||||
}
|
||||
|
||||
export const traverseFields = ({
|
||||
_locales,
|
||||
adapter,
|
||||
currentArgs,
|
||||
currentTableName,
|
||||
depth,
|
||||
fields,
|
||||
_locales,
|
||||
locatedArrays,
|
||||
locatedBlocks,
|
||||
path,
|
||||
@@ -37,39 +43,39 @@ export const traverseFields = ({
|
||||
switch (field.type) {
|
||||
case 'array': {
|
||||
const withArray: Result = {
|
||||
orderBy: ({ _order }, { asc }) => [asc(_order)],
|
||||
columns: {
|
||||
_parentID: false,
|
||||
_order: false,
|
||||
_parentID: false,
|
||||
},
|
||||
orderBy: ({ _order }, { asc }) => [asc(_order)],
|
||||
with: {},
|
||||
};
|
||||
}
|
||||
|
||||
const arrayTableName = `${currentTableName}_${toSnakeCase(field.name)}`;
|
||||
const arrayTableName = `${currentTableName}_${toSnakeCase(field.name)}`
|
||||
|
||||
if (adapter.tables[`${arrayTableName}_locales`]) withArray.with._locales = _locales;
|
||||
currentArgs.with[`${path}${field.name}`] = withArray;
|
||||
if (adapter.tables[`${arrayTableName}_locales`]) withArray.with._locales = _locales
|
||||
currentArgs.with[`${path}${field.name}`] = withArray
|
||||
|
||||
traverseFields({
|
||||
_locales,
|
||||
adapter,
|
||||
currentArgs: withArray,
|
||||
currentTableName: arrayTableName,
|
||||
depth,
|
||||
fields: field.fields,
|
||||
_locales,
|
||||
locatedArrays,
|
||||
locatedBlocks,
|
||||
path: '',
|
||||
topLevelArgs,
|
||||
topLevelTableName,
|
||||
});
|
||||
})
|
||||
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
case 'blocks':
|
||||
field.blocks.forEach((block) => {
|
||||
const blockKey = `_blocks_${block.slug}`;
|
||||
const blockKey = `_blocks_${block.slug}`
|
||||
|
||||
if (!topLevelArgs[blockKey]) {
|
||||
const withBlock: Result = {
|
||||
@@ -78,52 +84,52 @@ export const traverseFields = ({
|
||||
},
|
||||
orderBy: ({ _order }, { asc }) => [asc(_order)],
|
||||
with: {},
|
||||
};
|
||||
}
|
||||
|
||||
if (adapter.tables[`${topLevelTableName}_${toSnakeCase(block.slug)}_locales`]) withBlock.with._locales = _locales;
|
||||
topLevelArgs.with[blockKey] = withBlock;
|
||||
|
||||
traverseFields({
|
||||
_locales,
|
||||
adapter,
|
||||
currentArgs: withBlock,
|
||||
currentTableName,
|
||||
depth,
|
||||
fields: block.fields,
|
||||
_locales,
|
||||
locatedArrays,
|
||||
locatedBlocks,
|
||||
path,
|
||||
topLevelArgs,
|
||||
topLevelTableName,
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
break;
|
||||
break
|
||||
|
||||
case 'group':
|
||||
traverseFields({
|
||||
_locales,
|
||||
adapter,
|
||||
currentArgs,
|
||||
currentTableName,
|
||||
depth,
|
||||
fields: field.fields,
|
||||
_locales,
|
||||
locatedArrays,
|
||||
locatedBlocks,
|
||||
path: `${path}${field.name}_`,
|
||||
topLevelArgs,
|
||||
topLevelTableName,
|
||||
});
|
||||
})
|
||||
|
||||
break;
|
||||
break
|
||||
|
||||
default: {
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
return topLevelArgs;
|
||||
};
|
||||
return topLevelArgs
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import toSnakeCase from 'to-snake-case';
|
||||
import type { FindOne } from 'payload/dist/database/types';
|
||||
import type { PayloadRequest } from 'payload/dist/express/types';
|
||||
import type { SanitizedCollectionConfig } from 'payload/dist/collections/config/types';
|
||||
import buildQuery from './queries/buildQuery';
|
||||
import { buildFindManyArgs } from './find/buildFindManyArgs';
|
||||
import { transform } from './transform/read';
|
||||
import type { FindOne } from 'payload/database'
|
||||
import type { SanitizedCollectionConfig } from 'payload/types'
|
||||
import type { PayloadRequest } from 'payload/types'
|
||||
|
||||
import toSnakeCase from 'to-snake-case'
|
||||
|
||||
import { buildFindManyArgs } from './find/buildFindManyArgs'
|
||||
import buildQuery from './queries/buildQuery'
|
||||
import { transform } from './transform/read'
|
||||
|
||||
export const findOne: FindOne = async function findOne({
|
||||
collection,
|
||||
where: incomingWhere,
|
||||
locale,
|
||||
req = {} as PayloadRequest,
|
||||
where,
|
||||
}) {
|
||||
const collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config;
|
||||
const tableName = toSnakeCase(collection);
|
||||
const collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config
|
||||
const tableName = toSnakeCase(collection)
|
||||
|
||||
const { where } = await buildQuery({
|
||||
adapter: this,
|
||||
@@ -32,11 +35,12 @@ export const findOne: FindOne = async function findOne({
|
||||
|
||||
findManyArgs.where = where;
|
||||
|
||||
const doc = await this.db.query[tableName].findFirst(findManyArgs);
|
||||
const doc = await this.db.query[tableName].findFirst(findManyArgs)
|
||||
|
||||
return transform({
|
||||
config: this.payload.config,
|
||||
data: doc,
|
||||
fallbackLocale: req.fallbackLocale,
|
||||
fields: collectionConfig.fields,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -31,16 +31,17 @@ export function postgresAdapter(args: Args): PostgresAdapterResult {
|
||||
// @ts-expect-error
|
||||
return createDatabaseAdapter<PostgresAdapter>({
|
||||
...args,
|
||||
enums: {},
|
||||
relations: {},
|
||||
tables: {},
|
||||
payload,
|
||||
connect,
|
||||
create,
|
||||
createMigration,
|
||||
db: undefined,
|
||||
enums: {},
|
||||
find,
|
||||
// queryDrafts,
|
||||
findOne,
|
||||
// destroy,
|
||||
init,
|
||||
webpack,
|
||||
createMigration,
|
||||
payload,
|
||||
// beginTransaction,
|
||||
// rollbackTransaction,
|
||||
// commitTransaction,
|
||||
@@ -59,8 +60,8 @@ export function postgresAdapter(args: Args): PostgresAdapterResult {
|
||||
createVersion,
|
||||
// updateVersion,
|
||||
// deleteVersions,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
return adapter;
|
||||
return adapter
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
exports.postgresAdapter = () => ({});
|
||||
exports.postgresAdapter = () => ({})
|
||||
|
||||
@@ -9,7 +9,7 @@ export async function buildAndOrConditions({
|
||||
joins,
|
||||
where,
|
||||
adapter,
|
||||
locale,
|
||||
collectionSlug,
|
||||
fields,
|
||||
tableName,
|
||||
selectFields,
|
||||
@@ -24,7 +24,7 @@ export async function buildAndOrConditions({
|
||||
tableName: string,
|
||||
selectFields: Record<string, GenericColumn>
|
||||
}): Promise<SQL[]> {
|
||||
const completedConditions = [];
|
||||
const completedConditions = []
|
||||
// Loop over all AND / OR operations and add them to the AND / OR query param
|
||||
// Operations should come through as an array
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
@@ -36,7 +36,7 @@ export async function buildAndOrConditions({
|
||||
joins,
|
||||
where: condition,
|
||||
adapter,
|
||||
locale,
|
||||
collectionSlug,
|
||||
fields,
|
||||
tableName,
|
||||
selectFields,
|
||||
@@ -46,5 +46,5 @@ export async function buildAndOrConditions({
|
||||
}
|
||||
}
|
||||
}
|
||||
return completedConditions;
|
||||
return completedConditions
|
||||
}
|
||||
|
||||
@@ -96,4 +96,4 @@ const buildQuery = async function buildQuery({
|
||||
};
|
||||
};
|
||||
|
||||
export default buildQuery;
|
||||
export default buildQuery
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { and, eq, gt, gte, ilike, inArray, isNotNull, isNull, lt, lte, ne, notInArray, or } from 'drizzle-orm';
|
||||
|
||||
export const operatorMap = {
|
||||
greater_than_equal: gte,
|
||||
less_than_equal: lte,
|
||||
less_than: lt,
|
||||
// near: near,
|
||||
and,
|
||||
equals: eq,
|
||||
// TODO: isNotNull isn't right as it depends on if the query value is true or false
|
||||
exists: isNotNull,
|
||||
greater_than: gt,
|
||||
greater_than_equal: gte,
|
||||
// TODO:
|
||||
in: inArray,
|
||||
like: ilike,
|
||||
// TODO:
|
||||
@@ -20,4 +24,4 @@ export const operatorMap = {
|
||||
// intersects: intersects,
|
||||
and,
|
||||
or,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
import type { SQL } from 'drizzle-orm'
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import { Operator, Where } from 'payload/types';
|
||||
import { Field } from 'payload/dist/fields/config/types';
|
||||
@@ -25,7 +26,7 @@ export async function parseParams({
|
||||
joins,
|
||||
where,
|
||||
adapter,
|
||||
locale,
|
||||
collectionSlug,
|
||||
fields,
|
||||
tableName,
|
||||
selectFields,
|
||||
@@ -118,5 +119,5 @@ export async function parseParams({
|
||||
[result] = constraints;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -4,40 +4,37 @@
|
||||
|
||||
// type PushDiff = (schema: DrizzleSchemaExports) => Promise<{ warnings: string[], apply: () => Promise<void> }>
|
||||
|
||||
|
||||
// drizzle-kit@utils
|
||||
|
||||
import { generateDrizzleJson, generateMigration, pushSchema } from 'drizzle-kit/utils';
|
||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import { Pool } from 'pg';
|
||||
import { generateDrizzleJson, generateMigration, pushSchema } from 'drizzle-kit/utils'
|
||||
import { drizzle } from 'drizzle-orm/node-postgres'
|
||||
import { Pool } from 'pg'
|
||||
|
||||
async function generateUsage() {
|
||||
const schema = await import('./data/users');
|
||||
const schemaAfter = await import('./data/users-after');
|
||||
const schema = await import('./data/users')
|
||||
const schemaAfter = await import('./data/users-after')
|
||||
|
||||
const drizzleJsonBefore = generateDrizzleJson(schema);
|
||||
const drizzleJsonAfter = generateDrizzleJson(schemaAfter);
|
||||
const drizzleJsonBefore = generateDrizzleJson(schema)
|
||||
const drizzleJsonAfter = generateDrizzleJson(schemaAfter)
|
||||
|
||||
const sqlStatements = await generateMigration(drizzleJsonBefore, drizzleJsonAfter);
|
||||
const sqlStatements = await generateMigration(drizzleJsonBefore, drizzleJsonAfter)
|
||||
|
||||
console.log(sqlStatements);
|
||||
console.log(sqlStatements)
|
||||
}
|
||||
|
||||
async function pushUsage() {
|
||||
const schemaAfter = await import('./data/users-after');
|
||||
const schemaAfter = await import('./data/users-after')
|
||||
|
||||
const db = drizzle(
|
||||
new Pool({ connectionString: '' }),
|
||||
);
|
||||
const db = drizzle(new Pool({ connectionString: '' }))
|
||||
|
||||
const response = await pushSchema(schemaAfter, db);
|
||||
const response = await pushSchema(schemaAfter, db)
|
||||
|
||||
console.log('\n');
|
||||
console.log('hasDataLoss: ', response.hasDataLoss);
|
||||
console.log('warnings: ', response.warnings);
|
||||
console.log('statements: ', response.statementsToExecute);
|
||||
console.log('\n')
|
||||
console.log('hasDataLoss: ', response.hasDataLoss)
|
||||
console.log('warnings: ', response.warnings)
|
||||
console.log('statements: ', response.statementsToExecute)
|
||||
|
||||
await response.apply();
|
||||
await response.apply()
|
||||
|
||||
process.exit(0);
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { Relation } from 'drizzle-orm'
|
||||
import type { AnyPgColumnBuilder, IndexBuilder } from 'drizzle-orm/pg-core'
|
||||
import type { Field } from 'payload/types'
|
||||
|
||||
import { relations } from 'drizzle-orm'
|
||||
import {
|
||||
AnyPgColumnBuilder,
|
||||
index,
|
||||
integer,
|
||||
numeric,
|
||||
pgTable,
|
||||
serial,
|
||||
varchar,
|
||||
index,
|
||||
numeric,
|
||||
timestamp,
|
||||
IndexBuilder,
|
||||
unique,
|
||||
UniqueConstraintBuilder,
|
||||
} from 'drizzle-orm/pg-core';
|
||||
@@ -46,35 +48,35 @@ export const buildTable = ({
|
||||
const columns: Record<string, AnyPgColumnBuilder> = baseColumns;
|
||||
const indexes: Record<string, (cols: GenericColumns) => IndexBuilder> = {};
|
||||
|
||||
let hasLocalizedField = false;
|
||||
let hasLocalizedRelationshipField = false;
|
||||
const localesColumns: Record<string, AnyPgColumnBuilder> = {};
|
||||
const localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder> = {};
|
||||
let localesTable: GenericTable;
|
||||
let hasLocalizedField = false
|
||||
let hasLocalizedRelationshipField = false
|
||||
const localesColumns: Record<string, AnyPgColumnBuilder> = {}
|
||||
const localesIndexes: Record<string, (cols: GenericColumns) => IndexBuilder> = {}
|
||||
let localesTable: GenericTable
|
||||
|
||||
const relationships: Set<string> = new Set();
|
||||
let relationshipsTable: GenericTable;
|
||||
const relationships: Set<string> = new Set()
|
||||
let relationshipsTable: GenericTable
|
||||
|
||||
const arrayBlockRelations: Map<string, string> = new Map();
|
||||
const arrayBlockRelations: Map<string, string> = new Map()
|
||||
|
||||
const idField = fields.find((field) => fieldAffectsData(field) && field.name === 'id');
|
||||
let idColType = 'integer';
|
||||
const idField = fields.find((field) => fieldAffectsData(field) && field.name === 'id')
|
||||
let idColType = 'integer'
|
||||
|
||||
if (idField) {
|
||||
if (idField.type === 'number') {
|
||||
idColType = 'numeric';
|
||||
columns.id = numeric('id').primaryKey();
|
||||
idColType = 'numeric'
|
||||
columns.id = numeric('id').primaryKey()
|
||||
}
|
||||
|
||||
if (idField.type === 'text') {
|
||||
idColType = 'varchar';
|
||||
columns.id = varchar('id').primaryKey();
|
||||
idColType = 'varchar'
|
||||
columns.id = varchar('id').primaryKey()
|
||||
}
|
||||
} else {
|
||||
columns.id = serial('id').primaryKey();
|
||||
columns.id = serial('id').primaryKey()
|
||||
}
|
||||
|
||||
({ hasLocalizedField, hasLocalizedRelationshipField } = traverseFields({
|
||||
;({ hasLocalizedField, hasLocalizedRelationshipField } = traverseFields({
|
||||
adapter,
|
||||
arrayBlockRelations,
|
||||
buildRelationships,
|
||||
@@ -86,11 +88,11 @@ export const buildTable = ({
|
||||
newTableName: tableName,
|
||||
parentTableName: tableName,
|
||||
relationships,
|
||||
}));
|
||||
}))
|
||||
|
||||
if (timestamps) {
|
||||
columns.createdAt = timestamp('created_at').defaultNow().notNull();
|
||||
columns.updatedAt = timestamp('updated_at').defaultNow().notNull();
|
||||
columns.createdAt = timestamp('created_at').defaultNow().notNull()
|
||||
columns.updatedAt = timestamp('updated_at').defaultNow().notNull()
|
||||
}
|
||||
|
||||
const table = pgTable(tableName, columns, (cols) => {
|
||||
@@ -114,24 +116,27 @@ export const buildTable = ({
|
||||
localesColumns._parentID = parentIDColumnMap[idColType]('_parent_id').references(() => table.id, { onDelete: 'cascade' }).notNull();
|
||||
|
||||
localesTable = pgTable(localeTableName, localesColumns, (cols) => {
|
||||
return Object.entries(localesIndexes).reduce((acc, [colName, func]) => {
|
||||
acc[colName] = func(cols);
|
||||
return acc;
|
||||
}, {
|
||||
_localeParent: unique().on(cols._locale, cols._parentID),
|
||||
});
|
||||
});
|
||||
return Object.entries(localesIndexes).reduce(
|
||||
(acc, [colName, func]) => {
|
||||
acc[colName] = func(cols)
|
||||
return acc
|
||||
},
|
||||
{
|
||||
_localeParent: unique().on(cols._locale, cols._parentID),
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
adapter.tables[localeTableName] = localesTable;
|
||||
adapter.tables[localeTableName] = localesTable
|
||||
|
||||
const localesTableRelations = relations(localesTable, ({ one }) => ({
|
||||
_parentID: one(table, {
|
||||
fields: [localesTable._parentID],
|
||||
references: [table.id],
|
||||
}),
|
||||
}));
|
||||
}))
|
||||
|
||||
adapter.relations[`relations_${localeTableName}`] = localesTableRelations;
|
||||
adapter.relations[`relations_${localeTableName}`] = localesTableRelations
|
||||
}
|
||||
|
||||
if (buildRelationships) {
|
||||
@@ -141,21 +146,29 @@ export const buildTable = ({
|
||||
parent: parentIDColumnMap[idColType]('parent_id').references(() => table.id, { onDelete: 'cascade' }).notNull(),
|
||||
path: varchar('path').notNull(),
|
||||
order: integer('order'),
|
||||
};
|
||||
parent: parentIDColumnMap[idColType]('parent_id')
|
||||
.references(() => table.id)
|
||||
.notNull(),
|
||||
path: varchar('path').notNull(),
|
||||
}
|
||||
|
||||
if (hasLocalizedRelationshipField) {
|
||||
relationshipColumns.locale = adapter.enums._locales('locale');
|
||||
}
|
||||
|
||||
relationships.forEach((relationTo) => {
|
||||
const formattedRelationTo = toSnakeCase(relationTo);
|
||||
let colType = 'integer';
|
||||
const relatedCollectionCustomID = adapter.payload.collections[relationTo].config.fields.find((field) => fieldAffectsData(field) && field.name === 'id');
|
||||
if (relatedCollectionCustomID?.type === 'number') colType = 'numeric';
|
||||
if (relatedCollectionCustomID?.type === 'text') colType = 'varchar';
|
||||
const formattedRelationTo = toSnakeCase(relationTo)
|
||||
let colType = 'integer'
|
||||
const relatedCollectionCustomID = adapter.payload.collections[
|
||||
relationTo
|
||||
].config.fields.find((field) => fieldAffectsData(field) && field.name === 'id')
|
||||
if (relatedCollectionCustomID?.type === 'number') colType = 'numeric'
|
||||
if (relatedCollectionCustomID?.type === 'text') colType = 'varchar'
|
||||
|
||||
relationshipColumns[`${relationTo}ID`] = parentIDColumnMap[colType](`${formattedRelationTo}_id`).references(() => adapter.tables[formattedRelationTo].id);
|
||||
});
|
||||
relationshipColumns[`${relationTo}ID`] = parentIDColumnMap[colType](
|
||||
`${formattedRelationTo}_id`,
|
||||
).references(() => adapter.tables[formattedRelationTo].id)
|
||||
})
|
||||
|
||||
const relationshipsTableName = `${tableName}_relationships`;
|
||||
|
||||
@@ -172,54 +185,54 @@ export const buildTable = ({
|
||||
return result;
|
||||
});
|
||||
|
||||
adapter.tables[relationshipsTableName] = relationshipsTable;
|
||||
adapter.tables[relationshipsTableName] = relationshipsTable
|
||||
|
||||
const relationshipsTableRelations = relations(relationshipsTable, ({ one }) => {
|
||||
const result: Record<string, Relation<string>> = {
|
||||
parent: one(table, {
|
||||
relationName: '_relationships',
|
||||
fields: [relationshipsTable.parent],
|
||||
references: [table.id],
|
||||
relationName: '_relationships',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
relationships.forEach((relationTo) => {
|
||||
const relatedTableName = toSnakeCase(relationTo);
|
||||
const idColumnName = `${relationTo}ID`;
|
||||
const relatedTableName = toSnakeCase(relationTo)
|
||||
const idColumnName = `${relationTo}ID`
|
||||
result[idColumnName] = one(adapter.tables[relatedTableName], {
|
||||
fields: [relationshipsTable[idColumnName]],
|
||||
references: [adapter.tables[relatedTableName].id],
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
return result;
|
||||
});
|
||||
return result
|
||||
})
|
||||
|
||||
adapter.relations[`relations_${relationshipsTableName}`] = relationshipsTableRelations;
|
||||
adapter.relations[`relations_${relationshipsTableName}`] = relationshipsTableRelations
|
||||
}
|
||||
}
|
||||
|
||||
const tableRelations = relations(table, ({ many }) => {
|
||||
const result: Record<string, Relation<string>> = {};
|
||||
const result: Record<string, Relation<string>> = {}
|
||||
|
||||
arrayBlockRelations.forEach((val, key) => {
|
||||
result[key] = many(adapter.tables[val]);
|
||||
});
|
||||
result[key] = many(adapter.tables[val])
|
||||
})
|
||||
|
||||
if (hasLocalizedField) {
|
||||
result._locales = many(localesTable);
|
||||
result._locales = many(localesTable)
|
||||
}
|
||||
|
||||
if (relationships.size && relationshipsTable) {
|
||||
result._relationships = many(relationshipsTable, {
|
||||
relationName: '_relationships',
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
return result
|
||||
})
|
||||
|
||||
adapter.relations[`relations_${tableName}`] = tableRelations;
|
||||
|
||||
return { arrayBlockRelations };
|
||||
};
|
||||
return { arrayBlockRelations }
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { uniqueIndex, index } from 'drizzle-orm/pg-core';
|
||||
import { GenericColumn } from '../types';
|
||||
import { index, uniqueIndex } from 'drizzle-orm/pg-core'
|
||||
|
||||
import type { GenericColumn } from '../types'
|
||||
|
||||
type CreateIndexArgs = {
|
||||
name: string
|
||||
columnName: string
|
||||
name: string
|
||||
unique?: boolean
|
||||
}
|
||||
|
||||
export const createIndex = ({ name, columnName, unique }: CreateIndexArgs) => {
|
||||
export const createIndex = ({ columnName, name, unique }: CreateIndexArgs) => {
|
||||
return (table: { [x: string]: GenericColumn }) => {
|
||||
if (unique) return uniqueIndex(`${columnName}_idx`).on(table[name]);
|
||||
return index(`${columnName}_idx`).on(table[name]);
|
||||
};
|
||||
};
|
||||
if (unique) return uniqueIndex(`${columnName}_idx`).on(table[name])
|
||||
return index(`${columnName}_idx`).on(table[name])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { integer, numeric, varchar } from 'drizzle-orm/pg-core';
|
||||
import { integer, numeric, varchar } from 'drizzle-orm/pg-core'
|
||||
|
||||
export const parentIDColumnMap = {
|
||||
integer,
|
||||
varchar,
|
||||
numeric,
|
||||
};
|
||||
varchar,
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ type Args = {
|
||||
adapter: PostgresAdapter
|
||||
arrayBlockRelations: Map<string, string>
|
||||
buildRelationships: boolean
|
||||
columns: Record<string, AnyPgColumnBuilder>
|
||||
columnPrefix?: string
|
||||
columns: Record<string, AnyPgColumnBuilder>
|
||||
fieldPrefix?: string
|
||||
fields: Field[]
|
||||
forceLocalized?: boolean
|
||||
@@ -60,22 +60,22 @@ export const traverseFields = ({
|
||||
parentTableName,
|
||||
relationships,
|
||||
}: Args): Result => {
|
||||
let hasLocalizedField = false;
|
||||
let hasLocalizedRelationshipField = false;
|
||||
let hasLocalizedField = false
|
||||
let hasLocalizedRelationshipField = false
|
||||
|
||||
let parentIDColType = 'integer';
|
||||
if (columns.id instanceof PgNumericBuilder) parentIDColType = 'numeric';
|
||||
if (columns.id instanceof PgVarcharBuilder) parentIDColType = 'varchar';
|
||||
let parentIDColType = 'integer'
|
||||
if (columns.id instanceof PgNumericBuilder) parentIDColType = 'numeric'
|
||||
if (columns.id instanceof PgVarcharBuilder) parentIDColType = 'varchar'
|
||||
|
||||
fields.forEach((field) => {
|
||||
if ('name' in field && field.name === 'id') return;
|
||||
let columnName: string;
|
||||
if ('name' in field && field.name === 'id') return
|
||||
let columnName: string
|
||||
|
||||
let targetTable = columns;
|
||||
let targetIndexes = indexes;
|
||||
let targetTable = columns
|
||||
let targetIndexes = indexes
|
||||
|
||||
if (fieldAffectsData(field)) {
|
||||
columnName = `${columnPrefix || ''}${toSnakeCase(field.name)}`;
|
||||
columnName = `${columnPrefix || ''}${toSnakeCase(field.name)}`
|
||||
|
||||
// If field is localized,
|
||||
// add the column to the locale table instead of main table
|
||||
@@ -97,37 +97,37 @@ export const traverseFields = ({
|
||||
case 'textarea': {
|
||||
// TODO: handle hasMany
|
||||
// TODO: handle min / max length
|
||||
targetTable[`${fieldPrefix || ''}${field.name}`] = varchar(columnName);
|
||||
break;
|
||||
targetTable[`${fieldPrefix || ''}${field.name}`] = varchar(columnName)
|
||||
break
|
||||
}
|
||||
|
||||
case 'number': {
|
||||
// TODO: handle hasMany
|
||||
// TODO: handle min / max
|
||||
targetTable[`${fieldPrefix || ''}${field.name}`] = numeric(columnName);
|
||||
break;
|
||||
targetTable[`${fieldPrefix || ''}${field.name}`] = numeric(columnName)
|
||||
break
|
||||
}
|
||||
|
||||
case 'richText':
|
||||
case 'json': {
|
||||
targetTable[`${fieldPrefix || ''}${field.name}`] = jsonb(columnName);
|
||||
break;
|
||||
targetTable[`${fieldPrefix || ''}${field.name}`] = jsonb(columnName)
|
||||
break
|
||||
}
|
||||
|
||||
case 'date': {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
case 'point': {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
case 'radio': {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
case 'select': {
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
case 'array': {
|
||||
@@ -145,7 +145,11 @@ export const traverseFields = ({
|
||||
baseExtraConfig._parentOrder = (cols) => unique().on(cols._parentID, cols._order);
|
||||
}
|
||||
|
||||
const arrayTableName = `${newTableName}_${toSnakeCase(field.name)}`;
|
||||
if (field.localized && adapter.payload.config.localization) {
|
||||
baseColumns._locale = adapter.enums._locales('_locale').notNull()
|
||||
}
|
||||
|
||||
const arrayTableName = `${newTableName}_${toSnakeCase(field.name)}`
|
||||
|
||||
const { arrayBlockRelations: subArrayBlockRelations } = buildTable({
|
||||
adapter,
|
||||
@@ -153,9 +157,9 @@ export const traverseFields = ({
|
||||
baseExtraConfig,
|
||||
fields: field.fields,
|
||||
tableName: arrayTableName,
|
||||
});
|
||||
})
|
||||
|
||||
arrayBlockRelations.set(`${fieldPrefix || ''}${field.name}`, arrayTableName);
|
||||
arrayBlockRelations.set(`${fieldPrefix || ''}${field.name}`, arrayTableName)
|
||||
|
||||
const arrayTableRelations = relations(adapter.tables[arrayTableName], ({ many, one }) => {
|
||||
const result: Record<string, Relation<string>> = {
|
||||
@@ -163,22 +167,22 @@ export const traverseFields = ({
|
||||
fields: [adapter.tables[arrayTableName]._parentID],
|
||||
references: [adapter.tables[parentTableName].id],
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
if (hasLocalesTable(field.fields)) {
|
||||
result._locales = many(adapter.tables[`${arrayTableName}_locales`]);
|
||||
result._locales = many(adapter.tables[`${arrayTableName}_locales`])
|
||||
}
|
||||
|
||||
subArrayBlockRelations.forEach((val, key) => {
|
||||
result[key] = many(adapter.tables[val]);
|
||||
});
|
||||
result[key] = many(adapter.tables[val])
|
||||
})
|
||||
|
||||
return result;
|
||||
});
|
||||
return result
|
||||
})
|
||||
|
||||
adapter.relations[`relations_${arrayTableName}`] = arrayTableRelations;
|
||||
adapter.relations[`relations_${arrayTableName}`] = arrayTableRelations
|
||||
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
case 'blocks': {
|
||||
@@ -206,34 +210,37 @@ export const traverseFields = ({
|
||||
baseExtraConfig,
|
||||
fields: block.fields,
|
||||
tableName: blockTableName,
|
||||
});
|
||||
})
|
||||
|
||||
const blockTableRelations = relations(adapter.tables[blockTableName], ({ many, one }) => {
|
||||
const result: Record<string, Relation<string>> = {
|
||||
_parentID: one(adapter.tables[parentTableName], {
|
||||
fields: [adapter.tables[blockTableName]._parentID],
|
||||
references: [adapter.tables[parentTableName].id],
|
||||
}),
|
||||
};
|
||||
const blockTableRelations = relations(
|
||||
adapter.tables[blockTableName],
|
||||
({ many, one }) => {
|
||||
const result: Record<string, Relation<string>> = {
|
||||
_parentID: one(adapter.tables[parentTableName], {
|
||||
fields: [adapter.tables[blockTableName]._parentID],
|
||||
references: [adapter.tables[parentTableName].id],
|
||||
}),
|
||||
}
|
||||
|
||||
if (hasLocalesTable(block.fields)) {
|
||||
result._locales = many(adapter.tables[`${blockTableName}_locales`]);
|
||||
}
|
||||
if (hasLocalesTable(block.fields)) {
|
||||
result._locales = many(adapter.tables[`${blockTableName}_locales`])
|
||||
}
|
||||
|
||||
subArrayBlockRelations.forEach((val, key) => {
|
||||
result[key] = many(adapter.tables[val]);
|
||||
});
|
||||
subArrayBlockRelations.forEach((val, key) => {
|
||||
result[key] = many(adapter.tables[val])
|
||||
})
|
||||
|
||||
return result;
|
||||
});
|
||||
return result
|
||||
},
|
||||
)
|
||||
|
||||
adapter.relations[`relations_${blockTableName}`] = blockTableRelations;
|
||||
adapter.relations[`relations_${blockTableName}`] = blockTableRelations
|
||||
}
|
||||
|
||||
arrayBlockRelations.set(`_blocks_${block.slug}`, blockTableName);
|
||||
});
|
||||
arrayBlockRelations.set(`_blocks_${block.slug}`, blockTableName)
|
||||
})
|
||||
|
||||
break;
|
||||
break
|
||||
}
|
||||
|
||||
case 'group': {
|
||||
@@ -255,11 +262,11 @@ export const traverseFields = ({
|
||||
newTableName: `${parentTableName}_${toSnakeCase(field.name)}`,
|
||||
parentTableName,
|
||||
relationships,
|
||||
});
|
||||
})
|
||||
|
||||
if (groupHasLocalizedField) hasLocalizedField = true;
|
||||
if (groupHasLocalizedRelationshipField) hasLocalizedRelationshipField = true;
|
||||
break;
|
||||
if (groupHasLocalizedField) hasLocalizedField = true
|
||||
if (groupHasLocalizedRelationshipField) hasLocalizedRelationshipField = true
|
||||
break
|
||||
}
|
||||
|
||||
case 'tabs': {
|
||||
@@ -282,15 +289,12 @@ export const traverseFields = ({
|
||||
newTableName: `${parentTableName}_${toSnakeCase(tab.name)}`,
|
||||
parentTableName,
|
||||
relationships,
|
||||
});
|
||||
})
|
||||
|
||||
if (tabHasLocalizedField) hasLocalizedField = true;
|
||||
if (tabHasLocalizedRelationshipField) hasLocalizedRelationshipField = true;
|
||||
if (tabHasLocalizedField) hasLocalizedField = true
|
||||
if (tabHasLocalizedRelationshipField) hasLocalizedRelationshipField = true
|
||||
} else {
|
||||
({
|
||||
hasLocalizedField,
|
||||
hasLocalizedRelationshipField,
|
||||
} = traverseFields({
|
||||
;({ hasLocalizedField, hasLocalizedRelationshipField } = traverseFields({
|
||||
adapter,
|
||||
arrayBlockRelations,
|
||||
buildRelationships,
|
||||
@@ -302,18 +306,15 @@ export const traverseFields = ({
|
||||
newTableName: parentTableName,
|
||||
parentTableName,
|
||||
relationships,
|
||||
}));
|
||||
}))
|
||||
}
|
||||
});
|
||||
break;
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
case 'row':
|
||||
case 'collapsible': {
|
||||
({
|
||||
hasLocalizedField,
|
||||
hasLocalizedRelationshipField,
|
||||
} = traverseFields({
|
||||
;({ hasLocalizedField, hasLocalizedRelationshipField } = traverseFields({
|
||||
adapter,
|
||||
arrayBlockRelations,
|
||||
buildRelationships,
|
||||
@@ -325,27 +326,27 @@ export const traverseFields = ({
|
||||
newTableName: parentTableName,
|
||||
parentTableName,
|
||||
relationships,
|
||||
}));
|
||||
break;
|
||||
}))
|
||||
break
|
||||
}
|
||||
|
||||
case 'relationship':
|
||||
case 'upload':
|
||||
if (Array.isArray(field.relationTo)) {
|
||||
field.relationTo.forEach((relation) => relationships.add(relation));
|
||||
field.relationTo.forEach((relation) => relationships.add(relation))
|
||||
} else {
|
||||
relationships.add(field.relationTo);
|
||||
relationships.add(field.relationTo)
|
||||
}
|
||||
|
||||
if (field.localized && adapter.payload.config.localization) {
|
||||
hasLocalizedRelationshipField = true;
|
||||
}
|
||||
break;
|
||||
break
|
||||
|
||||
default:
|
||||
break;
|
||||
break
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
return { hasLocalizedField, hasLocalizedRelationshipField };
|
||||
};
|
||||
return { hasLocalizedField, hasLocalizedRelationshipField }
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { createBlocksMap } from '../../utilities/createBlocksMap';
|
||||
type TransformArgs = {
|
||||
config: SanitizedConfig
|
||||
data: Record<string, unknown>
|
||||
fallbackLocale?: string | false
|
||||
fallbackLocale?: false | string
|
||||
fields: Field[]
|
||||
locale?: string
|
||||
}
|
||||
@@ -21,14 +21,14 @@ export const transform = <T extends TypeWithID>({
|
||||
data,
|
||||
fields,
|
||||
}: TransformArgs): T => {
|
||||
let relationships: Record<string, Record<string, unknown>[]> = {};
|
||||
let relationships: Record<string, Record<string, unknown>[]> = {}
|
||||
|
||||
if ('_relationships' in data) {
|
||||
relationships = createRelationshipMap(data._relationships);
|
||||
delete data._relationships;
|
||||
relationships = createRelationshipMap(data._relationships)
|
||||
delete data._relationships
|
||||
}
|
||||
|
||||
const blocks = createBlocksMap(data);
|
||||
const blocks = createBlocksMap(data)
|
||||
|
||||
const result = traverseFields<T>({
|
||||
blocks,
|
||||
|
||||
@@ -55,7 +55,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
siblingData,
|
||||
table,
|
||||
}: TraverseFieldsArgs): T => {
|
||||
const sanitizedPath = path ? `${path}.` : path;
|
||||
const sanitizedPath = path ? `${path}.` : path
|
||||
|
||||
const formatted = fields.reduce((result, field) => {
|
||||
if (fieldAffectsData(field)) {
|
||||
@@ -160,8 +160,8 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
});
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
return {}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
if (!relationsByLocale[row.locale]) relationsByLocale[row.locale] = [];
|
||||
relationsByLocale[row.locale].push(row);
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
Object.entries(relationsByLocale).forEach(([locale, relations]) => {
|
||||
transformRelationship({
|
||||
@@ -233,7 +233,7 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
delete table[subFieldKey];
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
if (field.localized) {
|
||||
Object.entries(ref).forEach(([groupLocale, groupLocaleData]) => {
|
||||
@@ -310,11 +310,11 @@ export const traverseFields = <T extends Record<string, unknown>>({
|
||||
result[field.name] = localizedFieldData;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
return siblingData;
|
||||
}, siblingData);
|
||||
return siblingData
|
||||
}, siblingData)
|
||||
|
||||
return formatted as T;
|
||||
};
|
||||
return formatted as T
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import { Field } from 'payload/types';
|
||||
import { traverseFields } from './traverseFields';
|
||||
import { RowToInsert } from './types';
|
||||
import type { Field } from 'payload/types'
|
||||
|
||||
import type { RowToInsert } from './types'
|
||||
|
||||
import { traverseFields } from './traverseFields'
|
||||
|
||||
type Args = {
|
||||
data: Record<string, unknown>
|
||||
@@ -22,9 +24,8 @@ export const transformForWrite = ({
|
||||
row: {},
|
||||
locales: {},
|
||||
relationships: [],
|
||||
blocks: {},
|
||||
arrays: {},
|
||||
};
|
||||
row: {},
|
||||
}
|
||||
|
||||
// This function is responsible for building up the
|
||||
// above rowToInsert
|
||||
@@ -40,7 +41,7 @@ export const transformForWrite = ({
|
||||
path,
|
||||
relationships: rowToInsert.relationships,
|
||||
row: rowToInsert.row,
|
||||
});
|
||||
})
|
||||
|
||||
return rowToInsert;
|
||||
};
|
||||
return rowToInsert
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ export const traverseFields = ({
|
||||
path: `${path || ''}${field.name}.`,
|
||||
relationships,
|
||||
row,
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,5 +320,5 @@ export const traverseFields = ({
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ export type ArrayRowToInsert = {
|
||||
arrays: {
|
||||
[tableName: string]: ArrayRowToInsert[]
|
||||
}
|
||||
columnName: string
|
||||
locale: Record<string, unknown>
|
||||
row: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type BlockRowToInsert = {
|
||||
@@ -17,6 +20,8 @@ export type BlockRowToInsert = {
|
||||
arrays: {
|
||||
[tableName: string]: ArrayRowToInsert[]
|
||||
}
|
||||
locale: Record<string, unknown>
|
||||
row: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type RowToInsert = {
|
||||
@@ -31,4 +36,10 @@ export type RowToInsert = {
|
||||
arrays: {
|
||||
[tableName: string]: ArrayRowToInsert[]
|
||||
}
|
||||
blocks: {
|
||||
[blockType: string]: BlockRowToInsert[]
|
||||
}
|
||||
locale: Record<string, unknown>
|
||||
relationships: Record<string, unknown>[]
|
||||
row: Record<string, unknown>
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { ColumnBaseConfig, ColumnDataType, Relation, Relations } from 'drizzle-orm';
|
||||
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||
import { PgColumn, PgEnum, PgTableWithColumns } from 'drizzle-orm/pg-core';
|
||||
import { Payload } from 'payload';
|
||||
import { DatabaseAdapter } from 'payload/dist/database/types';
|
||||
import { ClientConfig, PoolConfig } from 'pg';
|
||||
import type { ColumnBaseConfig, ColumnDataType, Relation, Relations } from 'drizzle-orm'
|
||||
import type { NodePgDatabase } from 'drizzle-orm/node-postgres'
|
||||
import type { PgColumn, PgEnum, PgTableWithColumns } from 'drizzle-orm/pg-core'
|
||||
import type { Payload } from 'payload'
|
||||
import type { DatabaseAdapter } from 'payload/database'
|
||||
import type { ClientConfig, PoolConfig } from 'pg'
|
||||
|
||||
export type DrizzleDB = NodePgDatabase<Record<string, never>>
|
||||
|
||||
type BaseArgs = {
|
||||
migrationDir?: string;
|
||||
migrationName?: string;
|
||||
migrationDir?: string
|
||||
migrationName?: string
|
||||
}
|
||||
|
||||
type ClientArgs = {
|
||||
/** Client connection options for the Node package `pg` */
|
||||
client?: ClientConfig | string | false
|
||||
client?: ClientConfig | false | string
|
||||
} & BaseArgs
|
||||
|
||||
type PoolArgs = {
|
||||
@@ -24,26 +24,33 @@ type PoolArgs = {
|
||||
|
||||
export type Args = ClientArgs | PoolArgs
|
||||
|
||||
export type GenericColumn = PgColumn<ColumnBaseConfig<ColumnDataType, string>, Record<string, unknown>>
|
||||
export type GenericColumn = PgColumn<
|
||||
ColumnBaseConfig<ColumnDataType, string>,
|
||||
Record<string, unknown>
|
||||
>
|
||||
|
||||
export type GenericColumns = {
|
||||
[x: string]: GenericColumn
|
||||
}
|
||||
|
||||
export type GenericTable = PgTableWithColumns<{
|
||||
name: string, schema: undefined, columns: GenericColumns, dialect: string
|
||||
columns: GenericColumns
|
||||
dialect: string
|
||||
name: string
|
||||
schema: undefined
|
||||
}>
|
||||
|
||||
export type GenericEnum = PgEnum<[string, ...string[]]>
|
||||
|
||||
export type GenericRelation = Relations<string, Record<string, Relation<string>>>
|
||||
|
||||
export type PostgresAdapter = DatabaseAdapter & Args & {
|
||||
db: DrizzleDB
|
||||
enums: Record<string, GenericEnum>
|
||||
relations: Record<string, GenericRelation>
|
||||
tables: Record<string, GenericTable>
|
||||
schema: Record<string, GenericEnum | GenericTable | GenericRelation>
|
||||
}
|
||||
export type PostgresAdapter = DatabaseAdapter &
|
||||
Args & {
|
||||
db: DrizzleDB
|
||||
enums: Record<string, GenericEnum>
|
||||
relations: Record<string, GenericRelation>
|
||||
schema: Record<string, GenericEnum | GenericRelation | GenericTable>
|
||||
tables: Record<string, GenericTable>
|
||||
}
|
||||
|
||||
export type PostgresAdapterResult = (args: { payload: Payload }) => PostgresAdapter
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { UpdateOne } from 'payload/dist/database/types';
|
||||
import toSnakeCase from 'to-snake-case';
|
||||
import { SQL } from 'drizzle-orm';
|
||||
import buildQuery from '../queries/buildQuery';
|
||||
import { upsertRow } from '../upsertRow';
|
||||
import type { SQL } from 'drizzle-orm'
|
||||
import type { UpdateOne } from 'payload/database'
|
||||
|
||||
import toSnakeCase from 'to-snake-case'
|
||||
|
||||
import buildQuery from '../queries/buildQuery'
|
||||
import { upsertRow } from '../upsertRow'
|
||||
|
||||
export const updateOne: UpdateOne = async function updateOne({
|
||||
collection: collectionSlug,
|
||||
@@ -13,9 +15,9 @@ export const updateOne: UpdateOne = async function updateOne({
|
||||
req,
|
||||
where,
|
||||
}) {
|
||||
const collection = this.payload.collections[collectionSlug].config;
|
||||
const collection = this.payload.collections[collectionSlug].config
|
||||
|
||||
let query: SQL<unknown>;
|
||||
let query: SQL<unknown>
|
||||
|
||||
if (where) {
|
||||
query = await buildQuery({
|
||||
@@ -23,7 +25,7 @@ export const updateOne: UpdateOne = async function updateOne({
|
||||
collectionSlug,
|
||||
locale,
|
||||
where,
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
const result = await upsertRow({
|
||||
@@ -35,7 +37,7 @@ export const updateOne: UpdateOne = async function updateOne({
|
||||
operation: 'update',
|
||||
tableName: toSnakeCase(collectionSlug),
|
||||
where: query,
|
||||
});
|
||||
})
|
||||
|
||||
return result;
|
||||
};
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -27,29 +27,33 @@ export const upsertRow = async ({
|
||||
fields,
|
||||
path,
|
||||
tableName,
|
||||
});
|
||||
})
|
||||
|
||||
// First, we insert the main row
|
||||
let insertedRow: Record<string, unknown>;
|
||||
let insertedRow: Record<string, unknown>
|
||||
|
||||
if (operation === 'update') {
|
||||
const target = upsertTarget || adapter.tables[tableName].id;
|
||||
const target = upsertTarget || adapter.tables[tableName].id
|
||||
|
||||
if (id) {
|
||||
rowToInsert.row.id = id;
|
||||
[insertedRow] = await adapter.db.insert(adapter.tables[tableName])
|
||||
rowToInsert.row.id = id
|
||||
;[insertedRow] = await adapter.db
|
||||
.insert(adapter.tables[tableName])
|
||||
.values(rowToInsert.row)
|
||||
.onConflictDoUpdate({ target, set: rowToInsert.row })
|
||||
.returning();
|
||||
.onConflictDoUpdate({ set: rowToInsert.row, target })
|
||||
.returning()
|
||||
} else {
|
||||
[insertedRow] = await adapter.db.insert(adapter.tables[tableName])
|
||||
;[insertedRow] = await adapter.db
|
||||
.insert(adapter.tables[tableName])
|
||||
.values(rowToInsert.row)
|
||||
.onConflictDoUpdate({ target, set: rowToInsert.row, where })
|
||||
.returning();
|
||||
.onConflictDoUpdate({ set: rowToInsert.row, target, where })
|
||||
.returning()
|
||||
}
|
||||
} else {
|
||||
[insertedRow] = await adapter.db.insert(adapter.tables[tableName])
|
||||
.values(rowToInsert.row).returning();
|
||||
;[insertedRow] = await adapter.db
|
||||
.insert(adapter.tables[tableName])
|
||||
.values(rowToInsert.row)
|
||||
.returning()
|
||||
}
|
||||
|
||||
const localesToInsert: Record<string, unknown>[] = [];
|
||||
@@ -58,7 +62,7 @@ export const upsertRow = async ({
|
||||
|
||||
// Maintain a list of promises to run locale, blocks, and relationships
|
||||
// all in parallel
|
||||
const promises = [];
|
||||
const promises = []
|
||||
|
||||
// If there are locale rows with data, add the parent and locale to each
|
||||
if (Object.keys(rowToInsert.locales).length > 0) {
|
||||
@@ -72,20 +76,20 @@ export const upsertRow = async ({
|
||||
// If there are relationships, add parent to each
|
||||
if (rowToInsert.relationships.length > 0) {
|
||||
rowToInsert.relationships.forEach((relation) => {
|
||||
relation.parent = insertedRow.id;
|
||||
relationsToInsert.push(relation);
|
||||
});
|
||||
relation.parent = insertedRow.id
|
||||
relationsToInsert.push(relation)
|
||||
})
|
||||
}
|
||||
|
||||
// If there are blocks, add parent to each, and then
|
||||
// store by table name and rows
|
||||
Object.keys(rowToInsert.blocks).forEach((blockName) => {
|
||||
rowToInsert.blocks[blockName].forEach((blockRow) => {
|
||||
blockRow.row._parentID = insertedRow.id;
|
||||
if (!blocksToInsert[blockName]) blocksToInsert[blockName] = [];
|
||||
blocksToInsert[blockName].push(blockRow);
|
||||
});
|
||||
});
|
||||
blockRow.row._parentID = insertedRow.id
|
||||
if (!blocksToInsert[blockName]) blocksToInsert[blockName] = []
|
||||
blocksToInsert[blockName].push(blockRow)
|
||||
})
|
||||
})
|
||||
|
||||
// //////////////////////////////////
|
||||
// INSERT LOCALES
|
||||
@@ -131,7 +135,7 @@ export const upsertRow = async ({
|
||||
// INSERT BLOCKS
|
||||
// //////////////////////////////////
|
||||
|
||||
const insertedBlockRows: Record<string, Record<string, unknown>[]> = {};
|
||||
const insertedBlockRows: Record<string, Record<string, unknown>[]> = {}
|
||||
|
||||
Object.entries(blocksToInsert).forEach(([blockName, blockRows]) => {
|
||||
// For each block, push insert into promises to run parallel
|
||||
@@ -153,7 +157,7 @@ export const upsertRow = async ({
|
||||
blockRows[i].row = row;
|
||||
});
|
||||
|
||||
const blockLocaleIndexMap: number[] = [];
|
||||
const blockLocaleIndexMap: number[] = []
|
||||
|
||||
const blockLocaleRowsToInsert = blockRows.reduce((acc, blockRow, i) => {
|
||||
if (Object.entries(blockRow.locales).length > 0) {
|
||||
@@ -167,8 +171,8 @@ export const upsertRow = async ({
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
return acc
|
||||
}, [])
|
||||
|
||||
if (blockLocaleRowsToInsert.length > 0) {
|
||||
await adapter.db.insert(adapter.tables[`${tableName}_${blockName}_locales`])
|
||||
@@ -179,9 +183,9 @@ export const upsertRow = async ({
|
||||
adapter,
|
||||
arrays: blockRows.map(({ arrays }) => arrays),
|
||||
parentRows: insertedBlockRows[blockName],
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// //////////////////////////////////
|
||||
// INSERT ARRAYS RECURSIVELY
|
||||
@@ -202,10 +206,10 @@ export const upsertRow = async ({
|
||||
adapter,
|
||||
arrays: [rowToInsert.arrays],
|
||||
parentRows: [insertedRow],
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
await Promise.all(promises.map((promise) => promise()));
|
||||
await Promise.all(promises.map((promise) => promise()))
|
||||
|
||||
// //////////////////////////////////
|
||||
// RETRIEVE NEWLY UPDATED ROW
|
||||
@@ -232,5 +236,5 @@ export const upsertRow = async ({
|
||||
fields,
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export const insertArrays = async ({
|
||||
parentRows,
|
||||
}: Args): Promise<void> => {
|
||||
// Maintain a map of flattened rows by table
|
||||
const rowsByTable: RowsByTable = {};
|
||||
const rowsByTable: RowsByTable = {}
|
||||
|
||||
arrays.forEach((arraysByTable, parentRowIndex) => {
|
||||
Object.entries(arraysByTable).forEach(([tableName, arrayRows]) => {
|
||||
@@ -39,13 +39,13 @@ export const insertArrays = async ({
|
||||
};
|
||||
}
|
||||
|
||||
const parentID = parentRows[parentRowIndex].id;
|
||||
const parentID = parentRows[parentRowIndex].id
|
||||
|
||||
// Add any sub arrays that need to be created
|
||||
// We will call this recursively below
|
||||
arrayRows.forEach((arrayRow) => {
|
||||
if (Object.keys(arrayRow.arrays).length > 0) {
|
||||
rowsByTable[tableName].arrays.push(arrayRow.arrays);
|
||||
rowsByTable[tableName].arrays.push(arrayRow.arrays)
|
||||
}
|
||||
|
||||
// Set up parent IDs for both row and locale row
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Field } from 'payload/types';
|
||||
import { SQL } from 'drizzle-orm';
|
||||
import { GenericColumn, PostgresAdapter } from '../types';
|
||||
import type { SQL } from 'drizzle-orm'
|
||||
import type { Field } from 'payload/types'
|
||||
|
||||
import type { GenericColumn, PostgresAdapter } from '../types'
|
||||
|
||||
type BaseArgs = {
|
||||
adapter: PostgresAdapter
|
||||
@@ -11,17 +12,17 @@ type BaseArgs = {
|
||||
}
|
||||
|
||||
type CreateArgs = BaseArgs & {
|
||||
upsertTarget?: never
|
||||
where?: never
|
||||
id?: never
|
||||
operation: 'create'
|
||||
upsertTarget?: never
|
||||
where?: never
|
||||
}
|
||||
|
||||
type UpdateArgs = BaseArgs & {
|
||||
upsertTarget?: GenericColumn
|
||||
id?: number | string
|
||||
operation: 'update'
|
||||
upsertTarget?: GenericColumn
|
||||
where?: SQL<unknown>
|
||||
id?: string | number
|
||||
}
|
||||
|
||||
export type Args = CreateArgs | UpdateArgs
|
||||
|
||||
@@ -4,38 +4,38 @@ export type BlocksMap = {
|
||||
}
|
||||
|
||||
export const createBlocksMap = (data: Record<string, unknown>): BlocksMap => {
|
||||
const blocksMap: BlocksMap = {};
|
||||
const blocksMap: BlocksMap = {}
|
||||
|
||||
Object.entries(data).forEach(([key, rows]) => {
|
||||
if (key.startsWith('_blocks_') && Array.isArray(rows)) {
|
||||
const blockType = key.replace('_blocks_', '');
|
||||
const blockType = key.replace('_blocks_', '')
|
||||
|
||||
rows.forEach((row) => {
|
||||
if ('_path' in row) {
|
||||
if (!(row._path in blocksMap)) blocksMap[row._path] = [];
|
||||
if (!(row._path in blocksMap)) blocksMap[row._path] = []
|
||||
|
||||
row.blockType = blockType;
|
||||
blocksMap[row._path].push(row);
|
||||
row.blockType = blockType
|
||||
blocksMap[row._path].push(row)
|
||||
|
||||
delete row._path;
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
delete data[key];
|
||||
delete data[key]
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
Object.entries(blocksMap).reduce((sortedBlocksMap, [path, blocks]) => {
|
||||
sortedBlocksMap[path] = blocks.sort((a, b) => {
|
||||
if (typeof a._order === 'number' && typeof b._order === 'number') {
|
||||
return a._order - b._order;
|
||||
return a._order - b._order
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
return 0
|
||||
})
|
||||
|
||||
return sortedBlocksMap;
|
||||
}, {});
|
||||
return sortedBlocksMap
|
||||
}, {})
|
||||
|
||||
return blocksMap;
|
||||
};
|
||||
return blocksMap
|
||||
}
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
// Flatten relationships to object with path keys
|
||||
// for easier retrieval
|
||||
export const createRelationshipMap = (rawRelationships: unknown): Record<string, Record<string, unknown>[]> => {
|
||||
let relationships = {};
|
||||
export const createRelationshipMap = (
|
||||
rawRelationships: unknown,
|
||||
): Record<string, Record<string, unknown>[]> => {
|
||||
let relationships = {}
|
||||
|
||||
if (Array.isArray(rawRelationships)) {
|
||||
relationships = rawRelationships.reduce((res, relation) => {
|
||||
const formattedRelation = {
|
||||
...relation,
|
||||
};
|
||||
}
|
||||
|
||||
delete formattedRelation.path;
|
||||
delete formattedRelation.path
|
||||
|
||||
if (!res[relation.path]) res[relation.path] = [];
|
||||
res[relation.path].push(formattedRelation);
|
||||
if (!res[relation.path]) res[relation.path] = []
|
||||
res[relation.path].push(formattedRelation)
|
||||
|
||||
return res;
|
||||
}, {});
|
||||
return res
|
||||
}, {})
|
||||
}
|
||||
|
||||
return relationships;
|
||||
};
|
||||
return relationships
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { fieldAffectsData, fieldHasSubFields } from 'payload/dist/fields/config/types';
|
||||
import { Field } from 'payload/types';
|
||||
import type { Field } from 'payload/types'
|
||||
|
||||
import { fieldAffectsData, fieldHasSubFields } from 'payload/types'
|
||||
|
||||
export const hasLocalesTable = (fields: Field[]): boolean => {
|
||||
return fields.some((field) => {
|
||||
if (fieldAffectsData(field) && field.localized) return true;
|
||||
if (fieldHasSubFields(field) && field.type !== 'array') return hasLocalesTable(field.fields);
|
||||
if (field.type === 'tabs') return field.tabs.some((tab) => hasLocalesTable(tab.fields));
|
||||
return false;
|
||||
});
|
||||
};
|
||||
if (fieldAffectsData(field) && field.localized) return true
|
||||
if (fieldHasSubFields(field) && field.type !== 'array') return hasLocalesTable(field.fields)
|
||||
if (field.type === 'tabs') return field.tabs.some((tab) => hasLocalesTable(tab.fields))
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export function isArrayOfRows(data: unknown): data is Record<string, unknown>[] {
|
||||
return Array.isArray(data);
|
||||
return Array.isArray(data)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import path from 'path';
|
||||
import type { Webpack } from 'payload/dist/database/types';
|
||||
import type { Webpack } from 'payload/database'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
export const webpack: Webpack = (config) => {
|
||||
return {
|
||||
...config,
|
||||
resolve: {
|
||||
...config.resolve || {},
|
||||
...(config.resolve || {}),
|
||||
alias: {
|
||||
...config.resolve?.alias || {},
|
||||
...(config.resolve?.alias || {}),
|
||||
[path.resolve(__dirname, './index')]: path.resolve(__dirname, 'mock'),
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,24 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
"rootDir": "./src", /* Specify the root folder within your source files. */
|
||||
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
"composite": true, // Make sure typescript knows that this module depends on their references
|
||||
"noEmit": false /* Do not emit outputs. */,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
|
||||
"rootDir": "./src" /* Specify the root folder within your source files. */
|
||||
},
|
||||
"exclude": [
|
||||
"dist",
|
||||
"build",
|
||||
"tests",
|
||||
"test",
|
||||
"node_modules",
|
||||
".eslintrc.js",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.spec.jsx",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.spec.tsx"
|
||||
],
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts", "src/**/*.json"],
|
||||
"references": [{ "path": "../payload" }] // db-postgres depends on payload
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user