TripPin μέρος 7 - Σύνθετο σχήμα με τύπους M
Σημείωμα
Αυτό το περιεχόμενο αναφέρεται επί του παρόντος σε περιεχόμενο από μια υλοποίηση παλαιού τύπου για δοκιμές μονάδων στο Visual Studio. Το περιεχόμενο θα ενημερωθεί στο εγγύς μέλλον, ώστε να καλύπτει το νέο πλαίσιο δοκιμής Του Power Query SDK.
Αυτή η εκμάθηση πολλαπλών τμημάτων καλύπτει τη δημιουργία μιας νέας επέκτασης προέλευσης δεδομένων για το Power Query. Το εκπαιδευτικό βοήθημα προορίζεται να γίνει διαδοχικά. Κάθε μάθημα βασίζεται στη σύνδεση που δημιουργήθηκε σε προηγούμενα μαθήματα, προσθέτοντας σταδιακά νέες δυνατότητες στη σύνδεσή σας.
Σε αυτό το μάθημα, θα κάνετε τα εξής:
- Επιβολή σχήματος πίνακα με χρήση τύπων M
- Ορισμός τύπων για ένθετες εγγραφές και λίστες
- Επανασχεδιολογικός κώδικας για επαναχρησιμοποίηση και δοκιμή μονάδας
Στο προηγούμενο μάθημα ορίσατε τα σχήματα πίνακα χρησιμοποιώντας ένα απλό σύστημα "Πίνακας σχημάτων". Αυτή η προσέγγιση πίνακα σχήματος λειτουργεί για πολλά API REST/Σύνδεση ors, όμως οι υπηρεσίες που επιστρέφουν πλήρη ή ένθετα σύνολα δεδομένων μπορεί να επωφεληθούν από την προσέγγιση σε αυτό το πρόγραμμα εκμάθησης, η οποία αξιοποιεί το σύστημα τύπου M.
Αυτό το μάθημα θα σας καθοδηγήσει στα παρακάτω βήματα:
- Προσθήκη δοκιμών μονάδας.
- Ορισμός προσαρμοσμένων τύπων M.
- Επιβολή σχήματος με χρήση τύπων.
- Επανασχεδιάζοντας κοινό κώδικα σε ξεχωριστά αρχεία.
Προσθήκη δοκιμών μονάδας
Προτού αρχίσετε να χρησιμοποιείτε τη λογική σύνθετου σχήματος, θα προσθέσετε ένα σύνολο δοκιμών μονάδας στη σύνδεσή σας, για να μειώσετε την πιθανότητα ακούσιας διακοπής κάτι. Η δοκιμή μονάδων λειτουργεί ως εξής:
- Αντιγράψτε τον κοινό κώδικα από το δείγμα UnitTest στο αρχείο σας
TripPin.query.pq
. - Προσθέστε μια δήλωση ενότητας στο επάνω μέρος του αρχείου σας
TripPin.query.pq
. - Δημιουργήστε μια κοινόχρηστη εγγραφή (ονομάζεται
TripPin.UnitTest
). - Καθορίστε ένα
Fact
για κάθε δοκιμή. - Καλέστε
Facts.Summarize()
την για να εκτελέσετε όλες τις δοκιμές. - Αναφέρετε την προηγούμενη κλήση ως κοινόχρηστη τιμή για να εξασφαλίσετε ότι αξιολογείται όταν το έργο εκτελείται στο Visual Studio.
section TripPinUnitTests;
shared TripPin.UnitTest =
[
// Put any common variables here if you only want them to be evaluated once
RootTable = TripPin.Contents(),
Airlines = RootTable{[Name="Airlines"]}[Data],
Airports = RootTable{[Name="Airports"]}[Data],
People = RootTable{[Name="People"]}[Data],
// Fact(<Name of the Test>, <Expected Value>, <Actual Value>)
// <Expected Value> and <Actual Value> can be a literal or let statement
facts =
{
Fact("Check that we have three entries in our nav table", 3, Table.RowCount(RootTable)),
Fact("We have Airline data?", true, not Table.IsEmpty(Airlines)),
Fact("We have People data?", true, not Table.IsEmpty(People)),
Fact("We have Airport data?", true, not Table.IsEmpty(Airports)),
Fact("Airlines only has 2 columns", 2, List.Count(Table.ColumnNames(Airlines))),
Fact("Airline table has the right fields",
{"AirlineCode","Name"},
Record.FieldNames(Type.RecordFields(Type.TableRow(Value.Type(Airlines))))
)
},
report = Facts.Summarize(facts)
][report];
Η επιλογή Εκτέλεση στο έργο θα αξιολογήσει όλα τα Στοιχεία και θα σας δώσει μια έξοδο αναφοράς που μοιάζει κάπως έτσι:
Χρησιμοποιώντας ορισμένες αρχές από την ανάπτυξη βάσει δοκιμών, θα προσθέσετε τώρα μια δοκιμή που αποτυγχάνει αυτήν τη στιγμή, αλλά σύντομα θα υλοποιηθεί και θα διορθωθεί (μέχρι το τέλος αυτής της εκμάθησης). Συγκεκριμένα, θα προσθέσετε μια δοκιμή που ελέγχει μία από τις ένθετες εγγραφές (Μηνύματα ηλεκτρονικού ταχυδρομείου) που επιστρέφετε στην οντότητα Άτομα.
Fact("Emails is properly typed", type text, Type.ListItem(Value.Type(People{0}[Emails])))
Εάν εκτελέσετε ξανά τον κώδικα, θα πρέπει τώρα να δείτε ότι έχετε μια δοκιμή αποτυχίας.
Τώρα χρειάζεται απλώς να υλοποιήσετε τις λειτουργίες για να λειτουργήσει αυτό.
Ορισμός προσαρμοσμένων τύπων M
Η προσέγγιση επιβολής σχήματος στο προηγούμενο μάθημα που χρησιμοποιήθηκε "πίνακες σχήματος" ορίζεται ως ζεύγη ονόματος/τύπου. Λειτουργεί καλά όταν εργάζεστε με μεταφρασμένα/σχεσιακά δεδομένα, αλλά δεν υποστηρίζει τη ρύθμιση τύπων σε ένθετες εγγραφές/πίνακες/λίστες ή σας επιτρέπει να χρησιμοποιήσετε ξανά ορισμούς τύπου σε πίνακες/οντότητες.
Στην περίπτωση TripPin, τα δεδομένα στις οντότητες Άτομα και Αεροδρόμια περιέχουν δομημένες στήλες και ακόμη και μοιράζονται έναν τύπο (Location
) για την αναπαράσταση των πληροφοριών διεύθυνσης. Αντί να ορίσετε ζεύγη Ονόματος/Τύπου σε έναν πίνακα σχήματος, θα ορίσετε κάθε μία από αυτές τις οντότητες χρησιμοποιώντας προσαρμοσμένες δηλώσεις τύπου M.
Ακολουθεί μια γρήγορη ανανέωση σχετικά με τους τύπους στη γλώσσα M από την προδιαγραφή γλώσσας:
Μια τιμή τύπου είναι μια τιμή που ταξινομεί άλλες τιμές. Μια τιμή που ταξινομείται από έναν τύπο λέγεται ότι συμμορφώνεται με αυτόν τον τύπο. Το σύστημα τύπου M αποτελείται από τα ακόλουθα είδη τύπων:
- Στοιχειώδεις τύποι, οι οποίοι ταξινομούν στοιχειώδεις τιμές (
binary
, ,date
,datetimezone
datetime
, ,duration
,list
,null
logical
,number
,record
text
, ,time
,type
) και περιλαμβάνουν επίσης έναν αριθμό αφηρημένων τύπων (function
,table
,any
και )none
- Τύποι εγγραφών, οι οποίοι ταξινομούν τις τιμές εγγραφών με βάση τα ονόματα πεδίων και τους τύπους τιμών
- Τύποι λίστας, οι οποίοι ταξινομούν τις λίστες χρησιμοποιώντας έναν τύπο βάσης ενός στοιχείου
- Τύποι συναρτήσεων, οι οποίοι ταξινομούν τις τιμές συναρτήσεων με βάση τους τύπους των παραμέτρων τους και τις τιμές επιστροφής
- Τύποι πινάκων, οι οποίοι ταξινομούν τις τιμές πίνακα με βάση τα ονόματα στηλών, τους τύπους στηλών και τα κλειδιά
- Τύποι που επιδέχονται τιμές null, οι οποίοι ταξινομούν την τιμή null επιπλέον όλων των τιμών που ταξινομούνται με έναν βασικό τύπο
- Τύποι τύπων, οι οποίοι ταξινομούν τις τιμές που είναι τύποι
Χρησιμοποιώντας την μη επεξεργασμένη έξοδο JSON που λαμβάνετε (ή/και αναζητώντας τους ορισμούς στο $metadata της υπηρεσίας), μπορείτε να ορίσετε τους ακόλουθους τύπους εγγραφών για αναπαράσταση των σύνθετων τύπων OData:
LocationType = type [
Address = text,
City = CityType,
Loc = LocType
];
CityType = type [
CountryRegion = text,
Name = text,
Region = text
];
LocType = type [
#"type" = text,
coordinates = {number},
crs = CrsType
];
CrsType = type [
#"type" = text,
properties = record
];
Παρατηρήστε τον τρόπο με τον οποίο οι LocationType
αναφορές στο CityType
και LocType
το αντιπροσωπεύουν τις δομημένες στήλες του.
Για τις οντότητες ανώτατου επιπέδου (που θέλετε να αναπαρίστανται ως πίνακες), ορίζετε τύπους πινάκων:
AirlinesType = type table [
AirlineCode = text,
Name = text
];
AirportsType = type table [
Name = text,
IataCode = text,
Location = LocationType
];
PeopleType = type table [
UserName = text,
FirstName = text,
LastName = text,
Emails = {text},
AddressInfo = {nullable LocationType},
Gender = nullable text,
Concurrency = Int64.Type
];
Στη συνέχεια, ενημερώνετε τη μεταβλητή σας SchemaTable
(την οποία χρησιμοποιείτε ως "πίνακα αναζήτησης" για την οντότητα για να πληκτρολογήσετε αντιστοιχίσεις) για να χρησιμοποιήσετε αυτούς τους νέους ορισμούς τύπου:
SchemaTable = #table({"Entity", "Type"}, {
{"Airlines", AirlinesType },
{"Airports", AirportsType },
{"People", PeopleType}
});
Επιβολή σχήματος με χρήση τύπων
Θα βασιστείτε σε μια κοινή συνάρτηση (Table.ChangeType
) για να επιβάλετε ένα σχήμα στα δεδομένα σας, όπως χρησιμοποιήσατε SchemaTransformTable
στο προηγούμενο μάθημα.
Σε αντίθεση με SchemaTransformTable
το , Table.ChangeType
λαμβάνει έναν πραγματικό τύπο πίνακα M ως όρισμα και θα εφαρμόσει το σχήμα αναδρομικά για όλους τους ένθετες τύπους. Η υπογραφή του μοιάζει κάπως έτσι:
Table.ChangeType = (table, tableType as type) as nullable table => ...
Μπορείτε να βρείτε την πλήρη λίστα κώδικα για τη Table.ChangeType
συνάρτηση στο αρχείο Table.ChangeType.pqm .
Σημείωμα
Για ευελιξία, η συνάρτηση μπορεί να χρησιμοποιηθεί σε πίνακες, καθώς και σε λίστες εγγραφών (που είναι ο τρόπος με τον οποίο οι πίνακες θα απεικονίζονται σε ένα έγγραφο JSON).
Στη συνέχεια, πρέπει να ενημερώσετε τον κωδικό σύνδεσης για να αλλάξετε την schema
παράμετρο από ένα table
σε ένα type
και να Table.ChangeType
προσθέσετε μια κλήση στο στο GetEntity
.
GetEntity = (url as text, entity as text) as table =>
let
fullUrl = Uri.Combine(url, entity),
schema = GetSchemaForEntity(entity),
result = TripPin.Feed(fullUrl, schema),
appliedSchema = Table.ChangeType(result, schema)
in
appliedSchema;
GetPage
Το ενημερώνεται ώστε να χρησιμοποιεί τη λίστα πεδίων από το σχήμα (για να γνωρίζει τα ονόματα των στοιχείων που θα αναπτυχθούν όταν λάβετε τα αποτελέσματα), αλλά αφήνει την πραγματική επιβολή σχήματος στο GetEntity
.
GetPage = (url as text, optional schema as type) as table =>
let
response = Web.Contents(url, [ Headers = DefaultRequestHeaders ]),
body = Json.Document(response),
nextLink = GetNextLink(body),
// If we have no schema, use Table.FromRecords() instead
// (and hope that our results all have the same fields).
// If we have a schema, expand the record using its field names
data =
if (schema <> null) then
Table.FromRecords(body[value])
else
let
// convert the list of records into a table (single column of records)
asTable = Table.FromList(body[value], Splitter.SplitByNothing(), {"Column1"}),
fields = Record.FieldNames(Type.RecordFields(Type.TableRow(schema))),
expanded = Table.ExpandRecordColumn(asTable, fields)
in
expanded
in
data meta [NextLink = nextLink];
Επιβεβαίωση ότι ορίζονται ένθετοι τύποι
Ο ορισμός για τον δικό σας PeopleType
ορισμό ορίζει τώρα το Emails
πεδίο σε μια λίστα κειμένου ({text}
).
Εάν εφαρμόζετε σωστά τους τύπους, η κλήση στο Type.ListItem στη δοκιμή μονάδας θα πρέπει τώρα να επιστρέφει type text
αντί type any
για .
Η εκτέλεση των δοκιμών μονάδας δείχνει ξανά ότι μεταβιβάζονται όλες.
Επανασχεδιάζοντας κοινό κώδικα σε ξεχωριστά αρχεία
Σημείωμα
Ο μηχανισμός M θα έχει βελτιωμένη υποστήριξη για την αναφορά εξωτερικών μονάδων/κοινού κώδικα στο μέλλον, αλλά αυτή η προσέγγιση θα σας μεταφέρει μέχρι τότε.
Σε αυτό το σημείο, η επέκτασή σας έχει σχεδόν τόσο "κοινό" κώδικα όσο και κώδικα σύνδεσης TripPin. Στο μέλλον, αυτές οι κοινές συναρτήσεις θα αποτελούν μέρος της ενσωματωμένης τυπικής βιβλιοθήκης συναρτήσεων ή θα μπορείτε να τις αναφέρετε από μια άλλη επέκταση. Προς το παρόν, επανασχεδιάζετε τον κώδικά σας ως εξής:
- Μετακινήστε τις συναρτήσεις με δυνατότητα επανάληψης χρήσης σε ξεχωριστά αρχεία (.pqm).
- Ορίστε την ιδιότητα Ενέργεια δόμησης στο αρχείο σε Μεταγλώττιση για να βεβαιωθείτε ότι περιλαμβάνεται στο αρχείο επέκτασης κατά τη δόμηση .
- Καθορίστε μια συνάρτηση για φόρτωση του κώδικα χρησιμοποιώντας τη συνάρτηση Expression.Evaluate.
- Φορτώστε καθεμία από τις συνήθεις συναρτήσεις που θέλετε να χρησιμοποιήσετε.
Ο κώδικας για να το κάνετε αυτό περιλαμβάνεται στο παρακάτω τμήμα κώδικα:
Extension.LoadFunction = (fileName as text) =>
let
binary = Extension.Contents(fileName),
asText = Text.FromBinary(binary)
in
try
Expression.Evaluate(asText, #shared)
catch (e) =>
error [
Reason = "Extension.LoadFunction Failure",
Message.Format = "Loading '#{0}' failed - '#{1}': '#{2}'",
Message.Parameters = {fileName, e[Reason], e[Message]},
Detail = [File = fileName, Error = e]
];
Table.ChangeType = Extension.LoadFunction("Table.ChangeType.pqm");
Table.GenerateByPage = Extension.LoadFunction("Table.GenerateByPage.pqm");
Table.ToNavigationTable = Extension.LoadFunction("Table.ToNavigationTable.pqm");
Συμπέρασμα
Αυτή η εκμάθηση έκανε έναν αριθμό βελτιώσεων στον τρόπο με τον οποίο επιβάλλετε ένα σχήμα στα δεδομένα που λαμβάνετε από ένα REST API. Προς το παρόν, η σύνδεση δημιουργεί με κόπο τις πληροφορίες σχήματος, οι οποίες έχουν όφελος επιδόσεων κατά τον χρόνο εκτέλεσης, αλλά δεν είναι δυνατή η προσαρμογή στις αλλαγές στις υπερωρίες μετα-δεδομένων της υπηρεσίας. Τα μελλοντικά προγράμματα εκμάθησης θα μετακινηθούν σε μια καθαρά δυναμική προσέγγιση που θα συνάγει το σχήμα από το $metadata έγγραφο της υπηρεσίας.
Εκτός από τις αλλαγές σχήματος, αυτό το εκπαιδευτικό βοήθημα πρόσθεσε τις Δοκιμές μονάδων για τον κώδικά σας και επανασχεδιάστηκε οι κοινές βοηθητικές συναρτήσεις σε ξεχωριστά αρχεία για να βελτιώσει τη συνολική αναγνωσιμότητα.