summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-04-20 13:39:18 +0200
committerChristian Grothoff <christian@grothoff.org>2020-04-20 13:39:18 +0200
commit64cc6eb8c6ed4b7867c76f57c7762414ab4d0685 (patch)
tree0fe7ae499fa9b43b85765192eb515358920d1ff6 /src
parent458dc3653b4aef54130c580fd41610aa03f61d68 (diff)
downloadmerchant-64cc6eb8c6ed4b7867c76f57c7762414ab4d0685.tar.gz
merchant-64cc6eb8c6ed4b7867c76f57c7762414ab4d0685.tar.bz2
merchant-64cc6eb8c6ed4b7867c76f57c7762414ab4d0685.zip
backenddb implementation work
Diffstat (limited to 'src')
-rw-r--r--src/backend/taler-merchant-httpd_private-get-products-ID.c4
-rw-r--r--src/backend/taler-merchant-httpd_private-get-products.c3
-rw-r--r--src/backend/taler-merchant-httpd_private-patch-products-ID.c6
-rw-r--r--src/backend/taler-merchant-httpd_private-post-products.c8
-rw-r--r--src/backenddb/plugin_merchantdb_postgres.c346
-rw-r--r--src/include/taler_merchantdb_plugin.h7
6 files changed, 348 insertions, 26 deletions
diff --git a/src/backend/taler-merchant-httpd_private-get-products-ID.c b/src/backend/taler-merchant-httpd_private-get-products-ID.c
index 85358ff8..57b3182c 100644
--- a/src/backend/taler-merchant-httpd_private-get-products-ID.c
+++ b/src/backend/taler-merchant-httpd_private-get-products-ID.c
@@ -79,8 +79,8 @@ TMH_private_get_products_ID (const struct TMH_RequestHandler *rh,
(json_int_t) pd.total_lost,
"description_i18n",
pd.description_i18n,
- "location",
- pd.location,
+ "address",
+ pd.address,
"image",
pd.image);
GNUNET_free (pd.description);
diff --git a/src/backend/taler-merchant-httpd_private-get-products.c b/src/backend/taler-merchant-httpd_private-get-products.c
index 8f70c9fe..21729a59 100644
--- a/src/backend/taler-merchant-httpd_private-get-products.c
+++ b/src/backend/taler-merchant-httpd_private-get-products.c
@@ -26,21 +26,18 @@
* Add product details to our JSON array.
*
* @param cls a `json_t *` JSON array to build
- * @param key unused
* @param product_id ID of the product
* @param in_stock how many are currently in stock (possibly locked), -1 for infinite
* @param unit in which unit is the stock measured in
*/
static void
add_product (void *cls,
- const struct GNUNET_HashCode *key,
const char *product_id,
long long in_stock,
const char *unit)
{
json_t *pa = cls;
- (void) key;
GNUNET_assert (0 ==
json_array_append_new (
pa,
diff --git a/src/backend/taler-merchant-httpd_private-patch-products-ID.c b/src/backend/taler-merchant-httpd_private-patch-products-ID.c
index fd5a6c1e..6821d3d3 100644
--- a/src/backend/taler-merchant-httpd_private-patch-products-ID.c
+++ b/src/backend/taler-merchant-httpd_private-patch-products-ID.c
@@ -101,7 +101,7 @@ determine_cause (struct MHD_Connection *connection,
GNUNET_free (pdx.unit);
json_decref (pdx.taxes);
json_decref (pdx.image);
- json_decref (pdx.location);
+ json_decref (pdx.address);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_CONFLICT,
ec,
@@ -141,8 +141,8 @@ TMH_private_patch_products_ID (const struct TMH_RequestHandler *rh,
&pd.image),
GNUNET_JSON_spec_json ("taxes",
&pd.taxes),
- GNUNET_JSON_spec_json ("location",
- &pd.taxes),
+ GNUNET_JSON_spec_json ("address",
+ &pd.address),
GNUNET_JSON_spec_int64 ("total_stocked",
&total_stocked),
GNUNET_JSON_spec_absolute_time ("next_restock",
diff --git a/src/backend/taler-merchant-httpd_private-post-products.c b/src/backend/taler-merchant-httpd_private-post-products.c
index 498e51c9..c4402841 100644
--- a/src/backend/taler-merchant-httpd_private-post-products.c
+++ b/src/backend/taler-merchant-httpd_private-post-products.c
@@ -61,8 +61,8 @@ products_equal (const struct TALER_MERCHANTDB_ProductDetails *p1,
(p1->total_lost == p2->total_lost) &&
(1 == json_equal (p1->image,
p2->image)) &&
- (1 == json_equal (p1->location,
- p2->location)) &&
+ (1 == json_equal (p1->address,
+ p2->address)) &&
(p1->next_restock.abs_value_us ==
p2->next_restock.abs_value_us) );
}
@@ -101,8 +101,8 @@ TMH_private_post_products (const struct TMH_RequestHandler *rh,
&pd.image),
GNUNET_JSON_spec_json ("taxes",
&pd.taxes),
- GNUNET_JSON_spec_json ("location",
- &pd.taxes),
+ GNUNET_JSON_spec_json ("address",
+ &pd.address),
GNUNET_JSON_spec_int64 ("total_stocked",
&total_stocked),
GNUNET_JSON_spec_absolute_time ("next_restock",
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c
index 70a98d5c..08f80930 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -666,8 +666,8 @@ postgres_purge_instance (void *cls,
* @return database result code
*/
static enum GNUNET_DB_QueryStatus
-postgres_patch_instance (void *cls,
- const struct TALER_MERCHANTDB_InstanceSettings *is)
+postgres_update_instance (void *cls,
+ const struct TALER_MERCHANTDB_InstanceSettings *is)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -715,6 +715,327 @@ postgres_inactivate_account (void *cls,
}
+/**
+ * Context used for postgres_lookup_products().
+ */
+struct LookupProductsContext
+{
+ /**
+ * Function to call with the results.
+ */
+ TALER_MERCHANTDB_ProductsCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Internal result.
+ */
+ enum GNUNET_DB_QueryStatus qs;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results about products.
+ *
+ * @param[in,out] cls of type `struct LookupProductsContext *`
+ * @param result the postgres result
+ * @param num_result the number of results in @a result
+ */
+static void
+lookup_products_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct LookupProductsContext *plc = cls;
+
+ for (unsigned int i = 0; i < num_results; i++)
+ {
+ char *product_id;
+ uint64_t in_stock;
+ char *unit;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("product_id",
+ &product_id),
+ GNUNET_PQ_result_spec_uint64 ("in_stock",
+ &in_stock),
+ GNUNET_PQ_result_spec_string ("unit",
+ &unit),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ plc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ return;
+ }
+ plc->cb (plc->cb_cls,
+ product_id,
+ (UINT64_MAX == in_stock) ? -1LL : (long long) in_stock,
+ unit);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+/**
+ * Lookup all of the products the given instance has configured.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup products for
+ * @param cb function to call on all products found
+ * @param cb_cls closure for @a cb
+ * @return database result code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_products (void *cls,
+ const char *instance_id,
+ TALER_MERCHANTDB_ProductsCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct LookupProductsContext plc = {
+ .cb = cb,
+ .cb_cls = cb_cls
+ };
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "lookup_products",
+ params,
+ &lookup_products_cb,
+ &plc);
+ if (0 != plc.qs)
+ return plc.qs;
+ return qs;
+}
+
+
+/**
+ * Lookup details about a particular product.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup products for
+ * @param product_id product to lookup
+ * @param[out] pd set to the product details on success, can be NULL
+ * (in that case we only want to check if the product exists)
+ * @return database result code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_lookup_product (void *cls,
+ const char *instance_id,
+ const char *product_id,
+ struct TALER_MERCHANTDB_ProductDetails *pd)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (product_id),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_string ("description",
+ &pd->description),
+ TALER_PQ_result_spec_json ("description_i18n",
+ &pd->description_i18n),
+ GNUNET_PQ_result_spec_string ("unit",
+ &pd->unit),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("price",
+ &pd->price),
+ TALER_PQ_result_spec_json ("taxes",
+ &pd->taxes),
+ GNUNET_PQ_result_spec_uint64 ("total_stocked",
+ &pd->total_stocked),
+ GNUNET_PQ_result_spec_uint64 ("total_sold",
+ &pd->total_sold),
+ GNUNET_PQ_result_spec_uint64 ("total_lost",
+ &pd->total_lost),
+ TALER_PQ_result_spec_json ("image",
+ &pd->image),
+ TALER_PQ_result_spec_json ("address",
+ &pd->address),
+ GNUNET_PQ_result_spec_absolute_time ("next_restock",
+ &pd->next_restock),
+ GNUNET_PQ_result_spec_end
+ };
+ struct GNUNET_PQ_ResultSpec rs_null[] = {
+ GNUNET_PQ_result_spec_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "lookup_product",
+ params,
+ (NULL == pd)
+ ? rs_null
+ : rs);
+}
+
+
+/**
+ * Delete information about a product. Note that the transaction must
+ * enforce that no stocks are currently locked.
+ *
+ * @param cls closure
+ * @param instance_id instance to delete product of
+ * @param product_id product to delete
+ * @return DB status code, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
+ * if locks prevent deletion OR product unknown
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_delete_product (void *cls,
+ const char *instance_id,
+ const char *product_id)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (product_id),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "delete_product",
+ params);
+}
+
+
+/**
+ * Insert details about a particular product.
+ *
+ * @param cls closure
+ * @param instance_id instance to insert product for
+ * @param product_id product identifier of product to insert
+ * @param pd the product details to insert
+ * @return database result code
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_insert_product (void *cls,
+ const char *instance_id,
+ const char *product_id,
+ const struct TALER_MERCHANTDB_ProductDetails *pd)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (product_id),
+ GNUNET_PQ_query_param_string (pd->description),
+ TALER_PQ_query_param_json (pd->description_i18n),
+ GNUNET_PQ_query_param_string (pd->unit),
+ TALER_PQ_query_param_json (pd->image),
+ TALER_PQ_query_param_json (pd->taxes),
+ TALER_PQ_query_param_amount (&pd->price),
+ GNUNET_PQ_query_param_uint64 (&pd->total_stocked),
+ GNUNET_PQ_query_param_uint64 (&pd->total_sold),
+ GNUNET_PQ_query_param_uint64 (&pd->total_lost),
+ TALER_PQ_query_param_json (pd->address),
+ GNUNET_PQ_query_param_absolute_time (&pd->next_restock),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "insert_product",
+ params);
+}
+
+
+/**
+ * Update details about a particular product. Note that the
+ * transaction must enforce that the sold/stocked/lost counters
+ * are not reduced (i.e. by expanding the WHERE clause on the existing
+ * values).
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup products for
+ * @param product_id product to lookup
+ * @param[out] pd set to the product details on success, can be NULL
+ * (in that case we only want to check if the product exists)
+ * @return database result code, #GNUNET_DB_SUCCESS_NO_RESULTS if the
+ * non-decreasing constraints are not met *or* if the product
+ * does not yet exist.
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_update_product (void *cls,
+ const char *instance_id,
+ const char *product_id,
+ struct TALER_MERCHANTDB_ProductDetails *pd)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (product_id),
+ GNUNET_PQ_query_param_string (pd->description),
+ TALER_PQ_query_param_json (pd->description_i18n),
+ GNUNET_PQ_query_param_string (pd->unit),
+ TALER_PQ_query_param_json (pd->image),
+ TALER_PQ_query_param_json (pd->taxes),
+ TALER_PQ_query_param_amount (&pd->price),
+ GNUNET_PQ_query_param_uint64 (&pd->total_stocked),
+ GNUNET_PQ_query_param_uint64 (&pd->total_sold),
+ GNUNET_PQ_query_param_uint64 (&pd->total_lost),
+ TALER_PQ_query_param_json (pd->address),
+ GNUNET_PQ_query_param_absolute_time (&pd->next_restock),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "update_product",
+ params);
+}
+
+
+/**
+ * Lock stocks of a particular product. Note that the transaction must
+ * enforce that the "stocked-sold-lost >= locked" constraint holds.
+ *
+ * @param cls closure
+ * @param instance_id instance to lookup products for
+ * @param product_id product to lookup
+ * @param uuid the UUID that holds the lock
+ * @param quantity how many units should be locked
+ * @param expiration_time when should the lock expire
+ * @return database result code, #GNUNET_DB_SUCCESS_NO_RESULTS if the
+ * product is unknown OR if there insufficient stocks remaining
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_lock_product (void *cls,
+ const char *instance_id,
+ const char *product_id,
+ const struct GNUNET_Uuid *uuid,
+ uint32_t quantity,
+ struct GNUNET_TIME_Absolute expiration_time)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (instance_id),
+ GNUNET_PQ_query_param_string (product_id),
+ GNUNET_PQ_query_param_auto_from_type (uuid),
+ GNUNET_PQ_query_param_uint32 (&quantity),
+ GNUNET_PQ_query_param_absolute_time (&expiration_time),
+ GNUNET_PQ_query_param_end
+ };
+
+ check_connection (pg);
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "lock_product",
+ params);
+}
+
+
/* ********************* OLD API ************************** */
/**
@@ -727,12 +1048,11 @@ postgres_inactivate_account (void *cls,
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-postgres_find_contract_terms_from_hash (void *cls,
- json_t **contract_terms,
- const struct
- GNUNET_HashCode *h_contract_terms,
- const struct
- TALER_MerchantPublicKeyP *merchant_pub)
+postgres_find_contract_terms_from_hash (
+ void *cls,
+ json_t **contract_terms,
+ const struct GNUNET_HashCode *h_contract_terms,
+ const struct TALER_MerchantPublicKeyP *merchant_pub)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
@@ -3677,7 +3997,7 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
"DELETE FROM merchant_instances"
" WHERE merchant_instances.merchant_id = $1",
1),
- /* for postgres_patch_instance() */
+ /* for postgres_update_instance() */
GNUNET_PQ_make_prepare ("update_instance",
"UPDATE merchant_instances SET"
" merchant_name=$2"
@@ -4199,8 +4519,14 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
plugin->insert_account = &postgres_insert_account;
plugin->delete_instance_private_key = &postgres_delete_instance_private_key;
plugin->purge_instance = &postgres_purge_instance;
- plugin->patch_instance = &postgres_patch_instance;
+ plugin->update_instance = &postgres_update_instance;
plugin->inactivate_account = &postgres_inactivate_account;
+ plugin->lookup_products = &postgres_lookup_products;
+ plugin->lookup_product = &postgres_lookup_product;
+ plugin->delete_product = &postgres_delete_product;
+ plugin->insert_product = &postgres_insert_product;
+ plugin->update_product = &postgres_update_product;
+ plugin->lock_product = &postgres_lock_product;
/* old API: */
plugin->store_deposit = &postgres_store_deposit;
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index 353997db..09bb1372 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -144,14 +144,12 @@ typedef void
* Typically called by `lookup_products`.
*
* @param cls a `json_t *` JSON array to build
- * @param key unused
* @param product_id ID of the product
* @param in_stock how many are currently in stock (possibly locked), -1 for infinite
* @param unit in which unit is the stock measured in
*/
typedef void
(*TALER_MERCHANTDB_ProductsCallback)(void *cls,
- const struct GNUNET_HashCode *key,
const char *product_id,
long long in_stock,
const char *unit);
@@ -214,7 +212,7 @@ struct TALER_MERCHANTDB_ProductDetails
/**
* Identifies where the product is in stock, possibly an empty map.
*/
- json_t *location;
+ json_t *address;
/**
* Identifies when the product will be restocked. 0 for unknown,
@@ -542,7 +540,8 @@ struct TALER_MERCHANTDB_Plugin
struct TALER_MERCHANTDB_ProductDetails *pd);
/**
- * Delete information about a product.
+ * Delete information about a product. Note that the transaction must
+ * enforce that no stocks are currently locked.
*
* @param cls closure
* @param instance_id instance to delete product of