{ "info": { "author": "Elad Kehat", "author_email": "eladkehat@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.7", "Topic :: Database", "Typing :: Typed" ], "description": "# Soong - PostgreSQL utility library for AWS Lambda\n\nThe purpose of this library is to let Lambda functions connect to PostgreSQL on RDS and run queries against it.\n\n\u26a0\ufe0f Soong is currently in active development and should be considered work in progress. Do not use in production! \u26a0\ufe0f\n\n\n## How working with a relational DB on Lambda is different\n\n1. [Authentication](#authentication)\n1. [Connection Reuse](#connection-reuse)\n1. [Resource Constraints](#resource-constraints)\n\n\n### Authentication\n\n#### Non-Secret Parameters\nDatabase connection parameters, such as the host, port, database name and user name, should be passed to your lambda\nfunctions using environment variables. Soong supports this pattern by automatically detecting those variables.\n\nIf you are using [SAM](https://aws.amazon.com/serverless/sam/), you can assign those parameters to all of your\nfunctions in the global section of the template, as shown below. Soong will pick these variables automatically.\n```yaml\nGlobals:\n Function:\n Environment:\n Variables:\n PG_HOST: \"postgres1.abcde123.us-east-1.rds.amazonaws.com\"\n PG_DBNAME: database1\n PG_USER: jane_doe\n```\n\n#### Password\nA database password however, **should not be used at all!** Instead, use IAM authentication, as explained in the\n[RDS user guide](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html).\n\nSoong supports this authentication pattern by automatically generating an auth token when running in the Lambda\nenvironment.\n\nIn order to enable this pattern, you must:\n1. Enable IAM db authentication for your RDS instance\n([user guide](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Enabling.html)).\n1. Create a database user that uses IAM authentication\n([user guide](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.DBAccounts.html)).\nYou can also `GRANT rds_iam` to an existing user.\n1. Create an IAM policy for IAM database access\n([user guide](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html)).\nMake sure that the policy covers the user from the previous step.\n1. Assign that policy to the role under which your functions execute\n([user guide](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html?shortFooter=true)).\n\nFinally, you must use RDS API to generate an auth-token to use in place of a password. Soong does that for you\nbehind the scenes whenever you create a connection.\n\n#### Code Example\nIf you did all of the above, connecting to the database from your code is now a breeze:\n```python\nimport soong\n# The fancy cursor_factory is optional\nwith soong.connect(cursor_factory=psycopg2.extras.NamedTupleCursor) as conn:\n with conn.cursor() as cursor:\n cursor.execute(\"SELECT 'Hello, world!' AS hello;\")\n assert cursor.fetchone().hello == 'Hello, world!'\n```\n\n### Connection Reuse\nIn server-full applications, it is a best practice to manage a connection pool that lets various modules in the\napplication reuse database connections. When you decompose an application into serverless-style functions,\nthere is usually no point in a connection _pool_, because every function most likely needs just one connection.\nThis is why Soong makes it simple to connect, but does not provide a connection pool.\n\nThis does not mean that there is no connection reuse. Code that runs outside of the _handler_ function gets reused\nif the container remains warm and is reused by another invocation of the function.\n\nMoreover, Soong provides a global connection and makes it simple to initialize it lazily, and reconnect when it's\nclosed. See the code examples below.\n\n\n#### Code Examples\n\n```python\n# A global connection object is defined inside the soong package\nimport soong\n\ndef lambda_handler(event, context):\n with soong.connection() as conn: # Lazy initialization\n # Run some queries inside a transaction\n pass\n```\n\nYou can also control the connection yourself, rather than use Soong's.\nThe code example below shows how to generate the connection at the module scope, outside of the _handler_, so it can\nbe reused:\n```python\nimport soong\n\nconn = soong.connect()\n\ndef lambda_handler(event, context):\n with conn:\n # Run some queries inside a transaction\n pass\n```\n\nNote that you can also generate connections inside the handler if you want them to close rather than remain open for\nreuse. There are some scenarios where this is the better option, such as when your function rarely gets called, so\nthere is no connection reuse in practice, but every invocation keeps a connection hanging for a while, wasting\nresources on your database server.\n\n\n### Resource Constraints\nWith Lambda you pay directly for the CPU/Memory and execution time. Therefore it is important to limit resource\nutilization to the minimum necessary. In addition, code in lambda functions tends to be short and simple.\n\nIn my opinion, with most lambda functions it makes sense to avoid ORM tools, such as\n[SQL Alchemy](https://www.sqlalchemy.org), and opt for a more direct approach that is also more lightweight.\n\nThe Soong `query` and `dml` modules provide some well-documented utility functions that save you from writing a lot\nof boilerplate code in the most common database access use cases.\n\n#### Code Example\n```python\nimport soong\n\n# Get the gizmo with id 42 from the gizmos table\ngizmo42 = soong.query.get(soong.connection(cursor_factory=psycopg2.extras.NamedTupleCursor), 'gizmos', 42)\nprint(f'Got gizmo {gizmo42.name}')\n\n# Now rename it\n# Re-uses the global connection object, that's already been initialized with the cursor_factory\nsoong.dml.update(soong.connection(), 'gizmos', 42, {'name': 'Gizmo42: The Next Generation'})\n\n# Add a new gizmo\nid = soong.dml.insert(soong.connection(),\n 'gizmos', {'name': 'Best gizmo ever!', 'color': 'Bright red'}, returning='id')\n\n# Run a SELECT\nfor gizmo in soong.query.select(soong.connection(), 'gizmos', {'color': 'pink'}):\n print(gizmo.name)\n\n# You can also run an arbitrary query, without the boilerplate\nfor gizmo in soong.query.execute(soong.connection(), 'SELECT * FROM gizmos WHERE color = %s', ('pink', )):\n print(gizmo.name)\n```\n\n\n## Why \"Soong\"?\nThe name is a reference to [Noonien Soong][Noonien Soong article], the human cyberneticist who created\n[Data][Data on Wikipedia], the android character in _Star Trek: The Next Generation_.\n\n[Noonien Soong article]: https://intl.startrek.com/database_article/soong\n[Data on Wikipedia]: https://en.wikipedia.org/wiki/Data_(Star_Trek)\n\n![https://memory-alpha.fandom.com/wiki/Noonian_Soong](https://vignette.wikia.nocookie.net/memoryalpha/images/f/f0/Noonian_Soong_hologram.jpg/revision/latest/scale-to-width-down/411?cb=20141225185733&path-prefix=en)\n\nA hologram of Dr. Soong from around the time of Data's creation\n\nSource: https://memory-alpha.fandom.com/wiki/Noonian_Soong\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/eladkehat/soong", "keywords": "serverless aws labmda postgresql pgsql", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "soong", "package_url": "https://pypi.org/project/soong/", "platform": "", "project_url": "https://pypi.org/project/soong/", "project_urls": { "Homepage": "https://github.com/eladkehat/soong" }, "release_url": "https://pypi.org/project/soong/0.6.0/", "requires_dist": [ "boto3 (~=1.7)", "psycopg2-binary (~=2.7)" ], "requires_python": ">=3.7", "summary": "PostgreSQL utility library for AWS Lambda", "version": "0.6.0" }, "last_serial": 5141145, "releases": { "0.4.1": [ { "comment_text": "", "digests": { "md5": "32f07728948a830033b2c9321e34cdff", "sha256": "64ff649f7dac384745dd7270533219f949f6614d55ed1465d15a4f7c85a3abf7" }, "downloads": -1, "filename": "soong-0.4.1-py3-none-any.whl", "has_sig": false, "md5_digest": "32f07728948a830033b2c9321e34cdff", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 9163, "upload_time": "2019-03-23T16:11:55", "url": "https://files.pythonhosted.org/packages/c5/aa/a7748a2abac18da07e1a27684b4649108e9e312013aa8e53bad1f7d41eaa/soong-0.4.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b77fe6fe5185827ee07c205e430c3794", "sha256": "c622c3571a24857c3c8ebcb4f02e9d6de7762ec794f2fac1f1c614c6218b98ba" }, "downloads": -1, "filename": "soong-0.4.1.tar.gz", "has_sig": false, "md5_digest": "b77fe6fe5185827ee07c205e430c3794", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 12201, "upload_time": "2019-03-23T16:11:57", "url": "https://files.pythonhosted.org/packages/d0/81/aa54d5469c0d1757a1e71c51417a5ca5071c2ee078cf790b3f8642466674/soong-0.4.1.tar.gz" } ], "0.5.0": [ { "comment_text": "", "digests": { "md5": "5e39945022c94407dacc5a3dbee46194", "sha256": "6fd860722225b0c0110e7698c4d8286a1e77485413166613b84681911560591c" }, "downloads": -1, "filename": "soong-0.5.0-py3-none-any.whl", "has_sig": false, "md5_digest": "5e39945022c94407dacc5a3dbee46194", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 9196, "upload_time": "2019-03-25T14:09:29", "url": "https://files.pythonhosted.org/packages/64/3f/f108b7ed1d4c241923204a98c21ca604f02d34857de87daf3beb3a29cc3f/soong-0.5.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "34945ceb603fced42bb8f44257b77e2d", "sha256": "927c87b34f512bd26a2b8a204f065fe50fcc4cc6824717b3123312c79a189fff" }, "downloads": -1, "filename": "soong-0.5.0.tar.gz", "has_sig": false, "md5_digest": "34945ceb603fced42bb8f44257b77e2d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 12227, "upload_time": "2019-03-25T14:09:30", "url": "https://files.pythonhosted.org/packages/69/1f/939e83d38ac84d8269757d291fc934d93f1f3a05744f7ca34f8f8db0404e/soong-0.5.0.tar.gz" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "56ce48e4f064433655ed46df34e37db2", "sha256": "60843863268de690ab14a92bec7628369c2c865aeaf4af8c077dc6571664bf1c" }, "downloads": -1, "filename": "soong-0.6.0-py3-none-any.whl", "has_sig": false, "md5_digest": "56ce48e4f064433655ed46df34e37db2", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 9936, "upload_time": "2019-04-14T15:23:17", "url": "https://files.pythonhosted.org/packages/16/d4/3b2fb6b638a5a5225f8f2c9f78a54f87f5df025d32ea973392586253a84b/soong-0.6.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d8c42b4d5cdb56cb4d19a0eac088d80e", "sha256": "f1bffe94e34efefc927dd92b0c99176d9986c8c77472600898c5ae1563b96f08" }, "downloads": -1, "filename": "soong-0.6.0.tar.gz", "has_sig": false, "md5_digest": "d8c42b4d5cdb56cb4d19a0eac088d80e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 13344, "upload_time": "2019-04-14T15:23:19", "url": "https://files.pythonhosted.org/packages/dc/a6/23c859a0190b3a25e1ab904a5d3295f2939a8cadf0f7728fb3dee5616382/soong-0.6.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "56ce48e4f064433655ed46df34e37db2", "sha256": "60843863268de690ab14a92bec7628369c2c865aeaf4af8c077dc6571664bf1c" }, "downloads": -1, "filename": "soong-0.6.0-py3-none-any.whl", "has_sig": false, "md5_digest": "56ce48e4f064433655ed46df34e37db2", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 9936, "upload_time": "2019-04-14T15:23:17", "url": "https://files.pythonhosted.org/packages/16/d4/3b2fb6b638a5a5225f8f2c9f78a54f87f5df025d32ea973392586253a84b/soong-0.6.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d8c42b4d5cdb56cb4d19a0eac088d80e", "sha256": "f1bffe94e34efefc927dd92b0c99176d9986c8c77472600898c5ae1563b96f08" }, "downloads": -1, "filename": "soong-0.6.0.tar.gz", "has_sig": false, "md5_digest": "d8c42b4d5cdb56cb4d19a0eac088d80e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 13344, "upload_time": "2019-04-14T15:23:19", "url": "https://files.pythonhosted.org/packages/dc/a6/23c859a0190b3a25e1ab904a5d3295f2939a8cadf0f7728fb3dee5616382/soong-0.6.0.tar.gz" } ] }