Skip to content

Node wrapper poc#785

Draft
surbhigarg92 wants to merge 8 commits intomainfrom
node-wrapper-poc
Draft

Node wrapper poc#785
surbhigarg92 wants to merge 8 commits intomainfrom
node-wrapper-poc

Conversation

@surbhigarg92
Copy link
Copy Markdown

No description provided.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces three different proof-of-concept (POC) implementations for a Node.js wrapper for the Go Spanner library: an IPC-based gRPC wrapper, a Koffi-based FFI wrapper, and an N-API C++ wrapper. The changes include build scripts, setup utilities, and test suites for each approach. My feedback highlights several critical and high-severity issues, including hardcoded infrastructure paths and credentials, missing cross-platform support in build configurations, and the need for better error handling and code modularity across the POCs.

Comment on lines 31 to 40
--plugin=protoc-gen-java-grpc=/Users/loite/protoc-gen-grpc-java-1.75.0-osx-aarch_64.exe \
--java-grpc_out=../../wrappers/spannerlib-java/src/main/java/ \
--java-grpc_opt=paths=source_relative \
google/spannerlib/v1/spannerlib.proto

# dotnet add package Grpc.Tools --version 2.76.0
# 4. C# generation
echo "Generating C#..."
protoc \
--csharp_out=../../wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/ \
--plugin=protoc-gen-csharp_grpc=/Users/loite/.nuget/packages/grpc.tools/2.76.0/tools/macosx_x64/grpc_csharp_plugin \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The script contains hardcoded paths to protoc plugins, which makes it non-portable and specific to a single user's machine (/Users/loite/...). This will cause the script to fail for other developers or in CI/CD environments.

To improve this, consider one of the following approaches:

  1. Rely on PATH: Require developers to have the protoc-gen-* executables in their PATH.
  2. Use Environment Variables: Allow developers to specify the path to the plugins via environment variables.
  3. Local Installation: Add a step to download and install the required plugins locally within the project or use a package manager that handles this.

Comment on lines +3 to +4
const projectId = 'span-cloud-testing';
const instanceId = 'gargsurbhi-testing';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The projectId and instanceId are hardcoded. This makes the setup script not portable and tightly coupled to a specific GCP project and Spanner instance. It's better to read these values from environment variables to allow other developers to run the tests against their own infrastructure.

For example:

const projectId = process.env.GCP_PROJECT_ID || 'span-cloud-testing';
const instanceId = process.env.SPANNER_INSTANCE_ID || 'gargsurbhi-testing';

This provides a default but allows for easy overriding.

Suggested change
const projectId = 'span-cloud-testing';
const instanceId = 'gargsurbhi-testing';
const projectId = process.env.GCP_PROJECT_ID || 'span-cloud-testing';
const instanceId = process.env.SPANNER_INSTANCE_ID || 'gargsurbhi-testing';

Comment on lines +3 to +5
const projectId = 'span-cloud-testing';
const instanceId = 'gargsurbhi-testing';
const databaseId = `test-db-koffi-${Math.floor(Math.random() * 1000)}`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There are two issues here:

  1. The projectId and instanceId are hardcoded. This makes the setup script not portable. These should be read from environment variables.
  2. The databaseId is generated with the prefix test-db-koffi-. This seems like a copy-paste error from the koffi POC. It should be test-db-napi- to be consistent with this N-API POC.
Suggested change
const projectId = 'span-cloud-testing';
const instanceId = 'gargsurbhi-testing';
const databaseId = `test-db-koffi-${Math.floor(Math.random() * 1000)}`;
const projectId = process.env.GCP_PROJECT_ID || 'span-cloud-testing';
const instanceId = process.env.SPANNER_INSTANCE_ID || 'gargsurbhi-testing';
const databaseId = `test-db-napi-${Math.floor(Math.random() * 1000)}`;

Comment on lines +3 to +4
const projectId = 'span-cloud-testing';
const instanceId = 'gargsurbhi-testing';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The projectId and instanceId are hardcoded. This makes the setup script not portable and tightly coupled to a specific GCP project and Spanner instance. It's better to read these values from environment variables to allow other developers to run the tests against their own infrastructure.

