Skip to content

Commit

Permalink
feat: SQL Database support (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjholm authored Jul 11, 2024
1 parent bb77c58 commit b4d9c27
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ jobs:
# Run tox using the version of Python in `PATH`
run: tox -e py
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
continue-on-error: true
uses: codecov/[email protected]
with:
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
.nitric/
nitric.yaml
nitric.*.yaml
proto/
/proto/
/nitric/proto/KeyValue

# Byte-compiled / optimized / DLL files
__pycache__/
Expand Down
2 changes: 1 addition & 1 deletion makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ test:
@echo Running Tox tests
@tox -e py

NITRIC_VERSION := 1.1.0
NITRIC_VERSION := 1.6.0

download-local:
@rm -r ./proto/nitric
Expand Down
1 change: 1 addition & 0 deletions nitric/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Nitric:
"websocket": {},
"keyvaluestore": {},
"oidcsecuritydefinition": {},
"sql": {},
}

@classmethod
Expand Down
12 changes: 11 additions & 1 deletion nitric/proto/deployments/v1/__init__.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions nitric/proto/resources/v1/__init__.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file added nitric/proto/sql/__init__.py
Empty file.
77 changes: 77 additions & 0 deletions nitric/proto/sql/v1/__init__.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions nitric/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from nitric.resources.topics import Topic, topic
from nitric.resources.websockets import Websocket, websocket
from nitric.resources.queues import Queue, queue
from nitric.resources.sql import Sql, sql

__all__ = [
"api",
Expand All @@ -44,6 +45,8 @@
"schedule",
"secret",
"Secret",
"sql",
"Sql",
"topic",
"Topic",
"websocket",
Expand Down
84 changes: 84 additions & 0 deletions nitric/resources/sql.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#
# Copyright (c) 2021 Nitric Technologies Pty Ltd.
#
# This file is part of Nitric Python 3 SDK.
# See https://github.com/nitrictech/python-sdk for further info.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import annotations

from typing import Union

from grpclib import GRPCError
from grpclib.client import Channel

from nitric.exception import exception_from_grpc_error
from nitric.proto.resources.v1 import (
SqlDatabaseResource,
SqlDatabaseMigrations,
ResourceDeclareRequest,
ResourceIdentifier,
ResourceType,
)
from nitric.resources.resource import Resource as BaseResource
from nitric.utils import new_default_channel
from nitric.application import Nitric

from nitric.proto.sql.v1 import SqlStub, SqlConnectionStringRequest


class Sql(BaseResource):
"""A SQL Database."""

_channel: Channel
_sql_stub: SqlStub
name: str
migrations: Union[str, None]

def __init__(self, name: str, migrations: Union[str, None] = None):
"""Construct a new SQL Database."""
super().__init__(name)

self._channel: Union[Channel, None] = new_default_channel()
self._sql_stub = SqlStub(channel=self._channel)
self.name = name
self.migrations = migrations

async def _register(self) -> None:
try:
await self._resources_stub.declare(
resource_declare_request=ResourceDeclareRequest(
id=ResourceIdentifier(name=self.name, type=ResourceType.SqlDatabase),
sql_database=SqlDatabaseResource(
migrations=SqlDatabaseMigrations(migrations_path=self.migrations if self.migrations else "")
),
),
)
except GRPCError as grpc_err:
raise exception_from_grpc_error(grpc_err) from grpc_err

async def connection_string(self) -> str:
"""Return the connection string for this SQL Database."""
response = await self._sql_stub.connection_string(SqlConnectionStringRequest(database_name=self.name))

return response.connection_string


def sql(name: str, migrations: Union[str, None] = None) -> Sql:
"""
Create and register a sql database.
If a sql databse has already been registered with the same name, the original reference will be reused.
"""
return Nitric._create_resource(Sql, name, migrations)
61 changes: 61 additions & 0 deletions tests/resources/test_sql.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#
# Copyright (c) 2021 Nitric Technologies Pty Ltd.
#
# This file is part of Nitric Python 3 SDK.
# See https://github.com/nitrictech/python-sdk for further info.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from unittest import IsolatedAsyncioTestCase
from unittest.mock import AsyncMock, Mock, patch

import pytest

from nitric.proto.resources.v1 import (
ResourceDeclareRequest,
ResourceIdentifier,
ResourceType,
SqlDatabaseResource,
)
from nitric.resources import sql

# pylint: disable=protected-access,missing-function-docstring,missing-class-docstring


class Object(object):
pass


class MockAsyncChannel:
def __init__(self):
self.send = AsyncMock()
self.close = Mock()
self.done = Mock()


class SqlTest(IsolatedAsyncioTestCase):
def test_declare_sql(self):
mock_declare = AsyncMock()
mock_response = Object()
mock_declare.return_value = mock_response

with patch("nitric.proto.resources.v1.ResourcesStub.declare", mock_declare):
sqldb = sql("test-sql")

# Check expected values were passed to Stub
mock_declare.assert_called_with(
resource_declare_request=ResourceDeclareRequest(
id=ResourceIdentifier(name="test-sql", type=ResourceType.SqlDatabase),
sql_database=SqlDatabaseResource(),
)
)

0 comments on commit b4d9c27

Please sign in to comment.