Skip to content

Commit

Permalink
refs #3545 data provider raw SQL support
Browse files Browse the repository at this point in the history
  • Loading branch information
davidnich committed Jan 15, 2020
1 parent 6d8c3ef commit ce9fa61
Show file tree
Hide file tree
Showing 17 changed files with 303 additions and 119 deletions.
5 changes: 3 additions & 2 deletions bin/qdp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# @file qdp example program for the DataProvider module

/* Copyright 2019 Qore Technologies, s.r.o.
/* Copyright 2019 - 2020 Qore Technologies, s.r.o.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -158,7 +158,8 @@ class QdpCmd {
}

static getRecord(AbstractDataProvider provider) {
*hash<string, AbstractDataField> rec = provider.getRecordType();
*hash<auto> search_options = QdpCmd::getHash("search options");
*hash<string, AbstractDataField> rec = provider.getRecordType(search_options);
if (opts.verbose > 1) {
printf("%N\n", (map {$1.key: $1.value.getInfo()}, rec.pairIterator()));
} else {
Expand Down
3 changes: 2 additions & 1 deletion examples/test/qlib/SqlUtil/SqlUtilTestBase.qm
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,10 @@ public class SqlTestBase inherits QUnit::Test {

if (fname) {
# test update API
AbstractDatasource ds = table.getDatasource();
assertFalse(ds.currentThreadInTransaction());
string rstr = get_random_string();
assertTrue(dp.updateSingleRecord({fname: rstr}, {"id": 1}));
AbstractDatasource ds = table.getDatasource();
assertFalse(ds.currentThreadInTransaction());

hash<auto> row = dp.searchSingleRecord({"id": 1});
Expand Down
2 changes: 1 addition & 1 deletion qlib/CsvUtil/AbstractCsvIterator.qc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- mode: qore; indent-tabs-mode: nil -*-
# Qore AbstractCsvIterator class definition

/* AbstractCsvIterator.qc Copyright 2012 - 2019 Qore Technologies, s.r.o.
/* AbstractCsvIterator.qc Copyright 2012 - 2020 Qore Technologies, s.r.o.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
Expand Down
6 changes: 3 additions & 3 deletions qlib/CsvUtil/CsvHelper.qc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- mode: qore; indent-tabs-mode: nil -*-
# Qore CsvHelper class definition

/* CsvHelper.qm Copyright 2012 - 2018 Qore Technologies, s.r.o.
/* CsvHelper.qm Copyright 2012 - 2020 Qore Technologies, s.r.o.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -33,7 +33,7 @@ class CsvHelper {
const C_OPT1 = 0x1;
const C_OPT2 = 0x2;
#! supported type codes (hash for quick lookups)
const Types = (
const Types = {
"int": True,
"*int": True,
"float": True,
Expand All @@ -44,7 +44,7 @@ class CsvHelper {
"*string": True,
"date": True,
"*date": True,
);
};

#! supported field description attribute codes
const FieldAttrs = ("type", "format", "timezone", "code", "header");
Expand Down
4 changes: 2 additions & 2 deletions qlib/CsvUtil/CsvReadDataProvider.qc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- mode: qore; indent-tabs-mode: nil -*-
# Qore CsvReadDataProvider class definition

/* CsvReadDataProvider.qc Copyright 2012 - 2019 Qore Technologies, s.r.o.
/* CsvReadDataProvider.qc Copyright 2012 - 2020 Qore Technologies, s.r.o.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -116,7 +116,7 @@ public class CsvReadDataProvider inherits DataProvider::AbstractDataProvider {
}

#! Returns the description of the record type, if any
*hash<string, AbstractDataField> getRecordType() {
private *hash<string, AbstractDataField> getRecordTypeImpl(*hash<auto> search_options) {
if (!i.valid()) {
i.peek();
}
Expand Down
4 changes: 2 additions & 2 deletions qlib/CsvUtil/CsvWriteDataProvider.qc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- mode: qore; indent-tabs-mode: nil -*-
# Qore CsvWriteDataProvider class definition

/* CsvWriteDataProvider.qc Copyright 2012 - 2019 Qore Technologies, s.r.o.
/* CsvWriteDataProvider.qc Copyright 2012 - 2020 Qore Technologies, s.r.o.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -108,7 +108,7 @@ public class CsvWriteDataProvider inherits DataProvider::AbstractDataProvider {
}

#! Returns the description of the record type, if any
*hash<string, AbstractDataField> getRecordType() {
private *hash<string, AbstractDataField> getRecordTypeImpl(*hash<auto> search_options) {
return writer.getRecordType();
}

Expand Down
83 changes: 64 additions & 19 deletions qlib/DataProvider/AbstractDataProvider.qc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- mode: qore; indent-tabs-mode: nil -*-
#! Qore AbstractDataProvider class definition

/** AbstractDataProvider.qc Copyright 2019 Qore Technologies, s.r.o.
/** AbstractDataProvider.qc Copyright 2019 - 2020 Qore Technologies, s.r.o.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -151,6 +151,11 @@ public hashdecl DataProviderInfo {
*/
bool has_record = False;

