0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-03-03 22:57:08 -05:00

cleanup primary key support, db push

This commit is contained in:
Fred K. Schott 2024-01-25 03:00:56 -08:00
parent f249be392f
commit 2c897aea2a
3 changed files with 23 additions and 31 deletions

View file

@ -7,13 +7,14 @@ import type { Arguments } from 'yargs-parser';
import { appTokenError } from '../../../errors.js';
import { collectionToTable, createLocalDatabaseClient } from '../../../internal.js';
import {
createCurrentSnapshot,
createEmptySnapshot,
getMigrations,
initializeFromMigrations,
loadInitialSnapshot,
loadMigration,
} from '../../../migrations.js';
import type { DBCollections } from '../../../types.js';
import type { DBCollections, DBSnapshot } from '../../../types.js';
import {
STUDIO_ADMIN_TABLE_ROW_ID,
adminTable,
@ -30,9 +31,7 @@ export async function cmd({ config, flags }: { config: AstroConfig; flags: Argum
const isSeedData = flags.seed;
const isDryRun = flags.dryRun;
const appToken = flags.token ?? getAstroStudioEnv().ASTRO_STUDIO_APP_TOKEN;
const currentDb: DBCollections = (config.db?.collections ?? {}) as DBCollections;
const currentSnapshot = JSON.parse(JSON.stringify(currentDb));
const currentSnapshot = createCurrentSnapshot(config);
const allMigrationFiles = await getMigrations();
if (allMigrationFiles.length === 0) {
console.log('Project not yet initialized!');
@ -43,6 +42,7 @@ export async function cmd({ config, flags }: { config: AstroConfig; flags: Argum
const calculatedDiff = diff(prevSnapshot, currentSnapshot);
if (calculatedDiff) {
console.log('Changes detected!');
console.log(calculatedDiff);
process.exit(1);
}
@ -74,7 +74,7 @@ export async function cmd({ config, flags }: { config: AstroConfig; flags: Argum
}
if (isSeedData) {
console.info('Pushing data...');
await tempDataPush({ currentDb, appToken, isDryRun });
await pushData({ config, appToken, isDryRun });
}
console.info('Push complete!');
}
@ -90,7 +90,7 @@ async function pushSchema({
appToken: string;
isDryRun: boolean;
db: ReturnType<typeof createRemoteDatabaseClient>;
currentSnapshot: DBCollections;
currentSnapshot: DBSnapshot;
}) {
// load all missing migrations
const initialSnapshot = migrations.find((m) => m === '0000_snapshot.json');
@ -120,28 +120,26 @@ async function pushSchema({
}
/** TODO: refine with migration changes */
async function tempDataPush({
currentDb,
async function pushData({
config,
appToken,
isDryRun,
}: {
currentDb: DBCollections;
config: AstroConfig;
appToken: string;
isDryRun?: boolean;
}) {
const db = await createLocalDatabaseClient({
collections: JSON.parse(JSON.stringify(currentDb)),
collections: config.db!.collections! as DBCollections,
dbUrl: ':memory:',
seeding: true,
});
const queries: Query[] = [];
for (const [name, collection] of Object.entries(currentDb)) {
console.log(name, collection);
for (const [name, collection] of Object.entries(config.db!.collections! as DBCollections)) {
if (collection.writable || !collection.data) continue;
const table = collectionToTable(name, collection);
const insert = db.insert(table).values(await collection.data());
queries.push(insert.toSQL());
}
console.log(queries);

View file

@ -15,6 +15,7 @@ import type {
import { SQLiteAsyncDialect } from 'drizzle-orm/sqlite-core';
import { customAlphabet } from 'nanoid';
import prompts from 'prompts';
import { hasPrimaryKey } from '../internal.js';
const sqlite = new SQLiteAsyncDialect();
const genTempTableName = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10);
@ -408,7 +409,7 @@ export function getCreateTableQuery(collectionName: string, collection: DBCollec
([, field]) => hasPrimaryKey(field)
);
if (!colHasPrimaryKey) {
colQueries.push('_id INTEGER PRIMARY KEY AUTOINCREMENT');
colQueries.push('_id INTEGER PRIMARY KEY');
}
for (const [columnName, column] of Object.entries(collection.fields)) {
const colQuery = `${sqlite.escapeName(columnName)} ${schemaTypeToSqlType(
@ -570,10 +571,6 @@ type DBFieldWithDefault =
| WithDefaultDefined<BooleanField>
| WithDefaultDefined<JsonField>;
function hasPrimaryKey(field: DBField) {
return 'primaryKey' in field && !!field.primaryKey;
}
// Type narrowing the default fails on union types, so use a type guard
function hasDefault(field: DBField): field is DBFieldWithDefault {
if (field.default !== undefined) {

View file

@ -39,6 +39,10 @@ export type { Table } from './types.js';
const sqlite = new SQLiteAsyncDialect();
export function hasPrimaryKey(field: DBField) {
return 'primaryKey' in field && !!field.primaryKey;
}
function isReadableCollection(collection: DBCollection): collection is ReadableDBCollection {
return !collection.writable;
}
@ -232,12 +236,6 @@ const jsonType = customType<{ data: unknown; driverData: string }>({
},
});
const initialColumns = {
id: text('id')
.primaryKey()
.$default(() => generateId()),
};
type D1ColumnBuilder = SQLiteColumnBuilderBase<
ColumnBuilderBaseConfig<ColumnDataType, string> & { data: unknown }
>;
@ -247,17 +245,14 @@ export function collectionToTable(
collection: DBCollection,
isJsonSerializable = true
) {
const columns: Record<string, D1ColumnBuilder> & typeof initialColumns = {
// Spread to avoid mutating `initialColumns`
...initialColumns,
};
const columns: Record<string, D1ColumnBuilder> = {};
if (!Object.entries(collection.fields).some(([, field]) => hasPrimaryKey(field))) {
columns['_id'] = integer('_id').primaryKey();
}
for (const [fieldName, field] of Object.entries(collection.fields)) {
columns[fieldName] = columnMapper(fieldName, field, isJsonSerializable);
}
const table = sqliteTable(name, columns);
return table;
}
@ -276,11 +271,13 @@ function columnMapper(fieldName: string, field: DBField, isJsonSerializable: boo
// Duplicate default logic across cases to preserve type inference.
// No clean generic for every column builder.
if (field.default !== undefined) c = c.default(field.default);
if (field.primaryKey === true) c = c.primaryKey();
break;
}
case 'number': {
c = integer(fieldName);
if (field.default !== undefined) c = c.default(field.default);
if (field.primaryKey === true) c = c.primaryKey({autoIncrement: true});
break;
}
case 'boolean': {