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:
parent
f249be392f
commit
2c897aea2a
3 changed files with 23 additions and 31 deletions
|
@ -7,13 +7,14 @@ import type { Arguments } from 'yargs-parser';
|
||||||
import { appTokenError } from '../../../errors.js';
|
import { appTokenError } from '../../../errors.js';
|
||||||
import { collectionToTable, createLocalDatabaseClient } from '../../../internal.js';
|
import { collectionToTable, createLocalDatabaseClient } from '../../../internal.js';
|
||||||
import {
|
import {
|
||||||
|
createCurrentSnapshot,
|
||||||
createEmptySnapshot,
|
createEmptySnapshot,
|
||||||
getMigrations,
|
getMigrations,
|
||||||
initializeFromMigrations,
|
initializeFromMigrations,
|
||||||
loadInitialSnapshot,
|
loadInitialSnapshot,
|
||||||
loadMigration,
|
loadMigration,
|
||||||
} from '../../../migrations.js';
|
} from '../../../migrations.js';
|
||||||
import type { DBCollections } from '../../../types.js';
|
import type { DBCollections, DBSnapshot } from '../../../types.js';
|
||||||
import {
|
import {
|
||||||
STUDIO_ADMIN_TABLE_ROW_ID,
|
STUDIO_ADMIN_TABLE_ROW_ID,
|
||||||
adminTable,
|
adminTable,
|
||||||
|
@ -30,9 +31,7 @@ export async function cmd({ config, flags }: { config: AstroConfig; flags: Argum
|
||||||
const isSeedData = flags.seed;
|
const isSeedData = flags.seed;
|
||||||
const isDryRun = flags.dryRun;
|
const isDryRun = flags.dryRun;
|
||||||
const appToken = flags.token ?? getAstroStudioEnv().ASTRO_STUDIO_APP_TOKEN;
|
const appToken = flags.token ?? getAstroStudioEnv().ASTRO_STUDIO_APP_TOKEN;
|
||||||
|
const currentSnapshot = createCurrentSnapshot(config);
|
||||||
const currentDb: DBCollections = (config.db?.collections ?? {}) as DBCollections;
|
|
||||||
const currentSnapshot = JSON.parse(JSON.stringify(currentDb));
|
|
||||||
const allMigrationFiles = await getMigrations();
|
const allMigrationFiles = await getMigrations();
|
||||||
if (allMigrationFiles.length === 0) {
|
if (allMigrationFiles.length === 0) {
|
||||||
console.log('Project not yet initialized!');
|
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);
|
const calculatedDiff = diff(prevSnapshot, currentSnapshot);
|
||||||
if (calculatedDiff) {
|
if (calculatedDiff) {
|
||||||
console.log('Changes detected!');
|
console.log('Changes detected!');
|
||||||
|
console.log(calculatedDiff);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ export async function cmd({ config, flags }: { config: AstroConfig; flags: Argum
|
||||||
}
|
}
|
||||||
if (isSeedData) {
|
if (isSeedData) {
|
||||||
console.info('Pushing data...');
|
console.info('Pushing data...');
|
||||||
await tempDataPush({ currentDb, appToken, isDryRun });
|
await pushData({ config, appToken, isDryRun });
|
||||||
}
|
}
|
||||||
console.info('Push complete!');
|
console.info('Push complete!');
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ async function pushSchema({
|
||||||
appToken: string;
|
appToken: string;
|
||||||
isDryRun: boolean;
|
isDryRun: boolean;
|
||||||
db: ReturnType<typeof createRemoteDatabaseClient>;
|
db: ReturnType<typeof createRemoteDatabaseClient>;
|
||||||
currentSnapshot: DBCollections;
|
currentSnapshot: DBSnapshot;
|
||||||
}) {
|
}) {
|
||||||
// load all missing migrations
|
// load all missing migrations
|
||||||
const initialSnapshot = migrations.find((m) => m === '0000_snapshot.json');
|
const initialSnapshot = migrations.find((m) => m === '0000_snapshot.json');
|
||||||
|
@ -120,28 +120,26 @@ async function pushSchema({
|
||||||
}
|
}
|
||||||
|
|
||||||
/** TODO: refine with migration changes */
|
/** TODO: refine with migration changes */
|
||||||
async function tempDataPush({
|
async function pushData({
|
||||||
currentDb,
|
config,
|
||||||
appToken,
|
appToken,
|
||||||
isDryRun,
|
isDryRun,
|
||||||
}: {
|
}: {
|
||||||
currentDb: DBCollections;
|
config: AstroConfig;
|
||||||
appToken: string;
|
appToken: string;
|
||||||
isDryRun?: boolean;
|
isDryRun?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const db = await createLocalDatabaseClient({
|
const db = await createLocalDatabaseClient({
|
||||||
collections: JSON.parse(JSON.stringify(currentDb)),
|
collections: config.db!.collections! as DBCollections,
|
||||||
dbUrl: ':memory:',
|
dbUrl: ':memory:',
|
||||||
seeding: true,
|
seeding: true,
|
||||||
});
|
});
|
||||||
const queries: Query[] = [];
|
const queries: Query[] = [];
|
||||||
|
|
||||||
for (const [name, collection] of Object.entries(currentDb)) {
|
for (const [name, collection] of Object.entries(config.db!.collections! as DBCollections)) {
|
||||||
console.log(name, collection);
|
|
||||||
if (collection.writable || !collection.data) continue;
|
if (collection.writable || !collection.data) continue;
|
||||||
const table = collectionToTable(name, collection);
|
const table = collectionToTable(name, collection);
|
||||||
const insert = db.insert(table).values(await collection.data());
|
const insert = db.insert(table).values(await collection.data());
|
||||||
|
|
||||||
queries.push(insert.toSQL());
|
queries.push(insert.toSQL());
|
||||||
}
|
}
|
||||||
console.log(queries);
|
console.log(queries);
|
||||||
|
|
|
@ -15,6 +15,7 @@ import type {
|
||||||
import { SQLiteAsyncDialect } from 'drizzle-orm/sqlite-core';
|
import { SQLiteAsyncDialect } from 'drizzle-orm/sqlite-core';
|
||||||
import { customAlphabet } from 'nanoid';
|
import { customAlphabet } from 'nanoid';
|
||||||
import prompts from 'prompts';
|
import prompts from 'prompts';
|
||||||
|
import { hasPrimaryKey } from '../internal.js';
|
||||||
|
|
||||||
const sqlite = new SQLiteAsyncDialect();
|
const sqlite = new SQLiteAsyncDialect();
|
||||||
const genTempTableName = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10);
|
const genTempTableName = customAlphabet('abcdefghijklmnopqrstuvwxyz', 10);
|
||||||
|
@ -408,7 +409,7 @@ export function getCreateTableQuery(collectionName: string, collection: DBCollec
|
||||||
([, field]) => hasPrimaryKey(field)
|
([, field]) => hasPrimaryKey(field)
|
||||||
);
|
);
|
||||||
if (!colHasPrimaryKey) {
|
if (!colHasPrimaryKey) {
|
||||||
colQueries.push('_id INTEGER PRIMARY KEY AUTOINCREMENT');
|
colQueries.push('_id INTEGER PRIMARY KEY');
|
||||||
}
|
}
|
||||||
for (const [columnName, column] of Object.entries(collection.fields)) {
|
for (const [columnName, column] of Object.entries(collection.fields)) {
|
||||||
const colQuery = `${sqlite.escapeName(columnName)} ${schemaTypeToSqlType(
|
const colQuery = `${sqlite.escapeName(columnName)} ${schemaTypeToSqlType(
|
||||||
|
@ -570,10 +571,6 @@ type DBFieldWithDefault =
|
||||||
| WithDefaultDefined<BooleanField>
|
| WithDefaultDefined<BooleanField>
|
||||||
| WithDefaultDefined<JsonField>;
|
| 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
|
// Type narrowing the default fails on union types, so use a type guard
|
||||||
function hasDefault(field: DBField): field is DBFieldWithDefault {
|
function hasDefault(field: DBField): field is DBFieldWithDefault {
|
||||||
if (field.default !== undefined) {
|
if (field.default !== undefined) {
|
||||||
|
|
|
@ -39,6 +39,10 @@ export type { Table } from './types.js';
|
||||||
|
|
||||||
const sqlite = new SQLiteAsyncDialect();
|
const sqlite = new SQLiteAsyncDialect();
|
||||||
|
|
||||||
|
export function hasPrimaryKey(field: DBField) {
|
||||||
|
return 'primaryKey' in field && !!field.primaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
function isReadableCollection(collection: DBCollection): collection is ReadableDBCollection {
|
function isReadableCollection(collection: DBCollection): collection is ReadableDBCollection {
|
||||||
return !collection.writable;
|
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<
|
type D1ColumnBuilder = SQLiteColumnBuilderBase<
|
||||||
ColumnBuilderBaseConfig<ColumnDataType, string> & { data: unknown }
|
ColumnBuilderBaseConfig<ColumnDataType, string> & { data: unknown }
|
||||||
>;
|
>;
|
||||||
|
@ -247,17 +245,14 @@ export function collectionToTable(
|
||||||
collection: DBCollection,
|
collection: DBCollection,
|
||||||
isJsonSerializable = true
|
isJsonSerializable = true
|
||||||
) {
|
) {
|
||||||
const columns: Record<string, D1ColumnBuilder> & typeof initialColumns = {
|
const columns: Record<string, D1ColumnBuilder> = {};
|
||||||
// Spread to avoid mutating `initialColumns`
|
if (!Object.entries(collection.fields).some(([, field]) => hasPrimaryKey(field))) {
|
||||||
...initialColumns,
|
columns['_id'] = integer('_id').primaryKey();
|
||||||
};
|
}
|
||||||
|
|
||||||
for (const [fieldName, field] of Object.entries(collection.fields)) {
|
for (const [fieldName, field] of Object.entries(collection.fields)) {
|
||||||
columns[fieldName] = columnMapper(fieldName, field, isJsonSerializable);
|
columns[fieldName] = columnMapper(fieldName, field, isJsonSerializable);
|
||||||
}
|
}
|
||||||
|
|
||||||
const table = sqliteTable(name, columns);
|
const table = sqliteTable(name, columns);
|
||||||
|
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,11 +271,13 @@ function columnMapper(fieldName: string, field: DBField, isJsonSerializable: boo
|
||||||
// Duplicate default logic across cases to preserve type inference.
|
// Duplicate default logic across cases to preserve type inference.
|
||||||
// No clean generic for every column builder.
|
// No clean generic for every column builder.
|
||||||
if (field.default !== undefined) c = c.default(field.default);
|
if (field.default !== undefined) c = c.default(field.default);
|
||||||
|
if (field.primaryKey === true) c = c.primaryKey();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'number': {
|
case 'number': {
|
||||||
c = integer(fieldName);
|
c = integer(fieldName);
|
||||||
if (field.default !== undefined) c = c.default(field.default);
|
if (field.default !== undefined) c = c.default(field.default);
|
||||||
|
if (field.primaryKey === true) c = c.primaryKey({autoIncrement: true});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'boolean': {
|
case 'boolean': {
|
||||||
|
|
Loading…
Add table
Reference in a new issue