#! Do we require search options to retrieve the record type?
/** @note this is a static attribute; it is the same for all data providers of the same type
*/
bool record_requires_search_options = False;

#! Constructor options supported by the data provider for the constructor variant taking a hash
/** @note this is a static attribute; it is the same for all data providers of the same type
*/
Expand Down Expand Up @@ -247,7 +252,8 @@ public class AbstractDataProvider {
*/
*hash<auto> searchFirstRecord(hash<auto> where_cond, *hash<auto> search_options) {
checkRead();
return searchFirstRecordImpl(processFieldValues(where_cond), validateSearchOptions(search_options));
search_options = validateSearchOptions(search_options);
return searchFirstRecordImpl(processFieldValues(where_cond, search_options), search_options);
}

#! Returns a single record matching the search options
Expand All @@ -259,7 +265,8 @@ public class AbstractDataProvider {
*/
*hash<auto> searchSingleRecord(hash<auto> where_cond, *hash<auto> search_options) {
checkRead();
return searchSingleRecordImpl(processFieldValues(where_cond), validateSearchOptions(search_options));
search_options = validateSearchOptions(search_options);
return searchSingleRecordImpl(processFieldValues(where_cond, search_options), search_options);
}

#! Returns an iterator iterating all records
Expand Down Expand Up @@ -302,7 +309,8 @@ public class AbstractDataProvider {
throw "INVALID-BLOCK-SIZE", sprintf("block_size %d is invalid; the block size mst be a positive number",
block_size);
}
return searchRecordsBulkImpl(block_size, processFieldValues(where_cond), validateSearchOptions(search_options));
search_options = validateSearchOptions(search_options);
return searchRecordsBulkImpl(block_size, processFieldValues(where_cond, search_options), search_options);
}

#! Returns an iterator for zero or more records matching the search options
Expand All @@ -313,7 +321,8 @@ public class AbstractDataProvider {
*/
AbstractDataProviderRecordIterator searchRecords(*hash<auto> where_cond, *hash<auto> search_options) {
checkRead();
return searchRecordsImpl(processFieldValues(where_cond), validateSearchOptions(search_options));
search_options = validateSearchOptions(search_options);
return searchRecordsImpl(processFieldValues(where_cond, search_options), search_options);
}

#! Returns an iterator for zero or more records matching the search options according to an API request
Expand Down Expand Up @@ -342,8 +351,9 @@ public class AbstractDataProvider {
*/
bool updateSingleRecord(hash<auto> set, hash<auto> where_cond, *hash<auto> search_options) {
checkUpdate();
return updateSingleRecordImpl(processFieldValues(set), processFieldValues(where_cond),
validateSearchOptions(search_options));
search_options = validateSearchOptions(search_options);
return updateSingleRecordImpl(processFieldValues(set, search_options),
processFieldValues(where_cond, search_options), search_options);
}

#! Updates zero or more records matching the search options
Expand All @@ -357,8 +367,9 @@ public class AbstractDataProvider {
*/
int updateRecords(hash<auto> set, *hash<auto> where_cond, *hash<auto> search_options) {
checkUpdate();
return updateRecordsImpl(processFieldValues(set), processFieldValues(where_cond),
validateSearchOptions(search_options));
search_options = validateSearchOptions(search_options);
return updateRecordsImpl(processFieldValues(set, search_options),
processFieldValues(where_cond, search_options), search_options);
}

#! Deletes zero or more records
Expand All @@ -372,7 +383,8 @@ public class AbstractDataProvider {
*/
int deleteRecords(*hash<auto> where_cond, *hash<auto> search_options) {
checkDelete();
return deleteRecordsImpl(processFieldValues(where_cond), validateSearchOptions(search_options));
search_options = validateSearchOptions(search_options);
return deleteRecordsImpl(processFieldValues(where_cond, search_options), search_options);
}

#! Makes a request and returns the response
Expand Down Expand Up @@ -673,16 +685,17 @@ public class AbstractDataProvider {

#! processes search or set values to convert types if necessary
/** @param h the hash of field values to process
@param search_options the search options after processing by validateSearchOptions()

@return processed field values, all non-hash values of \a h are processed with the field's type to ensure
that the values are valid for the comparison or set operation; hash values are assumed to be provider-
specific comparison or set operations and should be processed by the provider-specific method
*/
private *hash<auto> processFieldValues(*hash<auto> h) {
private *hash<auto> processFieldValues(*hash<auto> h, *hash<auto> search_options) {
if (!h) {
return;
}
*hash<string, AbstractDataField> rec = getRecordType();
*hash<string, AbstractDataField> rec = getRecordTypeImpl(search_options);
hash<auto> rv;
foreach hash<auto> i in (h.pairIterator()) {
if (!rec{i.key}) {
Expand Down Expand Up @@ -761,15 +774,24 @@ public class AbstractDataProvider {
}

#! Returns the description of the record type, if any
*hash<string, AbstractDataField> getRecordType() {
# this method intentionally left blank
/** @param search_options to be included and processed by validateSearchOptions() if
\a recordRequiresSearchOptions() is @ref True for this provider, otherwise any value provided in this argument
is ignored

@return the record type or @ref NOTHING if the datas provider does not support a record type
*/
*hash<string, AbstractDataField> getRecordType(*hash<auto> search_options) {
if (!hasRecord()) {
return;
}
return getRecordTypeImpl(recordRequiresSearchOptions() ? validateSearchOptions(search_options) : NOTHING);
}

#! Returns the description of the record type, if any
*hash<string, AbstractDataField> getSoftRecordType() {
*hash<string, AbstractDataField> getSoftRecordType(*hash<auto> search_options) {
return map {
$1.key: $1.value.getSoftType()
}, getRecordType().pairIterator();
}, getRecordType(search_options).pairIterator();
}

#! Returns options that can be used for searching
Expand Down Expand Up @@ -874,10 +896,33 @@ public class AbstractDataProvider {
return getStaticInfoImpl().supports_request;
}

#! Returns True if the data provider requires search options to retrieve the record type
/**
*/
bool recordRequiresSearchOptions() {
return getStaticInfoImpl().record_requires_search_options;
}

#! Returns @ref True if the data provider has a record type
/** @return @ref True if the data provider has a record type
*/
bool hasRecord() {
return getStaticInfoImpl().has_record;
}

#! Returns the description of the record type, if any
/** @param search_options to be included and processed by validateSearchOptions() if
\a recordRequiresSearchOptions() is @ref True for this provider, otherwise any value provided in this argument
is ignored
*/
private *hash<string, AbstractDataField> getRecordTypeImpl(*hash<auto> search_options) {
throwUnimplementedException();
}

#! Returns an iterator for zero or more records matching the search options
/** @param block_size the number of records in a read block; must be a positive number
@param where_cond the search criteria; will be processed by processFieldValues()
@param search_options the search options; will be processed by validateSearchOptions()
@param where_cond the search criteria; after processing by processFieldValues()
@param search_options the search options after processing by validateSearchOptions()

@throw INVALID-BLOCK-SIZE the block size must be a positive number
@throw INVALID-OPERATION the data provider does not support reading
Expand All @@ -898,7 +943,7 @@ public class AbstractDataProvider {

#! Returns an iterator for zero or more records matching the search options according to an API request
/** @param req the request to serialize and make according to the request type
@param where_cond the search criteria; will be processed by processFieldValues()
@param where_cond the search criteria; after processing by processFieldValues()
@param search_options the search options after processing by validateSearchOptions()

This will execute the request and perform a default search on any record(s) returned
Expand Down
Loading

0 comments on commit ce9fa61

Please sign in to comment.