@@ -35,11 +35,12 @@ import { checkBillingEnabled } from "../gcp/cloudbilling";
3535async function setupSchemaIfNecessary(
3636 instanceId: string,
3737 databaseId: string,
38+ schemaName: string,
3839 options: Options,
3940): Promise<SchemaSetupStatus.GreenField | SchemaSetupStatus.BrownField> {
4041 try {
4142 await setupIAMUsers(instanceId, options);
42- const schemaInfo = await getSchemaMetadata(instanceId, databaseId, DEFAULT_SCHEMA , options);
43+ const schemaInfo = await getSchemaMetadata(instanceId, databaseId, schemaName , options);
4344 switch (schemaInfo.setupStatus) {
4445 case SchemaSetupStatus.BrownField:
4546 case SchemaSetupStatus.GreenField:
@@ -77,12 +78,13 @@ export async function diffSchema(
7778 setSchemaValidationMode(schema, validationMode);
7879 displayStartSchemaDiff(validationMode);
7980
80- const { serviceName, instanceName, databaseId, instanceId } = getIdentifiers(schema);
81+ const { serviceName, instanceName, databaseId, instanceId, schemaName } = getIdentifiers(schema);
8182 await ensureServiceIsConnectedToCloudSql(
8283 serviceName,
8384 instanceName,
8485 databaseId,
8586 /* linkIfNotConnected=*/ false,
87+ schemaName,
8688 );
8789
8890 let incompatible: IncompatibleSqlSchemaError | undefined = undefined;
@@ -162,12 +164,13 @@ export async function migrateSchema(args: {
162164 displayStartSchemaDiff(validationMode);
163165
164166 const projectId = needProjectId(options);
165- const { serviceName, instanceId, instanceName, databaseId } = getIdentifiers(schema);
167+ const { serviceName, instanceId, instanceName, databaseId, schemaName } = getIdentifiers(schema);
166168 await ensureServiceIsConnectedToCloudSql(
167169 serviceName,
168170 instanceName,
169171 databaseId,
170172 /* linkIfNotConnected=*/ true,
173+ schemaName,
171174 );
172175
173176 // Check if Cloud SQL instance is still being created.
@@ -196,7 +199,7 @@ export async function migrateSchema(args: {
196199 }
197200
198201 // Make sure database is setup.
199- await setupSchemaIfNecessary(instanceId, databaseId, options);
202+ await setupSchemaIfNecessary(instanceId, databaseId, schemaName, options);
200203
201204 let diffs: Diff[] = [];
202205 try {
@@ -247,6 +250,7 @@ export async function migrateSchema(args: {
247250 options,
248251 databaseId,
249252 instanceId,
253+ schemaName,
250254 incompatibleSchemaError: incompatible,
251255 choice: migrationMode,
252256 });
@@ -295,6 +299,7 @@ export async function migrateSchema(args: {
295299 options,
296300 databaseId,
297301 instanceId,
302+ schemaName,
298303 incompatibleSchemaError: incompatible,
299304 choice: migrationMode,
300305 });
@@ -349,17 +354,23 @@ export async function grantRoleToUserInSchema(options: Options, schema: Schema)
349354 const role = options.role as string;
350355 const email = options.email as string;
351356
352- const { serviceName, instanceId, instanceName, databaseId } = getIdentifiers(schema);
357+ const { serviceName, instanceId, instanceName, databaseId, schemaName } = getIdentifiers(schema);
353358
354359 await ensureServiceIsConnectedToCloudSql(
355360 serviceName,
356361 instanceName,
357362 databaseId,
358363 /* linkIfNotConnected=*/ false,
364+ schemaName,
359365 );
360366
361367 // Make sure we have the right setup for the requested role grant.
362- const schemaSetupStatus = await setupSchemaIfNecessary(instanceId, databaseId, options);
368+ const schemaSetupStatus = await setupSchemaIfNecessary(
369+ instanceId,
370+ databaseId,
371+ schemaName,
372+ options,
373+ );
363374
364375 // Edge case: we can't grant firebase owner unless database is greenfield.
365376 if (schemaSetupStatus !== SchemaSetupStatus.GreenField && role === "owner") {
@@ -369,7 +380,7 @@ export async function grantRoleToUserInSchema(options: Options, schema: Schema)
369380 }
370381
371382 // Grant the role to the user.
372- await grantRoleTo(options, instanceId, databaseId, role, email);
383+ await grantRoleTo(options, instanceId, databaseId, role, email, schemaName );
373384}
374385
375386function diffsEqual(x: Diff[], y: Diff[]): boolean {
@@ -399,6 +410,7 @@ export function getIdentifiers(schema: Schema): {
399410 instanceName: string;
400411 instanceId: string;
401412 databaseId: string;
413+ schemaName: string;
402414 serviceName: string;
403415} {
404416 const postgresDatasource = schema.datasources.find((d) => d.postgresql);
@@ -415,11 +427,13 @@ export function getIdentifiers(schema: Schema): {
415427 );
416428 }
417429 const instanceId = instanceName.split("/").pop()!;
430+ const schemaName = postgresDatasource?.postgresql?.schema || DEFAULT_SCHEMA;
418431 const serviceName = serviceNameFromSchema(schema);
419432 return {
420433 databaseId,
421434 instanceId,
422435 instanceName,
436+ schemaName,
423437 serviceName,
424438 };
425439}
@@ -442,9 +456,10 @@ async function handleIncompatibleSchemaError(args: {
442456 options: Options;
443457 instanceId: string;
444458 databaseId: string;
459+ schemaName: string;
445460 choice: "all" | "safe" | "none";
446461}): Promise<Diff[]> {
447- const { incompatibleSchemaError, options, instanceId, databaseId, choice } = args;
462+ const { incompatibleSchemaError, options, instanceId, databaseId, schemaName, choice } = args;
448463 const commandsToExecute = incompatibleSchemaError.diffs.filter((d) => {
449464 switch (choice) {
450465 case "all":
@@ -467,7 +482,7 @@ async function handleIncompatibleSchemaError(args: {
467482 ${diffsToString(commandsToExecuteBySuperUser)}`);
468483 }
469484
470- const schemaInfo = await getSchemaMetadata(instanceId, databaseId, DEFAULT_SCHEMA , options);
485+ const schemaInfo = await getSchemaMetadata(instanceId, databaseId, schemaName , options);
471486 if (schemaInfo.setupStatus !== SchemaSetupStatus.GreenField) {
472487 throw new FirebaseError(
473488 `Brownfield database are protected from SQL changes by Data Connect.\n` +
@@ -482,7 +497,7 @@ async function handleIncompatibleSchemaError(args: {
482497 options,
483498 instanceId,
484499 databaseId,
485- firebaseowner(databaseId),
500+ firebaseowner(databaseId, schemaName ),
486501 (await getIAMUser(options)).user,
487502 ))
488503 ) {
@@ -493,7 +508,7 @@ async function handleIncompatibleSchemaError(args: {
493508 }
494509 const account = (await requireAuth(options))!;
495510 logLabeledBullet("dataconnect", `Granting firebaseowner role to myself ${account}...`);
496- await grantRoleTo(options, instanceId, databaseId, "owner", account);
511+ await grantRoleTo(options, instanceId, databaseId, "owner", account, schemaName );
497512 }
498513
499514 if (commandsToExecuteBySuperUser.length) {
@@ -512,7 +527,10 @@ async function handleIncompatibleSchemaError(args: {
512527 options,
513528 instanceId,
514529 databaseId,
515- [`SET ROLE "${firebaseowner(databaseId)}"`, ...commandsToExecuteByOwner.map((d) => d.sql)],
530+ [
531+ `SET ROLE "${firebaseowner(databaseId, schemaName)}"`,
532+ ...commandsToExecuteByOwner.map((d) => d.sql),
533+ ],
516534 /** silent=*/ false,
517535 );
518536 return incompatibleSchemaError.diffs;
@@ -645,6 +663,7 @@ export async function ensureServiceIsConnectedToCloudSql(
645663 instanceName: string,
646664 databaseId: string,
647665 linkIfNotConnected: boolean,
666+ schemaName?: string,
648667): Promise<void> {
649668 let currentSchema = await getSchema(serviceName);
650669 let postgresql = currentSchema?.datasources?.find((d) => d.postgresql)?.postgresql;
@@ -720,6 +739,7 @@ export async function ensureServiceIsConnectedToCloudSql(
720739 try {
721740 postgresql.schemaValidation = "STRICT";
722741 postgresql.database = databaseId;
742+ postgresql.schema = schemaName;
723743 postgresql.cloudSql = { instance: instanceName };
724744 await upsertSchema(currentSchema, /** validateOnly=*/ false);
725745 } catch (err: any) {
0 commit comments