For example:

const projectId = process.env.GCP_PROJECT_ID || 'span-cloud-testing';
const instanceId = process.env.SPANNER_INSTANCE_ID || 'gargsurbhi-testing';

This provides a default but allows for easy overriding.

Suggested change
const projectId = 'span-cloud-testing';
const instanceId = 'gargsurbhi-testing';
const projectId = process.env.GCP_PROJECT_ID || 'span-cloud-testing';
const instanceId = process.env.SPANNER_INSTANCE_ID || 'gargsurbhi-testing';

Comment on lines +23 to +42
"conditions": [
["OS=='mac'", {
"libraries": [
"<(module_root_dir)/../../../shared/libspanner.so"
],
"xcode_settings": {
"OTHER_LDFLAGS": [
"-Wl,-rpath,<(module_root_dir)/../../../shared"
]
}
}],
["OS=='linux'", {
"libraries": [
"<(module_root_dir)/../../../shared/libspanner.so"
],
"ldflags": [
"-Wl,-rpath,'$$ORIGIN/../../../shared'"
]
}]
]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The build configuration is missing a condition for Windows (OS=='win'). This will cause the build to fail on Windows platforms. You should add a condition for Windows to specify the correct library name (libspanner.dll) and linker settings.

const path = require('path');

// Dynamically locate the actual compiled Go shared library
const libPath = path.resolve(__dirname, '../../../../../shared/libspanner.so');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The path to the shared library is hardcoded to use the .so extension, which is specific to Linux. This will fail on other operating systems like macOS (.dylib) or Windows (.dll). To make this cross-platform, you should determine the correct extension based on process.platform.

For example:

const getLibraryPath = () => {
  const root = path.resolve(__dirname, '../../../../../shared');
  switch (process.platform) {
    case 'darwin':
      return path.join(root, 'libspanner.dylib');
    case 'win32':
      return path.join(root, 'libspanner.dll');
    default:
      return path.join(root, 'libspanner.so');
  }
};
const libPath = getLibraryPath();

// The SpannerLib service definition is now available through the descriptor
const SpannerLib = protoDescriptor.google.spannerlib.v1.SpannerLib;

const client = new SpannerLib('localhost:50051', grpc.credentials.createInsecure());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The gRPC server address is hardcoded to localhost:50051. This limits flexibility. It's better to make this configurable via an environment variable, so the client can connect to a server running on a different host or port.

For example:

const GRPC_SERVER_ADDRESS = process.env.GRPC_SERVER_ADDRESS || 'localhost:50051';
const client = new SpannerLib(GRPC_SERVER_ADDRESS, grpc.credentials.createInsecure());
Suggested change
const client = new SpannerLib('localhost:50051', grpc.credentials.createInsecure());
const GRPC_SERVER_ADDRESS = process.env.GRPC_SERVER_ADDRESS || 'localhost:50051';
const client = new SpannerLib(GRPC_SERVER_ADDRESS, grpc.credentials.createInsecure());

let dbName = "dummy-testing-db";
try {
dbName = fs.readFileSync('./test-db.txt', 'utf8').trim();
} catch (e) { }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The catch block is empty, which swallows any errors that might occur when reading test-db.txt. This can make debugging difficult. It's better to log a message indicating that the file was not found and a default is being used.

For example:

} catch (e) {
  console.log('test-db.txt not found, using default. Run `npm run setup` to create a new test database.');
}
Suggested change
} catch (e) { }
} catch (e) { console.log("test-db.txt not found, using default. Run `npm run setup` to create a new test database."); }

let dbName = "dummy-testing-db";
try {
dbName = fs.readFileSync('./test-db.txt', 'utf8').trim();
} catch (e) { }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The catch block is empty, which swallows any errors that might occur when reading test-db.txt. This can make debugging difficult. It's better to log a message indicating that the file was not found and a default is being used.

For example:

} catch (e) {
  console.log('test-db.txt not found, using default. Run `npm run setup` to create a new test database.');
}
Suggested change
} catch (e) { }
} catch (e) { console.log("test-db.txt not found, using default. Run `npm run setup` to create a new test database."); }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant